feat(frontend): expose owned session scopes

This commit is contained in:
User
2026-07-16 18:46:18 +02:00
parent b454fb478b
commit 58e0884df1
8 changed files with 270 additions and 20 deletions
+27 -3
View File
@@ -1,6 +1,6 @@
import { http, HttpResponse } from "msw";
import { server } from "../test/msw";
import { createSession, listSessions, prewarmRuntime, resumeSession } from "./sessions";
import { createSession, getMe, listSessions, prewarmRuntime, resumeSession } from "./sessions";
import {
renameSession, setSessionGroup, archiveSession, unarchiveSession,
deleteSession, getSessionDocuments,
@@ -30,10 +30,34 @@ test.each([202, 204])("prewarmRuntime accepts a body-less %s response", async (s
expect(called).toBe(true);
});
test("listSessions GETs the array", async () => {
server.use(http.get("http://localhost:8787/sessions", () => HttpResponse.json([{ id: "s1", status: "open", question: "q", summary: null, created_at: "t", updated_at: null, author: null }])));
test("listSessions defaults to the current user's scope", async () => {
let scope: string | null = null;
server.use(http.get("http://localhost:8787/sessions", ({ request }) => {
scope = new URL(request.url).searchParams.get("scope");
return HttpResponse.json([{ id: "s1", status: "open", question: "q", summary: null, created_at: "t", updated_at: null, author: null }]);
}));
const rows = await listSessions();
expect(rows[0].id).toBe("s1");
expect(scope).toBe("mine");
});
test("listSessions requests the selected administrator scope", async () => {
let scope: string | null = null;
server.use(http.get("http://localhost:8787/sessions", ({ request }) => {
scope = new URL(request.url).searchParams.get("scope");
return HttpResponse.json([]);
}));
await listSessions("all");
expect(scope).toBe("all");
});
test("getMe fetches the typed authenticated principal", async () => {
server.use(http.get("http://localhost:8787/me", () =>
HttpResponse.json({ issuer: "portal", subject: "42", displayName: "Alice", isAdmin: true }),
));
await expect(getMe()).resolves.toEqual({
issuer: "portal", subject: "42", displayName: "Alice", isAdmin: true,
});
});
test("resumeSession returns the typed runtime disposition", async () => {
+7 -2
View File
@@ -1,5 +1,7 @@
import { apiFetch } from "./client";
import type { ResumeSessionResult, SessionSummary, SessionDocument, UiResponse } from "./types";
import type {
Principal, ResumeSessionResult, SessionScope, SessionSummary, SessionDocument, UiResponse,
} from "./types";
export const createSession = (i: { question: string; name?: string }) =>
apiFetch<{ id: string }>("/sessions", { method: "POST", body: JSON.stringify(i) });
@@ -8,7 +10,10 @@ export const createSession = (i: { question: string; name?: string }) =>
export const prewarmRuntime = () =>
apiFetch<void>("/runtime/prewarm", { method: "POST" });
export const listSessions = () => apiFetch<SessionSummary[]>("/sessions");
export const getMe = () => apiFetch<Principal>("/me");
export const listSessions = (scope: SessionScope = "mine") =>
apiFetch<SessionSummary[]>(`/sessions?scope=${scope}`);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const getSession = (id: string) => apiFetch<any>(`/sessions/${id}`);
+9
View File
@@ -104,6 +104,15 @@ export interface SessionSummary {
archived: boolean;
}
export type SessionScope = "mine" | "all";
export interface Principal {
issuer: string;
subject: string;
displayName?: string;
isAdmin: boolean;
}
export interface ResumeSessionResult {
id: string;
alreadyActive: boolean;