Files
gyxx-flow/workbench/plugin/client/src/index.jsx
T

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',
)
}