@you-agent-factory/factory-graph 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +3 -0
- package/README.md +22 -0
- package/dist/factory-graph-replay-surface.d.ts +21 -0
- package/dist/factory-graph-replay-surface.js +189 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +11 -0
- package/dist/semantic-doc-node.d.ts +16 -0
- package/dist/semantic-doc-node.js +29 -0
- package/dist/semantic-icon.d.ts +10 -0
- package/dist/semantic-icon.js +87 -0
- package/dist/semantic-node-shell.d.ts +18 -0
- package/dist/semantic-node-shell.js +56 -0
- package/dist/semantic-node-style.d.ts +12 -0
- package/dist/semantic-node-style.js +29 -0
- package/dist/semantic-nodes.d.ts +15 -0
- package/dist/semantic-nodes.js +14 -0
- package/dist/semantic-place-nodes.d.ts +47 -0
- package/dist/semantic-place-nodes.js +157 -0
- package/dist/semantic-support-nodes.d.ts +61 -0
- package/dist/semantic-support-nodes.js +121 -0
- package/dist/semantic-workstation-node.d.ts +34 -0
- package/dist/semantic-workstation-node.js +84 -0
- package/dist/semantic-workstation-presentation.d.ts +31 -0
- package/dist/semantic-workstation-presentation.js +127 -0
- package/dist/source.d.ts +29 -0
- package/dist/source.js +18 -0
- package/dist/work-state-presentation.d.ts +8 -0
- package/dist/work-state-presentation.js +40 -0
- package/package.json +54 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { GraphNodeButton } from "@you-agent-factory/components/graphs";
|
|
3
|
+
import { GraphSemanticIcon } from "./semantic-icon.js";
|
|
4
|
+
import { FactoryGraphNodeShell, } from "./semantic-node-shell.js";
|
|
5
|
+
import { factoryGraphNodeHoverClassName, factoryGraphNodeSurfaceClassName, } from "./semantic-node-style.js";
|
|
6
|
+
import { FactoryGraphNodeBadge, } from "./semantic-support-nodes.js";
|
|
7
|
+
import { workStatePhaseSemanticIconClassName, workStatePhaseSemanticIconKind, workStatePhaseSurfaceClassName, } from "./work-state-presentation.js";
|
|
8
|
+
const DOT_LIMIT = 10;
|
|
9
|
+
const CONTENT_CLASS = "flex min-w-0 w-full flex-col gap-0.5 overflow-hidden";
|
|
10
|
+
export function FactoryGraphStatePositionNodeView(props) {
|
|
11
|
+
return _jsx(FactoryGraphPlaceNodeView, { ...props });
|
|
12
|
+
}
|
|
13
|
+
export function FactoryGraphConstraintNodeView(props) {
|
|
14
|
+
return _jsx(FactoryGraphPlaceNodeView, { ...props });
|
|
15
|
+
}
|
|
16
|
+
function FactoryGraphPlaceNodeView({ data }) {
|
|
17
|
+
const placeLabel = formatPlaceLabel(data.place);
|
|
18
|
+
const selectable = data.place.kind === "work_state" && data.onSelectStateNode !== undefined;
|
|
19
|
+
const stateNode = data.place.kind === "work_state";
|
|
20
|
+
const nodeType = stateNode
|
|
21
|
+
? "statePosition"
|
|
22
|
+
: data.place.kind === "resource"
|
|
23
|
+
? "resource"
|
|
24
|
+
: "constraint";
|
|
25
|
+
const className = classNames(placeNodeClassName(data.place), factoryGraphNodeHoverClassName({
|
|
26
|
+
activeFlow: data.activeFlow,
|
|
27
|
+
muted: data.muted,
|
|
28
|
+
selected: data.selectedStateNode,
|
|
29
|
+
validationError: data.validationError,
|
|
30
|
+
}), data.activeFlow &&
|
|
31
|
+
!data.selectedStateNode &&
|
|
32
|
+
!data.validationError &&
|
|
33
|
+
"border-af-success-border shadow-af-success-chip", data.selectedStateNode &&
|
|
34
|
+
!data.validationError &&
|
|
35
|
+
"border-primary shadow-af-accent-selected", data.validationError &&
|
|
36
|
+
"ring-2 ring-af-danger-border motion-safe:animate-pulse", data.muted && "opacity-[0.45]");
|
|
37
|
+
const content = stateNode ? (_jsx(FactoryGraphStatePositionContent, { locale: data.locale, place: data.place, tokenCount: data.tokenCount })) : (_jsx(FactoryGraphStaticPlaceContent, { locale: data.locale, place: data.place, tokenCount: data.tokenCount }));
|
|
38
|
+
return (_jsx(FactoryGraphNodeShell, { className: classNames("justify-center text-left", className), handles: data.handles, nodeType: nodeType, children: selectable ? (_jsx(GraphNodeButton, { "aria-invalid": data.validationError ? true : undefined, "aria-label": data.validationMessage ?? selectStateLabel(placeLabel, data.locale), "aria-pressed": data.selectedStateNode, className: CONTENT_CLASS, "data-selected-state": data.selectedStateNode ? "true" : undefined, title: data.validationMessage, onClick: (event) => {
|
|
39
|
+
event.stopPropagation();
|
|
40
|
+
data.onSelectStateNode?.(data.place.place_id);
|
|
41
|
+
}, children: content })) : (content) }));
|
|
42
|
+
}
|
|
43
|
+
function FactoryGraphStatePositionContent({ locale, place, tokenCount, }) {
|
|
44
|
+
const label = formatPlaceLabel(place);
|
|
45
|
+
return (_jsxs(_Fragment, { children: [_jsxs("span", { className: "grid h-6 max-h-6 min-w-0 grid-cols-[auto_minmax(0,1fr)] items-center gap-1.5 overflow-hidden", "data-state-label-zone": true, children: [_jsx(FactoryGraphPlaceSemanticIcon, { locale: locale, place: place }), _jsx(FactoryGraphPlaceLabelText, { dataPrefix: "state", place: place })] }), _jsx("span", { className: "flex min-h-5 w-full shrink-0 items-center justify-center overflow-hidden", "data-state-marker-zone": true, title: label, children: stateMarkers(tokenCount, locale) ?? (_jsx("span", { className: "sr-only", children: activeItemCountLabel(tokenCount, locale) })) })] }));
|
|
46
|
+
}
|
|
47
|
+
function FactoryGraphStaticPlaceContent({ locale, place, tokenCount, }) {
|
|
48
|
+
const label = formatPlaceLabel(place);
|
|
49
|
+
if (place.kind !== "resource")
|
|
50
|
+
return (_jsxs("div", { className: "grid min-w-0 gap-0.5 overflow-hidden", "data-place-label-container": true, children: [_jsxs("span", { className: "flex min-w-0 items-center gap-1.5 overflow-hidden", "data-place-label-zone": true, title: label, children: [_jsx(FactoryGraphPlaceSemanticIcon, { locale: locale, place: place }), _jsx("strong", { className: "block min-w-0 truncate whitespace-nowrap font-mono text-[0.86rem] font-bold leading-tight", children: label })] }), _jsx("span", { className: "flex min-h-4 w-full shrink-0 items-center justify-start overflow-hidden", "data-place-marker-zone": true, title: label, children: tokenCountDisplay(place, tokenCount, locale) })] }));
|
|
51
|
+
return (_jsxs("div", { className: "flex min-w-0 w-full flex-col overflow-hidden", "data-place-label-container": true, children: [_jsxs("span", { "aria-label": label, className: "grid h-6 max-h-6 min-w-0 grid-cols-[auto_minmax(0,1fr)] items-center gap-1.5 overflow-hidden", "data-place-label-zone": true, role: "img", children: [_jsx(FactoryGraphPlaceSemanticIcon, { locale: locale, place: place }), _jsx(FactoryGraphPlaceLabelText, { dataPrefix: "place", place: place })] }), _jsx("span", { className: "flex min-h-5 w-full shrink-0 items-center justify-start overflow-hidden", "data-place-marker-zone": true, title: label, children: tokenCountDisplay(place, tokenCount, locale) })] }));
|
|
52
|
+
}
|
|
53
|
+
function FactoryGraphPlaceSemanticIcon({ locale, place, }) {
|
|
54
|
+
const kind = place.kind === "work_state"
|
|
55
|
+
? workStatePhaseSemanticIconKind(place.state_category)
|
|
56
|
+
: place.kind === "resource"
|
|
57
|
+
? "resource"
|
|
58
|
+
: place.kind === "limit"
|
|
59
|
+
? "limit"
|
|
60
|
+
: "constraint";
|
|
61
|
+
const className = place.kind === "work_state"
|
|
62
|
+
? workStatePhaseSemanticIconClassName(place.state_category)
|
|
63
|
+
: place.kind === "resource"
|
|
64
|
+
? "text-success"
|
|
65
|
+
: place.kind === "limit"
|
|
66
|
+
? "text-error"
|
|
67
|
+
: "text-info";
|
|
68
|
+
const label = placeSemanticLabel(place, locale);
|
|
69
|
+
return (_jsx("span", { className: "flex min-h-4 shrink-0 items-center", "data-place-semantic-icon": true, title: placeKindLabel(place, locale), children: _jsx(GraphSemanticIcon, { className: classNames("h-3.5 w-3.5", className), kind: kind, label: label }) }));
|
|
70
|
+
}
|
|
71
|
+
function FactoryGraphPlaceLabelText({ dataPrefix, place, }) {
|
|
72
|
+
const label = formatPlaceLabel(place);
|
|
73
|
+
const parts = placeLabelParts(place);
|
|
74
|
+
return (_jsxs("span", { className: "grid min-w-0 gap-px overflow-hidden", title: label, children: [_jsx("span", { className: "block min-w-0 overflow-hidden text-ellipsis whitespace-nowrap text-[0.62rem] font-bold uppercase leading-none text-on-surface-subtle", "data-place-work-type": dataPrefix === "place" ? true : undefined, "data-state-work-type": dataPrefix === "state" ? true : undefined, title: parts.workType, children: parts.workType }), _jsx("span", { className: "block min-w-0 overflow-hidden truncate whitespace-nowrap font-mono text-[0.76rem] font-bold leading-[0.82rem] text-on-surface", "data-place-state-value": dataPrefix === "place" ? true : undefined, "data-state-value": dataPrefix === "state" ? true : undefined, title: parts.stateValue, children: parts.stateValue })] }));
|
|
75
|
+
}
|
|
76
|
+
function stateMarkers(count, locale) {
|
|
77
|
+
if (count === 0)
|
|
78
|
+
return null;
|
|
79
|
+
return count > DOT_LIMIT ? (_jsx(FactoryGraphWorkProgressMarker, { ariaLabel: activeItemCountLabel(count, locale), className: "inline-flex min-h-5 min-w-7 rounded-full px-2 text-[0.76rem]", count: count, "data-state-work-progress": "numeric", kind: "numeric" })) : (_jsx(FactoryGraphWorkProgressMarker, { ariaLabel: activeItemCountLabel(count, locale), className: "inline-grid grid-cols-[repeat(5,0.5rem)] justify-center gap-1", "data-state-work-progress": "dots", dotCount: count, dotDataAttribute: "data-state-work-progress-dot", kind: "dots" }));
|
|
80
|
+
}
|
|
81
|
+
export function FactoryGraphWorkProgressMarker(props) {
|
|
82
|
+
if (props.kind === "numeric") {
|
|
83
|
+
const { ariaLabel, className, count, kind: _kind, ...rest } = props;
|
|
84
|
+
return (_jsx("span", { "aria-label": ariaLabel, className: classNames("items-center justify-center border border-af-success-border bg-success-container font-mono font-bold leading-none text-success", className), role: "status", ...rest, children: count }));
|
|
85
|
+
}
|
|
86
|
+
const { ariaLabel, className, dotClassName = "h-2 w-2", dotCount, dotDataAttribute, kind: _kind, suffix, ...rest } = props;
|
|
87
|
+
return (_jsxs("span", { "aria-label": ariaLabel, className: classNames("items-center justify-center border border-af-success-border bg-success-container", className), role: "status", ...rest, children: [Array.from({ length: dotCount }, (_, index) => `dot-${index}`).map((key, index) => (_jsx("span", { "aria-hidden": "true", className: classNames("rounded-full bg-success", dotClassName), "data-current-activity-work-progress-dot": String(index), [dotDataAttribute]: String(index) }, key))), suffix] }));
|
|
88
|
+
}
|
|
89
|
+
function tokenCountDisplay(place, count, locale) {
|
|
90
|
+
return (_jsx(FactoryGraphNodeBadge, { "aria-label": tokenCountLabel(place, count, locale), className: "w-fit", "data-place-token-count": true, role: "status", children: count }));
|
|
91
|
+
}
|
|
92
|
+
function placeNodeClassName(place) {
|
|
93
|
+
return place.kind === "work_state"
|
|
94
|
+
? workStatePhaseSurfaceClassName(place.state_category)
|
|
95
|
+
: place.kind === "resource"
|
|
96
|
+
? classNames(factoryGraphNodeSurfaceClassName("resource"), "text-on-surface")
|
|
97
|
+
: classNames(factoryGraphNodeSurfaceClassName("info"), "border-dashed text-on-surface");
|
|
98
|
+
}
|
|
99
|
+
function formatPlaceLabel(place) {
|
|
100
|
+
return place.type_id && place.state_value
|
|
101
|
+
? `${place.type_id}:${place.state_value}`
|
|
102
|
+
: place.place_id;
|
|
103
|
+
}
|
|
104
|
+
function placeLabelParts(place) {
|
|
105
|
+
return {
|
|
106
|
+
stateValue: place.state_value ?? place.place_id,
|
|
107
|
+
workType: place.type_id ?? "work",
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function classNames(...values) {
|
|
111
|
+
return values.filter(Boolean).join(" ");
|
|
112
|
+
}
|
|
113
|
+
function activeItemCountLabel(count, locale) {
|
|
114
|
+
return locale === "zh-CN"
|
|
115
|
+
? `${count} 个活动项`
|
|
116
|
+
: `${count} active ${count === 1 ? "item" : "items"}`;
|
|
117
|
+
}
|
|
118
|
+
function selectStateLabel(label, locale) {
|
|
119
|
+
return locale === "zh-CN" ? `选择 ${label} 状态` : `Select ${label} state`;
|
|
120
|
+
}
|
|
121
|
+
function placeKindLabel(place, locale) {
|
|
122
|
+
const chinese = locale === "zh-CN";
|
|
123
|
+
if (place.kind === "work_state")
|
|
124
|
+
return place.state_category === "TERMINAL"
|
|
125
|
+
? chinese
|
|
126
|
+
? "终止状态"
|
|
127
|
+
: "Terminal"
|
|
128
|
+
: place.state_category === "FAILED"
|
|
129
|
+
? chinese
|
|
130
|
+
? "失败状态"
|
|
131
|
+
: "Failed"
|
|
132
|
+
: chinese
|
|
133
|
+
? "队列"
|
|
134
|
+
: "Queue";
|
|
135
|
+
if (place.kind === "resource")
|
|
136
|
+
return chinese ? "资源" : "Resource";
|
|
137
|
+
return place.kind === "limit"
|
|
138
|
+
? chinese
|
|
139
|
+
? "限制"
|
|
140
|
+
: "Limit"
|
|
141
|
+
: chinese
|
|
142
|
+
? "约束"
|
|
143
|
+
: "Constraint";
|
|
144
|
+
}
|
|
145
|
+
function placeSemanticLabel(place, locale) {
|
|
146
|
+
return place.kind === "work_state" && place.state_category === "PROCESSING"
|
|
147
|
+
? locale === "zh-CN"
|
|
148
|
+
? "处理中状态"
|
|
149
|
+
: "Processing state"
|
|
150
|
+
: placeKindLabel(place, locale);
|
|
151
|
+
}
|
|
152
|
+
function tokenCountLabel(place, count, locale) {
|
|
153
|
+
if (locale === "zh-CN")
|
|
154
|
+
return `${count} 个${placeKindLabel(place, locale)}令牌`;
|
|
155
|
+
const token = count === 1 ? "token" : "tokens";
|
|
156
|
+
return `${count} ${placeKindLabel(place, locale).toLowerCase()} ${token}`;
|
|
157
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { Node, NodeProps } from "@xyflow/react";
|
|
2
|
+
import type { ComponentPropsWithoutRef, ReactNode } from "react";
|
|
3
|
+
import { type FactoryGraphNodeHandle } from "./semantic-node-shell.js";
|
|
4
|
+
/** The portion of a Factory place needed by the original semantic node views. */
|
|
5
|
+
export interface FactoryGraphPlaceRef {
|
|
6
|
+
kind?: string;
|
|
7
|
+
place_id: string;
|
|
8
|
+
state_value?: string | null;
|
|
9
|
+
type_id?: string | null;
|
|
10
|
+
}
|
|
11
|
+
export interface FactoryGraphWorkerNodeData extends Record<string, unknown> {
|
|
12
|
+
activeFlow: boolean;
|
|
13
|
+
factoryGraphNodeId?: string;
|
|
14
|
+
handles: FactoryGraphNodeHandle[];
|
|
15
|
+
kind: "worker";
|
|
16
|
+
locale?: string;
|
|
17
|
+
muted: boolean;
|
|
18
|
+
onSelectWorker?: (workerName: string) => void;
|
|
19
|
+
place: FactoryGraphPlaceRef;
|
|
20
|
+
selectedWorker: boolean;
|
|
21
|
+
}
|
|
22
|
+
export type FactoryGraphWorkerNode = Node<FactoryGraphWorkerNodeData, "worker">;
|
|
23
|
+
export interface FactoryGraphWorkTypeNodeData extends Record<string, unknown> {
|
|
24
|
+
activeFlow: boolean;
|
|
25
|
+
factoryGraphNodeId?: string;
|
|
26
|
+
handles: FactoryGraphNodeHandle[];
|
|
27
|
+
isDefaultWorkType?: boolean;
|
|
28
|
+
kind: "work-type";
|
|
29
|
+
locale?: string;
|
|
30
|
+
muted: boolean;
|
|
31
|
+
onSelectWorkType?: (workTypeName: string) => void;
|
|
32
|
+
place: FactoryGraphPlaceRef;
|
|
33
|
+
selectedWorkType?: boolean;
|
|
34
|
+
validationError?: boolean;
|
|
35
|
+
validationMessage?: string;
|
|
36
|
+
}
|
|
37
|
+
export type FactoryGraphWorkTypeNode = Node<FactoryGraphWorkTypeNodeData, "workType">;
|
|
38
|
+
export interface FactoryGraphResourceNodeData extends Record<string, unknown> {
|
|
39
|
+
activeFlow: boolean;
|
|
40
|
+
factoryGraphNodeId?: string;
|
|
41
|
+
handles: FactoryGraphNodeHandle[];
|
|
42
|
+
kind: "resource";
|
|
43
|
+
locale?: string;
|
|
44
|
+
muted: boolean;
|
|
45
|
+
onSelectResource?: (resourceName: string) => void;
|
|
46
|
+
place: FactoryGraphPlaceRef;
|
|
47
|
+
selectedResource: boolean;
|
|
48
|
+
tokenCount: number;
|
|
49
|
+
}
|
|
50
|
+
export type FactoryGraphResourceNode = Node<FactoryGraphResourceNodeData, "resource">;
|
|
51
|
+
/** Original Factory worker node, with host-owned worker selection. */
|
|
52
|
+
export declare function FactoryGraphWorkerNodeView({ data, }: NodeProps<FactoryGraphWorkerNode>): import("react").JSX.Element;
|
|
53
|
+
/** Original Factory work-type node, with host-owned selection and validation. */
|
|
54
|
+
export declare function FactoryGraphWorkTypeNodeView({ data, }: NodeProps<FactoryGraphWorkTypeNode>): import("react").JSX.Element;
|
|
55
|
+
/** Original Factory resource node, with host-owned resource selection. */
|
|
56
|
+
export declare function FactoryGraphResourceNodeView({ data, }: NodeProps<FactoryGraphResourceNode>): import("react").JSX.Element;
|
|
57
|
+
export declare function FactoryGraphNodeBadge({ children, className, tone, weight, ...rest }: ComponentPropsWithoutRef<"span"> & {
|
|
58
|
+
children: ReactNode;
|
|
59
|
+
tone?: "danger" | "info" | "neutral" | "success" | "warning";
|
|
60
|
+
weight?: "body" | "label";
|
|
61
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { GraphNodeButton } from "@you-agent-factory/components/graphs";
|
|
3
|
+
import { GraphSemanticIcon } from "./semantic-icon.js";
|
|
4
|
+
import { FactoryGraphNodeShell, } from "./semantic-node-shell.js";
|
|
5
|
+
import { factoryGraphNodeHoverClassName, factoryGraphNodeSurfaceClassName, } from "./semantic-node-style.js";
|
|
6
|
+
/** Original Factory worker node, with host-owned worker selection. */
|
|
7
|
+
export function FactoryGraphWorkerNodeView({ data, }) {
|
|
8
|
+
const workerName = resolveWorkerName(data);
|
|
9
|
+
const label = `worker:${workerName}`;
|
|
10
|
+
const workerLabel = semanticLabel("worker", data.locale);
|
|
11
|
+
const selectable = data.onSelectWorker !== undefined;
|
|
12
|
+
const content = (_jsxs("span", { "aria-label": label, className: "flex min-w-0 items-center gap-1.5 overflow-hidden", "data-worker-label-zone": true, role: "img", title: label, children: [_jsx("span", { className: "sr-only", children: label }), _jsx(GraphSemanticIcon, { className: "h-3.5 w-3.5 shrink-0 text-info", kind: "worker", label: workerLabel }), _jsxs("span", { className: "grid min-w-0 gap-px overflow-hidden", children: [_jsx("span", { className: "block min-w-0 overflow-hidden text-ellipsis whitespace-nowrap text-[0.62rem] font-bold uppercase leading-none text-info", children: workerLabel }), _jsx("strong", { className: "block min-w-0 truncate whitespace-nowrap font-mono text-[0.8rem] font-bold leading-tight text-on-surface", children: workerName })] })] }));
|
|
13
|
+
return (_jsx(FactoryGraphNodeShell, { className: classNames(factoryGraphNodeSurfaceClassName("info"), "justify-center text-left text-on-surface", factoryGraphNodeHoverClassName({
|
|
14
|
+
activeFlow: data.activeFlow,
|
|
15
|
+
muted: data.muted,
|
|
16
|
+
selected: data.selectedWorker,
|
|
17
|
+
}), data.activeFlow &&
|
|
18
|
+
!data.selectedWorker &&
|
|
19
|
+
"border-af-success-border shadow-af-success-chip", data.selectedWorker && "border-primary shadow-af-accent-selected", data.muted && "opacity-[0.45]"), handles: data.handles, nodeType: "worker", children: selectable ? (_jsx(GraphNodeButton, { "aria-label": selectLabel("worker", workerName, data.locale), "aria-pressed": data.selectedWorker, className: "grid min-w-0 gap-0.5 overflow-hidden", "data-selected-worker": data.selectedWorker ? "true" : undefined, onClick: (event) => {
|
|
20
|
+
event.stopPropagation();
|
|
21
|
+
data.onSelectWorker?.(workerName);
|
|
22
|
+
}, children: content })) : (content) }));
|
|
23
|
+
}
|
|
24
|
+
/** Original Factory work-type node, with host-owned selection and validation. */
|
|
25
|
+
export function FactoryGraphWorkTypeNodeView({ data, }) {
|
|
26
|
+
const name = workTypeName(data.place);
|
|
27
|
+
const label = `work-type:${name}`;
|
|
28
|
+
const workTypeLabel = semanticLabel("work-type", data.locale);
|
|
29
|
+
const selectable = data.onSelectWorkType !== undefined;
|
|
30
|
+
const content = (_jsxs("span", { "aria-hidden": selectable ? true : undefined, className: "flex min-w-0 items-center gap-1.5 overflow-hidden", "data-work-type-label-zone": true, ...(selectable ? {} : { "aria-label": label, role: "img" }), title: data.validationMessage ?? label, children: [selectable ? null : _jsx("span", { className: "sr-only", children: label }), _jsx(GraphSemanticIcon, { className: "h-3.5 w-3.5 shrink-0 text-info", kind: "work-type", label: workTypeLabel }), _jsxs("span", { className: "grid min-w-0 gap-px overflow-hidden", children: [_jsxs("span", { className: "flex min-w-0 items-center gap-1 overflow-hidden", children: [_jsx("span", { className: "block min-w-0 overflow-hidden text-ellipsis whitespace-nowrap text-[0.62rem] font-bold uppercase leading-none text-info", children: workTypeLabel }), data.isDefaultWorkType ? (_jsx(FactoryGraphNodeBadge, { className: "max-w-full shrink", role: "status", tone: "info", weight: "label", children: defaultWorkTypeLabel(data.locale) })) : null] }), _jsx("strong", { className: "block min-w-0 truncate whitespace-nowrap font-mono text-[0.8rem] font-bold leading-tight text-on-surface", children: name })] })] }));
|
|
31
|
+
return (_jsx(FactoryGraphNodeShell, { className: classNames(factoryGraphNodeSurfaceClassName("info"), "justify-center border-dashed text-left text-on-surface", factoryGraphNodeHoverClassName({
|
|
32
|
+
activeFlow: data.activeFlow,
|
|
33
|
+
muted: data.muted,
|
|
34
|
+
selected: data.selectedWorkType,
|
|
35
|
+
validationError: data.validationError,
|
|
36
|
+
}), data.activeFlow && "border-info shadow-af-info-chip", data.muted && "opacity-[0.45]", data.validationError &&
|
|
37
|
+
"ring-2 ring-af-danger-border motion-safe:animate-pulse", data.selectedWorkType &&
|
|
38
|
+
!data.validationError &&
|
|
39
|
+
"border-primary shadow-af-accent-selected"), handles: data.handles, nodeType: "workType", children: selectable ? (_jsx(GraphNodeButton, { "aria-invalid": data.validationError ? true : undefined, "aria-label": selectLabel("work type", name, data.locale), "aria-pressed": data.selectedWorkType, className: "grid min-w-0 gap-0.5 overflow-hidden", "data-selected-work-type": data.selectedWorkType ? "true" : undefined, onClick: (event) => {
|
|
40
|
+
event.stopPropagation();
|
|
41
|
+
data.onSelectWorkType?.(name);
|
|
42
|
+
}, children: content })) : (_jsx("div", { className: "grid min-w-0 gap-0.5 overflow-hidden", children: content })) }));
|
|
43
|
+
}
|
|
44
|
+
/** Original Factory resource node, with host-owned resource selection. */
|
|
45
|
+
export function FactoryGraphResourceNodeView({ data, }) {
|
|
46
|
+
const label = resourceName(data.place);
|
|
47
|
+
const resourceLabel = semanticLabel("resource", data.locale);
|
|
48
|
+
const selectable = data.onSelectResource !== undefined;
|
|
49
|
+
const content = (_jsx(FactoryGraphResourceNodeContent, { label: label, locale: data.locale, place: data.place, resourceLabel: resourceLabel, tokenCount: data.tokenCount }));
|
|
50
|
+
return (_jsx(FactoryGraphNodeShell, { className: classNames(factoryGraphNodeSurfaceClassName("resource"), "justify-center text-left text-on-surface", factoryGraphNodeHoverClassName({
|
|
51
|
+
activeFlow: data.activeFlow,
|
|
52
|
+
muted: data.muted,
|
|
53
|
+
selected: data.selectedResource,
|
|
54
|
+
}), data.activeFlow &&
|
|
55
|
+
!data.selectedResource &&
|
|
56
|
+
"border-af-success-border shadow-af-success-chip", data.selectedResource && "border-primary shadow-af-accent-selected", data.muted && "opacity-[0.45]"), handles: data.handles, nodeType: "resource", children: selectable ? (_jsx(GraphNodeButton, { "aria-label": selectLabel("resource", label, data.locale), "aria-pressed": data.selectedResource, className: "flex min-w-0 w-full flex-col overflow-hidden", "data-selected-resource": data.selectedResource ? "true" : undefined, onClick: (event) => {
|
|
57
|
+
event.stopPropagation();
|
|
58
|
+
data.onSelectResource?.(label);
|
|
59
|
+
}, children: content })) : (content) }));
|
|
60
|
+
}
|
|
61
|
+
function FactoryGraphResourceNodeContent({ label, locale, place, resourceLabel, tokenCount, }) {
|
|
62
|
+
return (_jsxs("div", { className: "flex min-w-0 w-full flex-col overflow-hidden", children: [_jsxs("span", { "aria-label": label, className: "grid h-6 max-h-6 min-w-0 grid-cols-[auto_minmax(0,1fr)] items-center gap-1.5 overflow-hidden", "data-resource-label-zone": true, role: "img", children: [_jsx("span", { className: "flex min-h-4 shrink-0 items-center", title: resourceLabel, children: _jsx(GraphSemanticIcon, { className: "h-3.5 w-3.5 text-success", kind: "resource", label: resourceLabel }) }), _jsx("span", { className: "flex min-w-0 overflow-hidden", title: label, children: _jsx("span", { className: "block min-w-0 overflow-hidden truncate whitespace-nowrap font-mono text-[0.76rem] font-bold leading-[0.82rem] text-on-surface", "data-resource-name": true, title: label, children: label }) })] }), _jsx("span", { className: "flex min-h-5 w-full shrink-0 items-center justify-start overflow-hidden", "data-resource-token-zone": true, title: label, children: _jsx(FactoryGraphNodeBadge, { "aria-label": tokenCountLabel(place, tokenCount, locale), className: "w-fit", "data-resource-token-count": true, role: "status", children: tokenCount }) })] }));
|
|
63
|
+
}
|
|
64
|
+
export function FactoryGraphNodeBadge({ children, className, tone = "neutral", weight = "body", ...rest }) {
|
|
65
|
+
const toneClass = {
|
|
66
|
+
danger: "border-af-danger-border bg-error-container text-on-error-container",
|
|
67
|
+
info: "border-af-info-border bg-info-container text-on-info-container",
|
|
68
|
+
neutral: "border-outline bg-surface-container-low text-on-surface-variant",
|
|
69
|
+
success: "border-af-success-border bg-success-container text-on-success-container",
|
|
70
|
+
warning: "border-af-warning-border bg-warning-container text-on-warning-container",
|
|
71
|
+
}[tone];
|
|
72
|
+
return (_jsx("span", { className: classNames("inline-flex min-h-6 w-fit items-center justify-center gap-1 rounded-full border px-2 py-0.5 font-semibold leading-none", toneClass, weight === "body"
|
|
73
|
+
? "font-mono text-[0.68rem]"
|
|
74
|
+
: "text-[0.65rem] font-semibold uppercase tracking-[0.08em]", className), ...rest, children: children }));
|
|
75
|
+
}
|
|
76
|
+
function resolveWorkerName(data) {
|
|
77
|
+
return (data.place.state_value ??
|
|
78
|
+
data.factoryGraphNodeId?.replace(/^worker:/, "") ??
|
|
79
|
+
data.place.place_id.replace(/^place:worker:/, "").replace(/^worker:/, ""));
|
|
80
|
+
}
|
|
81
|
+
function workTypeName(place) {
|
|
82
|
+
return typeof place.state_value === "string" &&
|
|
83
|
+
place.state_value.trim().length > 0
|
|
84
|
+
? place.state_value
|
|
85
|
+
: place.place_id.replace(/^work-type:/, "");
|
|
86
|
+
}
|
|
87
|
+
function resourceName(place) {
|
|
88
|
+
return typeof place.type_id === "string" && place.type_id.trim().length > 0
|
|
89
|
+
? place.type_id
|
|
90
|
+
: place.place_id.replace(/:available$/, "");
|
|
91
|
+
}
|
|
92
|
+
function classNames(...values) {
|
|
93
|
+
return values.filter(Boolean).join(" ");
|
|
94
|
+
}
|
|
95
|
+
function semanticLabel(kind, locale) {
|
|
96
|
+
const chinese = locale === "zh-CN";
|
|
97
|
+
return kind === "resource"
|
|
98
|
+
? chinese
|
|
99
|
+
? "资源"
|
|
100
|
+
: "Resource"
|
|
101
|
+
: kind === "worker"
|
|
102
|
+
? chinese
|
|
103
|
+
? "工作者"
|
|
104
|
+
: "Worker"
|
|
105
|
+
: chinese
|
|
106
|
+
? "工作类型"
|
|
107
|
+
: "Work type";
|
|
108
|
+
}
|
|
109
|
+
function defaultWorkTypeLabel(locale) {
|
|
110
|
+
return locale === "zh-CN" ? "默认工作类型" : "Default work type";
|
|
111
|
+
}
|
|
112
|
+
function selectLabel(kind, name, locale) {
|
|
113
|
+
return locale === "zh-CN"
|
|
114
|
+
? `选择 ${name} ${kind === "work type" ? "工作类型" : kind === "worker" ? "工作者" : "资源"}`
|
|
115
|
+
: `Select ${name} ${kind}`;
|
|
116
|
+
}
|
|
117
|
+
function tokenCountLabel(_place, count, locale) {
|
|
118
|
+
return locale === "zh-CN"
|
|
119
|
+
? `${count} 个资源令牌`
|
|
120
|
+
: `${count} resource tokens`;
|
|
121
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Node, NodeProps } from "@xyflow/react";
|
|
2
|
+
import { type FactoryGraphNodeHandle, type FactoryGraphZAxisIncompleteHints } from "./semantic-node-shell.js";
|
|
3
|
+
import { type FactoryGraphWorkItemRef, type FactoryGraphWorkstationRef } from "./semantic-workstation-presentation.js";
|
|
4
|
+
export type { FactoryGraphWorkItemRef, FactoryGraphWorkstationRef, } from "./semantic-workstation-presentation.js";
|
|
5
|
+
export interface FactoryGraphActiveExecution {
|
|
6
|
+
dispatch_id: string;
|
|
7
|
+
started_at: string;
|
|
8
|
+
work_items?: FactoryGraphWorkItemRef[];
|
|
9
|
+
}
|
|
10
|
+
export interface FactoryGraphWorkstationNodeData extends Record<string, unknown> {
|
|
11
|
+
active: boolean;
|
|
12
|
+
activeFlow: boolean;
|
|
13
|
+
executions: FactoryGraphActiveExecution[];
|
|
14
|
+
factoryGraphNodeId?: string;
|
|
15
|
+
handles: FactoryGraphNodeHandle[];
|
|
16
|
+
kind?: "workstation";
|
|
17
|
+
locale?: string;
|
|
18
|
+
muted: boolean;
|
|
19
|
+
now: number;
|
|
20
|
+
progressOutcomeRouteWorkstation?: unknown;
|
|
21
|
+
selectedWorkID: string | null;
|
|
22
|
+
selectedWorkstation: boolean;
|
|
23
|
+
summaryOnly?: boolean;
|
|
24
|
+
workstation: FactoryGraphWorkstationRef;
|
|
25
|
+
zAxisIncompleteHints?: FactoryGraphZAxisIncompleteHints | null;
|
|
26
|
+
onSelectWorkstation?: (nodeId: string) => void;
|
|
27
|
+
onSelectWorkID?: (workID: string, hint?: {
|
|
28
|
+
dispatchID?: string;
|
|
29
|
+
nodeID?: string;
|
|
30
|
+
}) => void;
|
|
31
|
+
}
|
|
32
|
+
export type FactoryGraphWorkstationNode = Node<FactoryGraphWorkstationNodeData, "workstation">;
|
|
33
|
+
/** Original Factory workstation presentation, with host-owned selection callbacks. */
|
|
34
|
+
export declare function FactoryGraphWorkstationNodeView({ data, }: NodeProps<FactoryGraphWorkstationNode>): import("react").JSX.Element;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { GraphNodeButton } from "@you-agent-factory/components/graphs";
|
|
3
|
+
import { GraphSemanticIcon } from "./semantic-icon.js";
|
|
4
|
+
import { FactoryGraphNodeShell, } from "./semantic-node-shell.js";
|
|
5
|
+
import { factoryGraphNodeHoverClassName, factoryGraphNodeSurfaceClassName, } from "./semantic-node-style.js";
|
|
6
|
+
import { FactoryGraphWorkProgressMarker } from "./semantic-place-nodes.js";
|
|
7
|
+
import { factoryGraphActiveItemsLabel as activeItemsLabel, factoryGraphClassNames as classNames, factoryGraphDurationText as durationText, factoryGraphGraphDuration as graphDuration, factoryGraphSelectExhaustionLabel as selectExhaustionLabel, factoryGraphSelectWorkstationLabel as selectWorkstationLabel, factoryGraphWorkItemLabel as workItemLabel, factoryGraphWorkItemLabelClassName as workItemLabelClassName, factoryGraphWorkstationPresentation as workstationPresentation, factoryGraphWorkstationTitleClassName as workstationTitleClassName, } from "./semantic-workstation-presentation.js";
|
|
8
|
+
const VISIBLE_WORK_ITEM_LIMIT = 3;
|
|
9
|
+
/** Original Factory workstation presentation, with host-owned selection callbacks. */
|
|
10
|
+
export function FactoryGraphWorkstationNodeView({ data, }) {
|
|
11
|
+
const presentation = workstationPresentation(data.workstation, data.locale);
|
|
12
|
+
const exhaustion = presentation.semanticKind === "exhaustion";
|
|
13
|
+
const title = data.workstation.workstation_name ||
|
|
14
|
+
data.workstation.transition_id ||
|
|
15
|
+
data.workstation.node_id;
|
|
16
|
+
const entries = data.executions.flatMap((execution) => (execution.work_items ?? []).map((workItem) => ({ execution, workItem })));
|
|
17
|
+
const className = classNames(factoryGraphNodeSurfaceClassName("workstation"), "min-w-0 w-full justify-start overflow-hidden border-2", factoryGraphNodeHoverClassName({ muted: data.muted, selected: data.selectedWorkstation }, "primary"), exhaustion ? "border-dashed border-af-danger-border" : "border-info-border", !exhaustion && presentation.borderClassName, !exhaustion &&
|
|
18
|
+
data.active &&
|
|
19
|
+
!data.selectedWorkstation &&
|
|
20
|
+
"border-af-success-border shadow-af-success-chip", !exhaustion &&
|
|
21
|
+
data.activeFlow &&
|
|
22
|
+
!data.selectedWorkstation &&
|
|
23
|
+
"agent-flow-node--active ring-2 ring-af-success-border", data.selectedWorkstation && "border-primary shadow-af-accent-selected", !exhaustion &&
|
|
24
|
+
data.selectedWorkID !== null &&
|
|
25
|
+
"border-info-border shadow-af-info-selected", data.muted && "opacity-[0.45]");
|
|
26
|
+
return (_jsx(FactoryGraphNodeShell, { className: className, handles: data.handles, nodeType: "workstation", zAxisIncompleteHints: data.zAxisIncompleteHints, children: exhaustion ? (_jsx(Exhaustion, { data: data, presentation: presentation, title: title })) : data.summaryOnly ? (_jsx(Summary, { data: data, presentation: presentation, title: title })) : (_jsx(ActiveContent, { data: data, entries: entries, presentation: presentation, title: title })) }));
|
|
27
|
+
}
|
|
28
|
+
function Summary({ data, presentation, title, }) {
|
|
29
|
+
return (_jsx(GraphNodeButton, { "aria-label": data.onSelectWorkstation
|
|
30
|
+
? selectWorkstationLabel(title, data.locale)
|
|
31
|
+
: undefined, "aria-pressed": data.onSelectWorkstation ? data.selectedWorkstation : undefined, className: "flex min-w-0 w-full items-center justify-between gap-2 overflow-hidden", "data-selected-workstation": data.selectedWorkstation ? "true" : undefined, "data-workstation-kind": presentation.semanticKind, disabled: data.onSelectWorkstation === undefined, onClick: data.onSelectWorkstation
|
|
32
|
+
? (event) => {
|
|
33
|
+
event.stopPropagation();
|
|
34
|
+
data.onSelectWorkstation?.(data.workstation.node_id);
|
|
35
|
+
}
|
|
36
|
+
: undefined, title: title, children: _jsx(Header, { presentation: presentation, title: title }) }));
|
|
37
|
+
}
|
|
38
|
+
function Exhaustion({ data, presentation, title, }) {
|
|
39
|
+
const header = _jsx(Header, { presentation: presentation, title: title, compact: true });
|
|
40
|
+
if (!data.onSelectWorkstation)
|
|
41
|
+
return (_jsx("div", { className: "flex h-full min-w-0 w-full items-center gap-2 overflow-hidden", "data-selected-workstation": data.selectedWorkstation ? "true" : undefined, "data-workstation-kind": presentation.semanticKind, title: title, children: header }));
|
|
42
|
+
return (_jsx(GraphNodeButton, { "aria-label": selectExhaustionLabel(title, data.locale), "aria-pressed": data.selectedWorkstation, className: "flex h-full min-w-0 w-full items-center gap-2 overflow-hidden", "data-selected-workstation": data.selectedWorkstation ? "true" : undefined, "data-workstation-kind": presentation.semanticKind, onClick: (event) => {
|
|
43
|
+
event.stopPropagation();
|
|
44
|
+
data.onSelectWorkstation?.(data.workstation.node_id);
|
|
45
|
+
}, title: title, children: header }));
|
|
46
|
+
}
|
|
47
|
+
function ActiveContent({ data, entries, presentation, title, }) {
|
|
48
|
+
const visible = entries.slice(0, VISIBLE_WORK_ITEM_LIMIT);
|
|
49
|
+
const header = _jsx(Header, { presentation: presentation, title: title });
|
|
50
|
+
return (_jsxs("div", { className: "grid h-full min-w-0 grid-rows-[auto_1fr_auto]", "data-active": data.active ? "true" : undefined, "data-selected-work": data.selectedWorkID !== null ? "true" : undefined, "data-selected-workstation": data.selectedWorkstation ? "true" : undefined, "data-workstation-kind": presentation.semanticKind, children: [data.onSelectWorkstation ? (_jsx(GraphNodeButton, { "aria-label": selectWorkstationLabel(title, data.locale), "aria-pressed": data.selectedWorkstation, className: "flex min-w-0 w-full items-center justify-between gap-2 overflow-hidden", onClick: (event) => {
|
|
51
|
+
event.stopPropagation();
|
|
52
|
+
data.onSelectWorkstation?.(data.workstation.node_id);
|
|
53
|
+
}, title: title, children: header })) : (_jsx("div", { className: "flex min-w-0 w-full items-center justify-between gap-2 overflow-hidden", title: title, children: header })), _jsx("ul", { className: "mt-2 grid min-w-0 list-none content-start gap-1 p-0", children: visible.map(({ execution, workItem }) => (_jsx(WorkItem, { data: data, execution: execution, workItem: workItem }, `${execution.dispatch_id}:${workItem.work_id}`))) }), _jsx(Overflow, { total: entries.length, visible: visible.length, locale: data.locale })] }));
|
|
54
|
+
}
|
|
55
|
+
function WorkItem({ data, execution, workItem, }) {
|
|
56
|
+
const selected = data.selectedWorkID === workItem.work_id;
|
|
57
|
+
const label = workItemLabel(workItem);
|
|
58
|
+
const duration = graphDuration(execution.started_at, data.now, data.locale);
|
|
59
|
+
const durationTitle = durationText(execution.started_at, data.now, data.locale);
|
|
60
|
+
const content = (_jsxs(_Fragment, { children: [_jsx("span", { className: workItemLabelClassName(label), "data-active-work-label": true, children: label }), _jsx("span", { className: "shrink-0 whitespace-nowrap text-right font-mono text-[0.72rem] text-on-surface-subtle", "data-active-work-duration": true, children: duration })] }));
|
|
61
|
+
const className = classNames("grid min-w-0 w-full grid-cols-[minmax(0,1fr)_auto] items-center gap-1 overflow-hidden rounded-lg border border-outline bg-surface px-1.5 py-1 text-[0.74rem]", selected && "border-info-border bg-info-container shadow-af-info-chip");
|
|
62
|
+
return (_jsx("li", { children: data.onSelectWorkID ? (_jsx(GraphNodeButton, { "aria-pressed": selected, className: className, "data-selected": selected ? "true" : undefined, onClick: (event) => {
|
|
63
|
+
event.stopPropagation();
|
|
64
|
+
data.onSelectWorkID?.(workItem.work_id, {
|
|
65
|
+
dispatchID: execution.dispatch_id,
|
|
66
|
+
nodeID: data.workstation.node_id,
|
|
67
|
+
});
|
|
68
|
+
}, title: `${label} - ${durationTitle}`, children: content })) : (_jsx("div", { className: className, "data-selected": selected ? "true" : undefined, title: `${label} - ${durationTitle}`, children: content })) }));
|
|
69
|
+
}
|
|
70
|
+
function Header({ compact = false, presentation, title, }) {
|
|
71
|
+
return (_jsxs(_Fragment, { children: [_jsx("span", { className: compact
|
|
72
|
+
? "flex min-h-4 items-center"
|
|
73
|
+
: "flex min-h-5 shrink-0 items-center", "data-workstation-semantic-icon": true, title: presentation.label, children: _jsx(GraphSemanticIcon, { className: classNames("h-4 w-4", presentation.className), kind: presentation.iconKind, label: presentation.label }) }), _jsx("span", { className: compact
|
|
74
|
+
? "block min-w-0 truncate whitespace-nowrap font-mono text-[0.74rem] font-bold leading-tight text-on-surface"
|
|
75
|
+
: workstationTitleClassName(title), "data-workstation-title": true, children: title })] }));
|
|
76
|
+
}
|
|
77
|
+
function Overflow({ locale, total, visible, }) {
|
|
78
|
+
const remaining = Math.max(0, total - visible);
|
|
79
|
+
if (!remaining)
|
|
80
|
+
return null;
|
|
81
|
+
if (remaining > 10)
|
|
82
|
+
return (_jsx(FactoryGraphWorkProgressMarker, { ariaLabel: activeItemsLabel(total, locale), className: "mt-2 flex min-h-7 w-full rounded-lg px-3 py-1 text-[0.9rem]", count: total, "data-workstation-work-progress": "numeric", kind: "numeric" }));
|
|
83
|
+
return (_jsx(FactoryGraphWorkProgressMarker, { ariaLabel: activeItemsLabel(total, locale), className: "mt-2 flex min-h-7 gap-1 rounded-lg px-2", "data-workstation-work-progress": "dots", dotClassName: "h-1.5 w-1.5", dotCount: remaining, dotDataAttribute: "data-workstation-work-progress-dot", kind: "dots", suffix: _jsxs("span", { className: "ml-1 font-mono text-[0.68rem] font-bold text-success", children: ["+", remaining] }) }));
|
|
84
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { GraphSemanticIconKind } from "./semantic-icon.js";
|
|
2
|
+
export interface FactoryGraphWorkstationRef {
|
|
3
|
+
node_id: string;
|
|
4
|
+
transition_id: string;
|
|
5
|
+
workstation_name: string;
|
|
6
|
+
worker_type?: string;
|
|
7
|
+
workstation_kind?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface FactoryGraphWorkItemRef {
|
|
10
|
+
display_name?: string;
|
|
11
|
+
work_id: string;
|
|
12
|
+
work_type_id?: string;
|
|
13
|
+
}
|
|
14
|
+
export type FactoryGraphWorkstationSemanticKind = "CRON" | "POLLER" | "REPEATER" | "STANDARD" | "exhaustion";
|
|
15
|
+
export interface FactoryGraphWorkstationPresentation {
|
|
16
|
+
borderClassName?: string;
|
|
17
|
+
className: string;
|
|
18
|
+
iconKind: GraphSemanticIconKind;
|
|
19
|
+
label: string;
|
|
20
|
+
semanticKind: FactoryGraphWorkstationSemanticKind;
|
|
21
|
+
}
|
|
22
|
+
export declare function factoryGraphWorkstationPresentation(workstation: FactoryGraphWorkstationRef, locale?: string): FactoryGraphWorkstationPresentation;
|
|
23
|
+
export declare function factoryGraphWorkItemLabel(item: FactoryGraphWorkItemRef): string;
|
|
24
|
+
export declare function factoryGraphGraphDuration(startedAt: string, now: number, locale?: string): string;
|
|
25
|
+
export declare function factoryGraphDurationText(startedAt: string, now: number, locale?: string): string;
|
|
26
|
+
export declare function factoryGraphActiveItemsLabel(count: number, locale?: string): string;
|
|
27
|
+
export declare function factoryGraphSelectWorkstationLabel(title: string, locale?: string): string;
|
|
28
|
+
export declare function factoryGraphSelectExhaustionLabel(title: string, locale?: string): string;
|
|
29
|
+
export declare function factoryGraphWorkstationTitleClassName(label: string): string;
|
|
30
|
+
export declare function factoryGraphWorkItemLabelClassName(label: string): string;
|
|
31
|
+
export declare function factoryGraphClassNames(...values: Array<string | false | null | undefined>): string;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { factoryGraphNodeTitleClassName } from "./semantic-node-style.js";
|
|
2
|
+
export function factoryGraphWorkstationPresentation(workstation, locale) {
|
|
3
|
+
const exhaustion = workstation.workstation_kind === "exhaustion" ||
|
|
4
|
+
(!workstation.workstation_kind && !workstation.worker_type);
|
|
5
|
+
const normalized = workstation.workstation_kind?.trim().toUpperCase();
|
|
6
|
+
const semanticKind = exhaustion
|
|
7
|
+
? "exhaustion"
|
|
8
|
+
: normalized === "CRON"
|
|
9
|
+
? "CRON"
|
|
10
|
+
: normalized === "POLLER"
|
|
11
|
+
? "POLLER"
|
|
12
|
+
: normalized === "REPEATER"
|
|
13
|
+
? "REPEATER"
|
|
14
|
+
: "STANDARD";
|
|
15
|
+
const chinese = locale === "zh-CN";
|
|
16
|
+
const values = {
|
|
17
|
+
CRON: {
|
|
18
|
+
borderClassName: "border-dashed",
|
|
19
|
+
className: "text-success",
|
|
20
|
+
iconKind: "cron",
|
|
21
|
+
semanticKind: "CRON",
|
|
22
|
+
},
|
|
23
|
+
POLLER: {
|
|
24
|
+
borderClassName: "border-dotted",
|
|
25
|
+
className: "text-primary",
|
|
26
|
+
iconKind: "poller",
|
|
27
|
+
semanticKind: "POLLER",
|
|
28
|
+
},
|
|
29
|
+
REPEATER: {
|
|
30
|
+
borderClassName: "border-double",
|
|
31
|
+
className: "text-info",
|
|
32
|
+
iconKind: "repeater",
|
|
33
|
+
semanticKind: "REPEATER",
|
|
34
|
+
},
|
|
35
|
+
STANDARD: {
|
|
36
|
+
className: "text-on-surface-subtle",
|
|
37
|
+
iconKind: "workstation",
|
|
38
|
+
semanticKind: "STANDARD",
|
|
39
|
+
},
|
|
40
|
+
exhaustion: {
|
|
41
|
+
className: "text-error",
|
|
42
|
+
iconKind: "exhaustion",
|
|
43
|
+
semanticKind: "exhaustion",
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
const labels = {
|
|
47
|
+
CRON: chinese ? "Cron 工作站" : "Cron workstation",
|
|
48
|
+
POLLER: chinese ? "轮询器工作站" : "Poller workstation",
|
|
49
|
+
REPEATER: chinese ? "重复器工作站" : "Repeater workstation",
|
|
50
|
+
STANDARD: chinese ? "标准工作站" : "Standard workstation",
|
|
51
|
+
exhaustion: chinese ? "耗尽规则" : "Exhaustion rule",
|
|
52
|
+
};
|
|
53
|
+
return { ...values[semanticKind], label: labels[semanticKind] };
|
|
54
|
+
}
|
|
55
|
+
export function factoryGraphWorkItemLabel(item) {
|
|
56
|
+
return item.display_name?.trim() || item.work_id?.trim() || "Unknown work";
|
|
57
|
+
}
|
|
58
|
+
export function factoryGraphGraphDuration(startedAt, now, locale) {
|
|
59
|
+
const millis = durationMillis(startedAt, now);
|
|
60
|
+
if (millis === undefined)
|
|
61
|
+
return "Unavailable";
|
|
62
|
+
const [value, suffix] = graphDurationParts(millis, locale);
|
|
63
|
+
return `${value}${suffix}`;
|
|
64
|
+
}
|
|
65
|
+
export function factoryGraphDurationText(startedAt, now, locale) {
|
|
66
|
+
const millis = durationMillis(startedAt, now);
|
|
67
|
+
if (millis === undefined)
|
|
68
|
+
return "Unavailable";
|
|
69
|
+
const seconds = Math.floor(millis / 1000);
|
|
70
|
+
const minutes = Math.floor(seconds / 60);
|
|
71
|
+
const hours = Math.floor(minutes / 60);
|
|
72
|
+
const [hour, minute, second] = locale === "zh-CN" ? ["小时", "分", "秒"] : ["h", "m", "s"];
|
|
73
|
+
if (hours > 0)
|
|
74
|
+
return `${hours}${hour} ${minutes % 60}${minute}`;
|
|
75
|
+
if (minutes > 0)
|
|
76
|
+
return `${minutes}${minute} ${seconds % 60}${second}`;
|
|
77
|
+
return `${seconds}${second}`;
|
|
78
|
+
}
|
|
79
|
+
export function factoryGraphActiveItemsLabel(count, locale) {
|
|
80
|
+
return locale === "zh-CN"
|
|
81
|
+
? `${count} 个活动项`
|
|
82
|
+
: `${count} active ${count === 1 ? "item" : "items"}`;
|
|
83
|
+
}
|
|
84
|
+
export function factoryGraphSelectWorkstationLabel(title, locale) {
|
|
85
|
+
return locale === "zh-CN"
|
|
86
|
+
? `选择 ${title} 工作站`
|
|
87
|
+
: `Select ${title} workstation`;
|
|
88
|
+
}
|
|
89
|
+
export function factoryGraphSelectExhaustionLabel(title, locale) {
|
|
90
|
+
return locale === "zh-CN"
|
|
91
|
+
? `选择 ${title} 枯竭规则`
|
|
92
|
+
: `Select ${title} exhaustion rule`;
|
|
93
|
+
}
|
|
94
|
+
export function factoryGraphWorkstationTitleClassName(label) {
|
|
95
|
+
return factoryGraphNodeTitleClassName(factoryGraphClassNames("basis-0 flex-1", label.length > 34
|
|
96
|
+
? "text-[0.78rem]"
|
|
97
|
+
: label.length > 20
|
|
98
|
+
? "text-[0.88rem]"
|
|
99
|
+
: "text-[1rem]"));
|
|
100
|
+
}
|
|
101
|
+
export function factoryGraphWorkItemLabelClassName(label) {
|
|
102
|
+
return factoryGraphClassNames("block min-w-0 basis-0 flex-1 truncate whitespace-nowrap leading-tight", label.length > 58
|
|
103
|
+
? "text-[0.64rem]"
|
|
104
|
+
: label.length > 38
|
|
105
|
+
? "text-[0.68rem]"
|
|
106
|
+
: "text-[0.74rem]");
|
|
107
|
+
}
|
|
108
|
+
export function factoryGraphClassNames(...values) {
|
|
109
|
+
return values.filter(Boolean).join(" ");
|
|
110
|
+
}
|
|
111
|
+
function durationMillis(startedAt, now) {
|
|
112
|
+
const started = Date.parse(startedAt);
|
|
113
|
+
return Number.isNaN(started) ? undefined : Math.max(0, now - started);
|
|
114
|
+
}
|
|
115
|
+
function graphDurationParts(millis, locale) {
|
|
116
|
+
const units = [
|
|
117
|
+
[24 * 60 * 60 * 1000, locale === "zh-CN" ? "天" : "d"],
|
|
118
|
+
[60 * 60 * 1000, locale === "zh-CN" ? "时" : "h"],
|
|
119
|
+
[60 * 1000, locale === "zh-CN" ? "分" : "m"],
|
|
120
|
+
[1000, locale === "zh-CN" ? "秒" : "s"],
|
|
121
|
+
];
|
|
122
|
+
const unit = units.find(([size]) => millis >= size) ?? units[3];
|
|
123
|
+
return [
|
|
124
|
+
new Intl.NumberFormat(locale).format(Math.floor(millis / unit[0])),
|
|
125
|
+
unit[1],
|
|
126
|
+
];
|
|
127
|
+
}
|