fix: stabilize v03 live web entry
This commit is contained in:
@@ -3,6 +3,7 @@ import test from "node:test";
|
||||
|
||||
import type { ApiResult, HwpodNodeOpsResponse, HwpodSpecsResponse, LiveProbePayload, LiveSurface } from "../src/types/index.ts";
|
||||
import { summarizeBuilds, summarizeHwpodNodeOps, summarizeProbeRows } from "../src/stores/workbench-live.ts";
|
||||
import { liveCall } from "../src/stores/workbench.ts";
|
||||
|
||||
test("R3 probe summary exposes React WorkbenchProbe rows", () => {
|
||||
const summary = summarizeProbeRows(liveSurface());
|
||||
@@ -33,6 +34,19 @@ test("R3 HWPOD summary combines specs availability, node-ops and blocker stream"
|
||||
assert.ok(summary.streamLines.some((line) => line.includes("op_01_workspace_ls workspace.ls hwpod_node_unavailable")));
|
||||
});
|
||||
|
||||
test("R3 live refresh keeps partial evidence when one endpoint throws", async () => {
|
||||
const failed = await liveCall("live builds", async () => {
|
||||
throw new Error("network edge reset");
|
||||
});
|
||||
assert.equal(failed.ok, false);
|
||||
assert.equal(failed.status, 0);
|
||||
assert.match(failed.error ?? "", /live builds: network edge reset/);
|
||||
|
||||
const passed = await liveCall("health/live", async () => ok<LiveProbePayload>({ status: "ok", revision: "155530d8d9355887a23a08e341291994cc312f54" }));
|
||||
assert.equal(passed.ok, true);
|
||||
assert.equal(passed.data?.revision, "155530d8d9355887a23a08e341291994cc312f54");
|
||||
});
|
||||
|
||||
function liveSurface(): LiveSurface {
|
||||
const liveProbe = ok<LiveProbePayload>({ serviceId: "hwlab-cloud-api", environment: "v03", status: "ok", ready: true, revision: "c0cbdbb38de77f1ecc9d1222438a13294d81d4dd", observedAt: "2026-06-13T17:59:15.000Z" });
|
||||
return {
|
||||
|
||||
@@ -61,6 +61,7 @@ export const useAuthStore = defineStore("auth", () => {
|
||||
session.value = sessionFromPayload(response.data);
|
||||
authState.value = "authenticated";
|
||||
checked.value = true;
|
||||
document.body.dataset.authState = "authenticated";
|
||||
}
|
||||
|
||||
async function logout(): Promise<void> {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { computed, ref } from "vue";
|
||||
import { defineStore } from "pinia";
|
||||
import { api } from "@/api";
|
||||
import { mergeRunnerTrace, snapshotToRunnerTrace, subscribeToTrace, type TraceSnapshot } from "@/composables/useTraceSubscription";
|
||||
import type { AgentChatResponse, AgentChatResultResponse, ChatMessage, ConversationRecord, LiveSurface, ProviderProfile, WorkspaceRecord } from "@/types";
|
||||
import type { AgentChatResponse, AgentChatResultResponse, ApiResult, ChatMessage, ConversationRecord, LiveSurface, ProviderProfile, WorkspaceRecord } from "@/types";
|
||||
import { DEFAULT_WORKBENCH_PROJECT_ID, firstNonEmptyString, nextProtocolId, rememberWorkbenchProjectId, resolveInitialWorkbenchProjectId, workspaceProjectId } from "@/utils";
|
||||
import { RECENT_DRAFTS_STORAGE_KEY, activeTraceIdFromWorkspace, defaultProviderProfileOptions, normalizeRecentDrafts, providerProfileOptionsFromPayload, recordRecentDraft, resolveComposerState, sortSessionTabs, workspaceWithClearedActiveTrace, type DraftEntry, type ProviderProfileOption } from "./workbench-session";
|
||||
|
||||
@@ -60,7 +60,15 @@ export const useWorkbenchStore = defineStore("workbench", () => {
|
||||
}
|
||||
|
||||
async function refreshLive(): Promise<void> {
|
||||
const [healthLive, health, restIndex, adapter, hwpodSpecs, hwpodNodeOps, liveBuilds] = await Promise.all([api.healthLive(), api.health(), api.restIndex(), api.adapter(), api.hwpod.specs(), api.hwpod.nodeOpsHealth(), api.liveBuilds()]);
|
||||
const [healthLive, health, restIndex, adapter, hwpodSpecs, hwpodNodeOps, liveBuilds] = await Promise.all([
|
||||
liveCall("health/live", api.healthLive),
|
||||
liveCall("health", api.health),
|
||||
liveCall("REST index", api.restIndex),
|
||||
liveCall("adapter", api.adapter),
|
||||
liveCall("hwpod specs", api.hwpod.specs),
|
||||
liveCall("hwpod node ops", api.hwpod.nodeOpsHealth),
|
||||
liveCall("live builds", api.liveBuilds)
|
||||
]);
|
||||
live.value = { healthLive, health, restIndex, adapter, hwpodSpecs, hwpodNodeOps, liveBuilds, loadedAt: new Date().toISOString() };
|
||||
}
|
||||
|
||||
@@ -313,6 +321,14 @@ function messagesFromWorkspace(workspace: WorkspaceRecord | null): ChatMessage[]
|
||||
return source.map((message) => ({ ...message, id: message.id ?? nextProtocolId("msg"), title: message.title ?? (message.role === "user" ? "用户" : "Code Agent"), createdAt: message.createdAt ?? new Date().toISOString(), status: message.status ?? "source" }));
|
||||
}
|
||||
|
||||
export async function liveCall<T>(label: string, call: () => Promise<ApiResult<T>>): Promise<ApiResult<T>> {
|
||||
try {
|
||||
return await call();
|
||||
} catch (error) {
|
||||
return { ok: false, status: 0, data: null, error: `${label}: ${error instanceof Error ? error.message : String(error)}` };
|
||||
}
|
||||
}
|
||||
|
||||
function makeMessage(role: ChatMessage["role"], text: string, status: ChatMessage["status"], extra: Partial<ChatMessage> = {}): ChatMessage {
|
||||
return { id: nextProtocolId("msg"), role, title: extra.title ?? (role === "user" ? "用户" : "Code Agent"), text, status, createdAt: new Date().toISOString(), ...extra };
|
||||
}
|
||||
|
||||
@@ -1,13 +1,22 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { useAuthStore } from "@/stores/auth";
|
||||
|
||||
const auth = useAuthStore();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const username = ref("admin");
|
||||
const password = ref("");
|
||||
|
||||
async function submit(): Promise<void> {
|
||||
await auth.login(username.value, password.value);
|
||||
if (auth.isAuthenticated) await router.replace(nextPath());
|
||||
}
|
||||
|
||||
function nextPath(): string {
|
||||
const redirect = route.query.redirect;
|
||||
return typeof redirect === "string" && redirect.startsWith("/") && !redirect.startsWith("//") ? redirect : "/workbench";
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user