- console: GET /api/workflows/{id}, /runs/{run_id}, /runs/{run_id}/diagnosis
(journal trace + sanitized bounded log tails, workflow/run pairing enforced)
- workbench/: dsh 宿主插件(7 个工作流工具、中文系统提示词、失败监控器、
本机回环桥接服务)+ 侧边栏面板客户端包(sidebar.footer.action 与
shell.overlay 追加插槽)+ 降级独立面板 + 一键启动脚本
- adapters/browser: 收敛 looks_like_login_url 到共享层,修复
jd_main_image_collector 对 gyxx_flow.accounts 的越层导入
- tests: 新端点覆盖;replay_policy 断言对齐已迁移的 catalog(repeatable)
58 lines
1.3 KiB
JavaScript
58 lines
1.3 KiB
JavaScript
/**
|
|
* GYXX 工作台面板 —— 极简外部存储(避免向客户端包引入额外依赖)。
|
|
* React 18 的 useSyncExternalStore 直接订阅。
|
|
*/
|
|
|
|
const listeners = new Set()
|
|
|
|
let state = {
|
|
open: false,
|
|
loading: false,
|
|
error: null,
|
|
generatedAt: null,
|
|
summary: null,
|
|
workflows: [],
|
|
selectedId: null,
|
|
detail: null,
|
|
detailLoading: false,
|
|
runs: [],
|
|
diagnosis: null,
|
|
diagnosisLoading: false,
|
|
question: '',
|
|
businessDate: defaultBusinessDate(),
|
|
alerts: [],
|
|
seenAlertIds: {},
|
|
toasts: [],
|
|
}
|
|
|
|
export function defaultBusinessDate() {
|
|
const now = new Date()
|
|
now.setDate(now.getDate() - 1)
|
|
const pad = (value) => String(value).padStart(2, '0')
|
|
return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`
|
|
}
|
|
|
|
export function getState() {
|
|
return state
|
|
}
|
|
|
|
export function update(patch) {
|
|
state = { ...state, ...patch }
|
|
for (const listener of listeners) listener()
|
|
}
|
|
|
|
export function subscribe(listener) {
|
|
listeners.add(listener)
|
|
return () => listeners.delete(listener)
|
|
}
|
|
|
|
export function pushToast(toast) {
|
|
const id = `t-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`
|
|
update({ toasts: [...state.toasts, { id, ...toast }] })
|
|
return id
|
|
}
|
|
|
|
export function dismissToast(id) {
|
|
update({ toasts: state.toasts.filter((toast) => toast.id !== id) })
|
|
}
|