86 lines
2.7 KiB
React
86 lines
2.7 KiB
React
/**
|
|
* GYXX 工作台客户端插件入口。
|
|
* 由 esbuild 打包为 CJS 并通过 window.__ModuleLoader__ 注册(见 scripts/build-client.mjs)。
|
|
* 运行时只依赖 dsh 平台共享模块表中的 react。
|
|
*/
|
|
|
|
import { createElement, useSyncExternalStore } from 'react'
|
|
import { WorkflowPanel, refreshWorkflows } from './Panel.jsx'
|
|
import { Toasts } from './Toasts.jsx'
|
|
import { getState, subscribe, update } from './store.js'
|
|
import stylesText from './styles.css'
|
|
|
|
export const inject = ['slots']
|
|
|
|
function useWorkbench() {
|
|
return useSyncExternalStore(subscribe, getState)
|
|
}
|
|
|
|
function injectStyles() {
|
|
if (typeof document === 'undefined') return
|
|
if (document.getElementById('gyxxwb-styles')) return
|
|
const style = document.createElement('style')
|
|
style.id = 'gyxxwb-styles'
|
|
style.textContent = stylesText
|
|
document.head.appendChild(style)
|
|
}
|
|
|
|
/** 侧边栏底部动作:工作流面板开关 + 聚合状态点。 */
|
|
function WorkbenchFooterAction() {
|
|
const s = useWorkbench()
|
|
const failed = s.workflows.filter((w) => !w.active_run && w.last_run?.status === 'failed').length
|
|
const running = s.workflows.filter((w) => w.active_run).length
|
|
const tone = failed > 0 ? 'failed' : running > 0 ? 'running' : 'success'
|
|
return createElement(
|
|
'button',
|
|
{
|
|
type: 'button',
|
|
className: `gyxxwb-footer-btn${s.open ? ' gyxxwb-footer-btn-active' : ''}`,
|
|
title: 'GYXX 工作流工作台',
|
|
onClick: () => {
|
|
const next = !getState().open
|
|
update({ open: next })
|
|
if (next) refreshWorkflows()
|
|
},
|
|
},
|
|
createElement('span', { className: `gyxxwb-dot gyxxwb-dot-${tone}` }),
|
|
createElement('span', null, '工作流'),
|
|
)
|
|
}
|
|
|
|
/** 覆盖层根:左侧抽屉面板 + 失败 toast。 */
|
|
function WorkbenchOverlay() {
|
|
return createElement(
|
|
'div',
|
|
{ className: 'gyxxwb-overlay' },
|
|
createElement(WorkflowPanel, null),
|
|
createElement(Toasts, null),
|
|
)
|
|
}
|
|
|
|
export function apply(ctx) {
|
|
injectStyles()
|
|
// 插槽须等宿主声明后才能注册:slots.inject 会等待座位声明(顺序安全),
|
|
// 直接 register 在我们先于 ui-sidebar/ui-layout 加载时会报“slot is not declared”。
|
|
ctx.effect(
|
|
() =>
|
|
ctx.slots.inject('sidebar.footer.action', () =>
|
|
ctx.slots.register(
|
|
{ name: 'sidebar.footer.action', id: 'gyxx-workbench.footer' },
|
|
WorkbenchFooterAction,
|
|
),
|
|
),
|
|
'gyxx-workbench: footer action',
|
|
)
|
|
ctx.effect(
|
|
() =>
|
|
ctx.slots.inject('shell.overlay', () =>
|
|
ctx.slots.register(
|
|
{ name: 'shell.overlay', id: 'gyxx-workbench.overlay' },
|
|
WorkbenchOverlay,
|
|
),
|
|
),
|
|
'gyxx-workbench: overlay',
|
|
)
|
|
}
|