feat: integrate pixel teacher presence and resilient classroom preview

This commit is contained in:
鲨鱼辣椒 committed 2026-09-23 18:23:53 +08:00
1 parent 12d800ec51
commit 7951cca700
60 files changed
+3313 -180

No files matched your search

+17 -1
View File
@@ -5,6 +5,7 @@ import { Login } from '@/pages/Login';
import { dispatchPluginWorkspaceCommand } from '@/pages/Plugins/plugin-workspace-controller';
import { useAuthStore } from '@/stores/auth';
import { useProviderStore } from '@/stores/providers';
import { codingRecoveryAccount } from '@/lib/coding-login-recovery';
const hostApiFetchMock = vi.hoisted(() => vi.fn());
@@ -39,7 +40,7 @@ function resetAuthStore() {
function LocationProbe() {
const location = useLocation();
return <output data-testid="login-destination">{location.pathname}{location.search}</output>;
return <output data-testid="login-destination" data-recovery={JSON.stringify(location.state?.codingRecovery ?? null)}>{location.pathname}{location.search}</output>;
}
function PluginSignInAction() {
@@ -244,6 +245,21 @@ describe('Login page', () => {
expect(importUserModelConfig).toHaveBeenCalledWith('password-access-token');
});
it.each([true, false])('requires fresh login and only resumes the same account (same=%s)', async (same) => {
const user = { username: 'alice', userId: 'a1', tenantId: 't1', deptId: null, authorities: [] };
useAuthStore.setState({ user, accessToken: 'stale-token', expiresAt: Date.now() + 3600_000, lastActiveAt: Date.now() });
const recovery = { id: 'recovery-1', account: codingRecoveryAccount(user), projectId: 'p1', conversationId: 'c1', work: true };
loginWithPassword.mockImplementation(async () => useAuthStore.setState({ accessToken: 'fresh-token', user: same ? user : { ...user, userId: 'a2' } }));
renderLogin([{ pathname: '/login', state: { from: '/project-config/plugins', reauthenticate: true, codingRecovery: recovery } }]);
expect(screen.queryByTestId('login-destination')).not.toBeInTheDocument();
fireEvent.change(screen.getByLabelText('用户名'), { target: { value: 'alice' } });
fireEvent.change(screen.getByLabelText('密码'), { target: { value: 'password' } });
fireEvent.click(screen.getByRole('checkbox', { name: /我已阅读并同意/ }));
fireEvent.click(screen.getByRole('button', { name: '登录' }));
const destination = await screen.findByTestId('login-destination');
expect(JSON.parse(destination.getAttribute('data-recovery')!)).toEqual(same ? recovery : null);
});
it('returns a signed-out plugin action to the exact canonical workspace query after login', async () => {
const canonicalPath = '/project-config/plugins?scope=all&source=official&state=available&q=notes&plugin=official%3Amakelore.notes';
loginWithPassword.mockImplementation(async () => {