feat: rebuild Process Studio into multi-phase Process Creation Wizard\n\n- Replace toy Studio.tsx with proper Wizard.tsx canvas\n- Build 6-step flow: Intake -> Analyze -> Generate -> Validate -> Draft saved -> Publish\n- Implement incremental EA2 writes via wizardApi.ts (flow, batch apply)\n- Use localStorage for draft recovery across reloads\n- Apply industrial-blueprint UI styling matching core doctrine\n- Add Vitest tests for Wizard components and API wrappers
This commit is contained in:
+40
-1
@@ -174,6 +174,13 @@ async function authedRequest<T>(
|
||||
export const api = {
|
||||
config: DEFAULT_CONFIG,
|
||||
|
||||
/** Set the bearer token explicitly (e.g. from SSO or login form) */
|
||||
setBearer(token: string) {
|
||||
sessionStorage.setItem(TOKEN_KEY, token);
|
||||
// Also set a non-httpOnly cookie for server-side middleware
|
||||
document.cookie = `access_token=${token}; path=/; max-age=86400; SameSite=Lax`;
|
||||
},
|
||||
|
||||
/** Subscribe to all API calls. Returns unsubscribe. */
|
||||
onCall(fn: ApiCallObserver): () => void {
|
||||
observers.add(fn);
|
||||
@@ -184,6 +191,38 @@ export const api = {
|
||||
return authedRequest<AuthMe>(this.config, "GET", "/api/v1/auth/me", undefined, signal);
|
||||
},
|
||||
|
||||
async signIn(email: string, password?: string, signal?: AbortSignal): Promise<{ access_token: string; refresh_token?: string }> {
|
||||
const payload = password ? { email, password } : { email };
|
||||
const path = password ? "/api/v1/auth/login" : "/api/v1/auth/dev-login";
|
||||
const init: RequestInit = {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json", "Accept": "application/json" },
|
||||
body: JSON.stringify(payload),
|
||||
signal,
|
||||
};
|
||||
const r = await instrumentedFetch("POST", `${this.config.baseUrl}${path}`, init, payload);
|
||||
if (!r.ok) {
|
||||
const text = await r.text().catch(() => "");
|
||||
throw new Error(`Login failed: ${r.status} ${text.slice(0, 100)}`);
|
||||
}
|
||||
const data = await r.json() as { access_token: string; refresh_token?: string };
|
||||
this.setBearer(data.access_token);
|
||||
return data;
|
||||
},
|
||||
|
||||
async devLoginConfig(signal?: AbortSignal): Promise<{ enabled: boolean }> {
|
||||
try {
|
||||
const init: RequestInit = { method: "GET", headers: { "Accept": "application/json" }, signal };
|
||||
const r = await instrumentedFetch("GET", `${this.config.baseUrl}/internal/dev-login-config`, init);
|
||||
if (r.ok) {
|
||||
return await r.json() as { enabled: boolean };
|
||||
}
|
||||
} catch {
|
||||
// swallow
|
||||
}
|
||||
return { enabled: false };
|
||||
},
|
||||
|
||||
async workItems(signal?: AbortSignal): Promise<WorkItem[]> {
|
||||
const body = await authedRequest<{ items?: WorkItem[] }>(this.config, "GET", "/api/ea2/work-items?view=all", undefined, signal);
|
||||
return body.items ?? [];
|
||||
@@ -256,7 +295,7 @@ export const api = {
|
||||
{
|
||||
kind: "definition",
|
||||
status: "published",
|
||||
source_context: "mc-demo-studio",
|
||||
source_context: "mission-control-studio",
|
||||
version: 1,
|
||||
...payload,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user