feat(auth): add remembered local login to the frontend
This commit is contained in:
@@ -3,7 +3,7 @@ import { useEffect, useRef, useState } from "react";
|
||||
import { CornerDownLeft } from "lucide-react";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { postSteer, createSession } from "../api/sessions";
|
||||
import { ApiError } from "../api/client";
|
||||
import { ApiError, apiErrorMessage } from "../api/client";
|
||||
import { getSettings } from "../api/settings";
|
||||
import { getWorkspace, listWorkspaces } from "../api/workspaces";
|
||||
import { listModels } from "../api/models";
|
||||
@@ -11,6 +11,7 @@ import { useSessionStore } from "../store/sessionStore";
|
||||
import {
|
||||
WorkspaceSelectionError, workspacePolicyGate, workspacePreferences, type WorkspacePreference,
|
||||
} from "../workspaces/drafts";
|
||||
import { captureAuthOperation, isAuthOperationCurrent } from "../auth/authOperation";
|
||||
|
||||
const THINKING_LEVELS = ["low", "medium", "high"] as const;
|
||||
|
||||
@@ -48,6 +49,8 @@ export function SteerInput({
|
||||
const setLastUserEntry = useSessionStore((s) => s.setLastUserEntry);
|
||||
const setPhase = useSessionStore((s) => s.setPhase);
|
||||
const taRef = useRef<HTMLTextAreaElement | null>(null);
|
||||
const operationEpochRef = useRef(0);
|
||||
useEffect(() => () => { operationEpochRef.current += 1; }, []);
|
||||
|
||||
// Merge our own ref (for autosizing) with the forwarded one (parent focus).
|
||||
function attachRef(el: HTMLTextAreaElement | null) {
|
||||
@@ -68,14 +71,19 @@ export function SteerInput({
|
||||
async function submit() {
|
||||
const trimmed = text.trim();
|
||||
if (!trimmed || busy) return;
|
||||
const operation = captureAuthOperation({ sessionId, disposalEpoch: operationEpochRef.current });
|
||||
if (!operation) return;
|
||||
setBusy(true);
|
||||
if (sessionId) {
|
||||
try {
|
||||
await postSteer(sessionId, trimmed);
|
||||
if (!isAuthOperationCurrent(operation, { sessionId, disposalEpoch: operationEpochRef.current })) return;
|
||||
setLastUserEntry({ kind: "input", text: trimmed });
|
||||
setText("");
|
||||
} finally {
|
||||
setBusy(false);
|
||||
if (isAuthOperationCurrent(operation, { sessionId, disposalEpoch: operationEpochRef.current })) {
|
||||
setBusy(false);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -86,22 +94,29 @@ export function SteerInput({
|
||||
setLastUserEntry({ kind: "input", text: trimmed });
|
||||
onSessionCreating?.(trimmed);
|
||||
try {
|
||||
const { id } = await createSession({ question: trimmed });
|
||||
const { id } = await createSession({ question: trimmed }, {
|
||||
operation,
|
||||
isCurrent: () => isAuthOperationCurrent(operation, {
|
||||
sessionId: null,
|
||||
disposalEpoch: operationEpochRef.current,
|
||||
}),
|
||||
});
|
||||
if (!isAuthOperationCurrent(operation, { sessionId: null, disposalEpoch: operationEpochRef.current })) return;
|
||||
onSessionCreated?.(id);
|
||||
setText("");
|
||||
} catch (error) {
|
||||
if (!isAuthOperationCurrent(operation, { sessionId: null, disposalEpoch: operationEpochRef.current })) return;
|
||||
// Keep the question in the composer so retrying does not require retyping.
|
||||
// A DWH-unreachable precheck (local dev, VPN down) carries a specific code;
|
||||
// surface its message as the alert instead of the generic retry hint.
|
||||
const payload = error instanceof ApiError
|
||||
? (error.payload as { code?: string; error?: string } | undefined)
|
||||
: undefined;
|
||||
const alert = payload?.code === "dwh_unreachable"
|
||||
? payload.error
|
||||
// ApiError messages are derived from the local status/code allowlist;
|
||||
// never surface response-body text from the server.
|
||||
const alert = error instanceof ApiError && error.code === "dwh_unreachable"
|
||||
? apiErrorMessage(error)
|
||||
: error instanceof WorkspaceSelectionError ? error.message : undefined;
|
||||
onSessionCreateFailed?.(alert);
|
||||
} finally {
|
||||
setBusy(false);
|
||||
if (isAuthOperationCurrent(operation, { sessionId: null, disposalEpoch: operationEpochRef.current })) {
|
||||
setBusy(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user