feat: integrate pixel teacher presence and resilient classroom preview
This commit is contained in:
9
src/lib/classroom-layout.ts
Normal file
9
src/lib/classroom-layout.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export const CLASSROOM_SIDEBAR_DEFAULT_WIDTH = 171;
|
||||
export const CLASSROOM_SIDEBAR_MIN_WIDTH = 128;
|
||||
export const CLASSROOM_SIDEBAR_MAX_WIDTH = 256;
|
||||
|
||||
export function normalizeClassroomSidebarWidth(width: unknown): number {
|
||||
return typeof width === 'number' && Number.isFinite(width)
|
||||
? Math.max(CLASSROOM_SIDEBAR_MIN_WIDTH, Math.min(CLASSROOM_SIDEBAR_MAX_WIDTH, Math.round(width)))
|
||||
: CLASSROOM_SIDEBAR_DEFAULT_WIDTH;
|
||||
}
|
||||
23
src/lib/coding-login-recovery.ts
Normal file
23
src/lib/coding-login-recovery.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import type { AuthUser } from '@/stores/auth';
|
||||
|
||||
export interface CodingLoginRecovery {
|
||||
id: string;
|
||||
account: string;
|
||||
projectId: string;
|
||||
conversationId: string | null;
|
||||
work: boolean;
|
||||
}
|
||||
|
||||
export function codingRecoveryAccount(user: AuthUser | null): string {
|
||||
return user ? JSON.stringify([user.tenantId, user.userId, user.username]) : '';
|
||||
}
|
||||
|
||||
export function readCodingLoginRecovery(value: unknown): CodingLoginRecovery | undefined {
|
||||
if (!value || typeof value !== 'object') return;
|
||||
const item = value as Partial<CodingLoginRecovery>;
|
||||
if (typeof item.id !== 'string' || typeof item.account !== 'string' || !item.account
|
||||
|| typeof item.projectId !== 'string' || !item.projectId
|
||||
|| !(item.conversationId === null || typeof item.conversationId === 'string')
|
||||
|| typeof item.work !== 'boolean') return;
|
||||
return item as CodingLoginRecovery;
|
||||
}
|
||||
@@ -2,6 +2,8 @@ import { hostApiFetch, createHostEventSource, ensureHostApiToken } from './host-
|
||||
import type {
|
||||
ConsultationRole,
|
||||
TeacherAvailability,
|
||||
TeacherCheckInInput,
|
||||
TeacherCheckInResult,
|
||||
TeacherDefinition,
|
||||
TeacherSend,
|
||||
TeacherTopic,
|
||||
@@ -14,6 +16,11 @@ export function teacherTopicsPath(projectId: string, sourceId: string, role?: Co
|
||||
: `/api/coding/projects/${encodeURIComponent(projectId)}/conversations/${encodeURIComponent(sourceId)}/teacher-topics`;
|
||||
}
|
||||
export const teacherApi = {
|
||||
checkIn: (projectId: string, input: TeacherCheckInInput) =>
|
||||
hostApiFetch<TeacherCheckInResult>(`/api/coding/projects/${encodeURIComponent(projectId)}/teacher-check-in`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(input),
|
||||
}),
|
||||
config: (role: ConsultationRole = 'teacher') =>
|
||||
hostApiFetch<TeacherAvailability & { definition: TeacherDefinition | null }>(
|
||||
`/api/coding/${role}/config`
|
||||
@@ -28,8 +35,8 @@ export const teacherApi = {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ draftRevision, sampleContext }),
|
||||
}),
|
||||
read: (base: string, id: string) =>
|
||||
hostApiFetch<TeacherTopic>(base + '/' + encodeURIComponent(id)),
|
||||
read: (base: string, id: string, select = true) =>
|
||||
hostApiFetch<TeacherTopic>(base + '/' + encodeURIComponent(id) + (select ? '' : '?select=false')),
|
||||
send: (base: string, id: string, input: TeacherSend) =>
|
||||
hostApiFetch<TeacherTopic>(base + '/' + encodeURIComponent(id) + '/messages', {
|
||||
method: 'POST',
|
||||
|
||||
9
src/lib/coding-work-preview.ts
Normal file
9
src/lib/coding-work-preview.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { hostApiFetch } from './host-api';
|
||||
import type { WorkPreviewResult } from '../../shared/coding-work-preview';
|
||||
|
||||
export function ensureWorkPreview(projectId: string, requestId: string, conversationId?: string | null): Promise<WorkPreviewResult> {
|
||||
return hostApiFetch('/api/agent-browser/ensure-work', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ project_id: projectId, request_id: requestId, conversation_id: conversationId }),
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user