Files
pikasTech-HWLAB/web/hwlab-cloud-web/src/components/hwpod/hwpod-workspace-presentation.ts
T
2026-07-21 14:12:32 +02:00

88 lines
4.2 KiB
TypeScript

import type { HwpodOperationResponse } from "@/types";
export type WorkspacePreviewMode = "text" | "markdown";
export interface BuildOperationPresentation {
status: string;
label: string;
tone: "idle" | "running" | "ok" | "warn" | "error";
operationId: string | null;
exitCode: number | null;
jobId: string | null;
log: string;
terminal: boolean;
}
export function workspacePreviewMode(path: string): WorkspacePreviewMode {
return /\.(?:md|markdown)$/iu.test(path.trim()) ? "markdown" : "text";
}
export function presentBuildOperation(operation: HwpodOperationResponse | null, pending = false): BuildOperationPresentation {
if (!operation) {
return {
status: pending ? "submitting" : "idle",
label: pending ? "正在提交编译" : "尚未编译",
tone: pending ? "running" : "idle",
operationId: null,
exitCode: null,
jobId: null,
log: "",
terminal: false,
};
}
const activity = record(operation.result);
const response = record(activity.response);
const result = Array.isArray(response.results) ? record(response.results[0]) : {};
const output = record(result.output);
const commands = Array.isArray(output.commands) ? output.commands.map(record) : [];
const lastCommand = commands.at(-1) ?? {};
const stdout = stringValue(output.stdout) || stringValue(lastCommand.stdout);
const stderr = stringValue(output.stderr) || stringValue(lastCommand.stderr);
const parsed = parseJsonRecord(stdout);
const toolStatus = stringValue(parsed.status).toLowerCase();
const operationStatus = stringValue(operation.status).toLowerCase() || "unknown";
const exitCode = numberValue(output.exitCode, lastCommand.exitCode, parsed.return_code, parsed.returnCode);
const jobId = stringValue(parsed.job_id) || stringValue(parsed.jobId) || null;
const asyncQueued = parsed.accepted === true && ["queued", "running", "accepted"].includes(toolStatus);
const failed = operation.error != null
|| activity.ok === false
|| response.ok === false
|| result.ok === false
|| output.ok === false
|| (exitCode !== null && exitCode !== 0)
|| ["failed", "error", "canceled", "cancelled", "timed-out", "timeout"].includes(toolStatus)
|| ["failed", "canceled", "cancelled", "terminated", "timed-out", "timeout"].includes(operationStatus);
const terminal = !asyncQueued && ["completed", "succeeded", "failed", "canceled", "cancelled", "terminated", "timed-out", "timeout"].includes(operationStatus);
const running = pending || asyncQueued || ["accepted", "queued", "running", "pending", "in-progress"].includes(operationStatus);
const log = [stderr ? `stderr\n${stderr.trim()}` : "", stdout ? `stdout\n${stdout.trim()}` : ""].filter(Boolean).join("\n\n");
if (failed) return { status: toolStatus || operationStatus, label: "编译失败", tone: "error", operationId: operation.operationId, exitCode, jobId, log, terminal: true };
if (asyncQueued) return { status: toolStatus, label: "构建已排队,等待真实终态", tone: "warn", operationId: operation.operationId, exitCode, jobId, log, terminal: false };
if (running) return { status: operationStatus, label: "正在等待 Windows Keil 构建终态", tone: "running", operationId: operation.operationId, exitCode, jobId, log, terminal: false };
if (terminal) return { status: operationStatus, label: "编译通过", tone: "ok", operationId: operation.operationId, exitCode, jobId, log, terminal: true };
return { status: operationStatus, label: "编译状态未知", tone: "warn", operationId: operation.operationId, exitCode, jobId, log, terminal: false };
}
function record(value: unknown): Record<string, unknown> {
return value && typeof value === "object" && !Array.isArray(value) ? value as Record<string, unknown> : {};
}
function stringValue(value: unknown): string {
return typeof value === "string" ? value.trim() : "";
}
function numberValue(...values: unknown[]): number | null {
for (const value of values) {
const number = Number(value);
if (Number.isFinite(number)) return number;
}
return null;
}
function parseJsonRecord(value: string): Record<string, unknown> {
if (!value) return {};
try { return record(JSON.parse(value)); }
catch { return {}; }
}