@procaaso/alphinity-ui-components 1.9.0 → 1.11.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/dist/index.cjs +1161 -361
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +280 -9
- package/dist/index.d.ts +280 -9
- package/dist/index.js +1054 -265
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
Button: () => Button,
|
|
34
|
+
COLOR_PRESETS: () => COLOR_PRESETS,
|
|
34
35
|
CardHeader: () => CardHeader,
|
|
35
36
|
CardUnit: () => CardUnit,
|
|
36
37
|
CardValue: () => CardValue,
|
|
@@ -44,6 +45,7 @@ __export(index_exports, {
|
|
|
44
45
|
DisplayModeToggle: () => DisplayModeToggle,
|
|
45
46
|
EquipmentIndicator: () => EquipmentIndicator,
|
|
46
47
|
EquipmentIndicatorWithSparkline: () => EquipmentIndicatorWithSparkline,
|
|
48
|
+
FORCED_MARK_COLOR: () => FORCED_MARK_COLOR,
|
|
47
49
|
FixedSVGContainer: () => FixedSVGContainer,
|
|
48
50
|
FooterPanel: () => FooterPanel,
|
|
49
51
|
FullscreenContainer: () => FullscreenContainer,
|
|
@@ -59,6 +61,7 @@ __export(index_exports, {
|
|
|
59
61
|
PanelTabs: () => PanelTabs,
|
|
60
62
|
RightPanel: () => RightPanel,
|
|
61
63
|
RightToggleButton: () => RightToggleButton,
|
|
64
|
+
STATUS_LED_APPEARANCE: () => STATUS_LED_APPEARANCE,
|
|
62
65
|
SVGArea: () => SVGArea,
|
|
63
66
|
SVGLockedOverlay: () => SVGLockedOverlay,
|
|
64
67
|
ScrollableSVGWrapper: () => ScrollableSVGWrapper,
|
|
@@ -69,6 +72,8 @@ __export(index_exports, {
|
|
|
69
72
|
ThemeProvider: () => ThemeProvider,
|
|
70
73
|
ThemeToggle: () => ThemeToggle,
|
|
71
74
|
TrendLine: () => TrendLine,
|
|
75
|
+
UNKNOWN_MARK_COLOR: () => UNKNOWN_MARK_COLOR,
|
|
76
|
+
UNKNOWN_MARK_COLOR_DARK: () => UNKNOWN_MARK_COLOR_DARK,
|
|
72
77
|
ValueEntry: () => ValueEntry,
|
|
73
78
|
ZoomButton: () => ZoomButton,
|
|
74
79
|
ZoomControls: () => ZoomControls,
|
|
@@ -78,6 +83,8 @@ __export(index_exports, {
|
|
|
78
83
|
exampleDiagram: () => exampleDiagram,
|
|
79
84
|
exportDiagram: () => exportDiagram,
|
|
80
85
|
generateRoutePoints: () => generateRoutePoints,
|
|
86
|
+
getAppearanceDefaults: () => getAppearanceDefaults,
|
|
87
|
+
getAppearanceSchema: () => getAppearanceSchema,
|
|
81
88
|
getAvailableSymbols: () => getAvailableSymbols,
|
|
82
89
|
getPortWorldPosition: () => getPortWorldPosition,
|
|
83
90
|
getSymbolDefinition: () => getSymbolDefinition,
|
|
@@ -85,9 +92,12 @@ __export(index_exports, {
|
|
|
85
92
|
mockSymbolLibrary: () => mockSymbolLibrary,
|
|
86
93
|
nodeHasPort: () => nodeHasPort,
|
|
87
94
|
overlayStyles: () => overlayStyles,
|
|
95
|
+
readAppearanceValue: () => readAppearanceValue,
|
|
88
96
|
registerSymbol: () => registerSymbol,
|
|
89
97
|
registerSymbols: () => registerSymbols,
|
|
98
|
+
resolvePresetColor: () => resolvePresetColor,
|
|
90
99
|
resolveStatusColor: () => resolveStatusColor,
|
|
100
|
+
useBooleanIndicators: () => useBooleanIndicators,
|
|
91
101
|
useDeviceConfigs: () => useDeviceConfigs,
|
|
92
102
|
useDeviceControls: () => useDeviceControls,
|
|
93
103
|
useDrag: () => useDrag,
|
|
@@ -98,7 +108,8 @@ __export(index_exports, {
|
|
|
98
108
|
useTelemetryStatus: () => useTelemetryStatus,
|
|
99
109
|
useTheme: () => useTheme,
|
|
100
110
|
useViewBox: () => useViewBox,
|
|
101
|
-
validateDiagram: () => validateDiagram
|
|
111
|
+
validateDiagram: () => validateDiagram,
|
|
112
|
+
writeAppearanceValue: () => writeAppearanceValue
|
|
102
113
|
});
|
|
103
114
|
module.exports = __toCommonJS(index_exports);
|
|
104
115
|
|
|
@@ -278,6 +289,8 @@ var ValueEntry = ({
|
|
|
278
289
|
inputType = "numeric",
|
|
279
290
|
label,
|
|
280
291
|
readOnly = false,
|
|
292
|
+
forced = false,
|
|
293
|
+
realValue,
|
|
281
294
|
className = "",
|
|
282
295
|
disabled,
|
|
283
296
|
...props
|
|
@@ -328,9 +341,14 @@ var ValueEntry = ({
|
|
|
328
341
|
const unitClass = unit ? "ui-value-entry--with-unit" : "";
|
|
329
342
|
const currentStatus = disabled || readOnly ? "disabled" : status;
|
|
330
343
|
const statusVariantClass = currentStatus ? `ui-value-entry--${currentStatus}` : "";
|
|
344
|
+
const forcedClass = forced ? "ui-value-entry--forced" : "";
|
|
345
|
+
const hasRealValue = forced && realValue !== void 0;
|
|
331
346
|
const displayText = isEditing ? displayValue : inputType === "numeric" ? Number(value).toFixed(precision) : String(value);
|
|
332
347
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "ui-value-entry-container", children: [
|
|
333
|
-
label && /* @__PURE__ */ (0, import_jsx_runtime3.
|
|
348
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "ui-value-entry-label", children: [
|
|
349
|
+
label,
|
|
350
|
+
forced && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "ui-value-entry-forced-badge", "aria-label": "Forced", children: "F" })
|
|
351
|
+
] }),
|
|
334
352
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "ui-value-entry-wrapper", children: [
|
|
335
353
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
336
354
|
"input",
|
|
@@ -343,19 +361,71 @@ var ValueEntry = ({
|
|
|
343
361
|
onKeyDown: handleKeyDown,
|
|
344
362
|
disabled,
|
|
345
363
|
readOnly,
|
|
346
|
-
className: `${baseClass} ${statusVariantClass} ${unitClass} ${className}`.trim(),
|
|
364
|
+
className: `${baseClass} ${statusVariantClass} ${forcedClass} ${unitClass} ${className}`.trim(),
|
|
347
365
|
...props
|
|
348
366
|
}
|
|
349
367
|
),
|
|
350
368
|
unit && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "ui-value-entry-unit", children: unit }),
|
|
351
369
|
status === "alarm" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "ui-value-entry-badge ui-value-entry-badge--alarm" }),
|
|
352
|
-
status === "warning" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "ui-value-entry-badge ui-value-entry-badge--warning" })
|
|
370
|
+
status === "warning" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "ui-value-entry-badge ui-value-entry-badge--warning" }),
|
|
371
|
+
!label && forced && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "ui-value-entry-forced-badge", "aria-label": "Forced", children: "F" })
|
|
372
|
+
] }),
|
|
373
|
+
hasRealValue && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "ui-value-entry-real-value", children: [
|
|
374
|
+
"REAL ",
|
|
375
|
+
String(realValue),
|
|
376
|
+
unit ? ` ${unit}` : ""
|
|
353
377
|
] })
|
|
354
378
|
] });
|
|
355
379
|
};
|
|
356
380
|
|
|
357
381
|
// src/components/ValueEntry/LegacyValueEntry.tsx
|
|
358
382
|
var import_react3 = require("react");
|
|
383
|
+
|
|
384
|
+
// src/theme/statusColors.ts
|
|
385
|
+
var DEFAULT_STATUS_COLORS = {
|
|
386
|
+
normal: { fill: "#888888", stroke: "#6b6b6b", bg: "#888888", text: "#ffffff", border: "#6b6b6b" },
|
|
387
|
+
warning: { fill: "#f59e0b", stroke: "#d97706", bg: "#FFD700", text: "#000000", border: "#d97706" },
|
|
388
|
+
alarm: { fill: "#ef4444", stroke: "#dc2626", bg: "#FF0000", text: "#ffffff", border: "#dc2626" },
|
|
389
|
+
fault: { fill: "#dc2626", stroke: "#b91c1c", bg: "#FF0000", text: "#ffffff", border: "#b91c1c" },
|
|
390
|
+
off: { fill: "#edeeef", stroke: "#000000", bg: "#666666", text: "#ffffff", border: "#4b5563" },
|
|
391
|
+
starting: { fill: "#90EE90", stroke: "#22c55e", bg: "#90EE90", text: "#000000", border: "#22c55e" },
|
|
392
|
+
stopping: { fill: "#FFD700", stroke: "#d97706", bg: "#FFD700", text: "#000000", border: "#d97706" }
|
|
393
|
+
};
|
|
394
|
+
var FORCED_MARK_COLOR = {
|
|
395
|
+
fill: "#ede9fe",
|
|
396
|
+
stroke: "#5b21b6",
|
|
397
|
+
bg: "#ede9fe",
|
|
398
|
+
text: "#5b21b6",
|
|
399
|
+
border: "#7c3aed"
|
|
400
|
+
};
|
|
401
|
+
var UNKNOWN_MARK_COLOR = {
|
|
402
|
+
fill: "#ebebf5",
|
|
403
|
+
stroke: "#8f8fc2",
|
|
404
|
+
bg: "#ebebf5",
|
|
405
|
+
text: "#4f4f8a",
|
|
406
|
+
border: "#8f8fc2"
|
|
407
|
+
};
|
|
408
|
+
var UNKNOWN_MARK_COLOR_DARK = {
|
|
409
|
+
fill: "#23263a",
|
|
410
|
+
stroke: "#6f74a3",
|
|
411
|
+
bg: "#23263a",
|
|
412
|
+
text: "#b9bbdb",
|
|
413
|
+
border: "#6f74a3"
|
|
414
|
+
};
|
|
415
|
+
var STATUS_ALIASES = {
|
|
416
|
+
running: "normal",
|
|
417
|
+
stopped: "off"
|
|
418
|
+
};
|
|
419
|
+
function resolveStatusColor(status, customMap) {
|
|
420
|
+
const raw = (status || "off").toLowerCase();
|
|
421
|
+
const key = STATUS_ALIASES[raw] ?? raw;
|
|
422
|
+
const defaults = DEFAULT_STATUS_COLORS[key] ?? DEFAULT_STATUS_COLORS.off;
|
|
423
|
+
const overrides = customMap?.[key];
|
|
424
|
+
if (!overrides) return defaults;
|
|
425
|
+
return { ...defaults, ...overrides };
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// src/components/ValueEntry/LegacyValueEntry.tsx
|
|
359
429
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
360
430
|
var LegacyValueEntry = ({
|
|
361
431
|
value,
|
|
@@ -368,6 +438,8 @@ var LegacyValueEntry = ({
|
|
|
368
438
|
inputType = "numeric",
|
|
369
439
|
label,
|
|
370
440
|
readOnly = false,
|
|
441
|
+
forced = false,
|
|
442
|
+
realValue,
|
|
371
443
|
className = "",
|
|
372
444
|
disabled,
|
|
373
445
|
...props
|
|
@@ -448,6 +520,27 @@ var LegacyValueEntry = ({
|
|
|
448
520
|
}
|
|
449
521
|
};
|
|
450
522
|
const statusStyles = getStatusStyles();
|
|
523
|
+
const forcedBadgeStyle = {
|
|
524
|
+
display: "inline-flex",
|
|
525
|
+
alignItems: "center",
|
|
526
|
+
justifyContent: "center",
|
|
527
|
+
width: "1.1rem",
|
|
528
|
+
height: "1.1rem",
|
|
529
|
+
fontSize: "0.7rem",
|
|
530
|
+
fontWeight: 700,
|
|
531
|
+
color: FORCED_MARK_COLOR.text,
|
|
532
|
+
backgroundColor: FORCED_MARK_COLOR.bg,
|
|
533
|
+
border: `1px solid ${FORCED_MARK_COLOR.border}`,
|
|
534
|
+
borderRadius: "50%",
|
|
535
|
+
marginLeft: "8px",
|
|
536
|
+
lineHeight: 1
|
|
537
|
+
};
|
|
538
|
+
const realValueStyle = {
|
|
539
|
+
fontSize: "0.75rem",
|
|
540
|
+
fontWeight: 500,
|
|
541
|
+
color: "#94a3b8",
|
|
542
|
+
letterSpacing: "0.02em"
|
|
543
|
+
};
|
|
451
544
|
const inputStyle = {
|
|
452
545
|
width: "12rem",
|
|
453
546
|
height: "4rem",
|
|
@@ -496,17 +589,22 @@ var LegacyValueEntry = ({
|
|
|
496
589
|
gap: "0.75rem"
|
|
497
590
|
},
|
|
498
591
|
children: [
|
|
499
|
-
label && /* @__PURE__ */ (0, import_jsx_runtime4.
|
|
592
|
+
(label || forced) && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
500
593
|
"label",
|
|
501
594
|
{
|
|
502
595
|
style: {
|
|
596
|
+
display: "flex",
|
|
597
|
+
alignItems: "center",
|
|
503
598
|
fontSize: "0.875rem",
|
|
504
599
|
fontWeight: "600",
|
|
505
600
|
color: "#cbd5e1",
|
|
506
601
|
textTransform: "uppercase",
|
|
507
602
|
letterSpacing: "0.05em"
|
|
508
603
|
},
|
|
509
|
-
children:
|
|
604
|
+
children: [
|
|
605
|
+
label,
|
|
606
|
+
forced && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: forcedBadgeStyle, "aria-label": "Forced", children: "F" })
|
|
607
|
+
]
|
|
510
608
|
}
|
|
511
609
|
),
|
|
512
610
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { position: "relative", display: "inline-flex", alignItems: "center" }, children: [
|
|
@@ -563,6 +661,11 @@ var LegacyValueEntry = ({
|
|
|
563
661
|
}
|
|
564
662
|
}
|
|
565
663
|
)
|
|
664
|
+
] }),
|
|
665
|
+
forced && realValue !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: realValueStyle, children: [
|
|
666
|
+
"REAL ",
|
|
667
|
+
String(realValue),
|
|
668
|
+
unit ? ` ${unit}` : ""
|
|
566
669
|
] })
|
|
567
670
|
]
|
|
568
671
|
}
|
|
@@ -578,6 +681,9 @@ var ControlPanel = ({
|
|
|
578
681
|
onModeChange,
|
|
579
682
|
setpointValue,
|
|
580
683
|
onSetpointChange,
|
|
684
|
+
currentSetpointValue,
|
|
685
|
+
currentSetpointForced = false,
|
|
686
|
+
currentSetpointRealValue,
|
|
581
687
|
secondSetpointValue,
|
|
582
688
|
onSecondSetpointChange,
|
|
583
689
|
modeConfigs = {},
|
|
@@ -674,6 +780,21 @@ var ControlPanel = ({
|
|
|
674
780
|
disabled: status === "disabled"
|
|
675
781
|
}
|
|
676
782
|
) }),
|
|
783
|
+
currentSetpointValue !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
784
|
+
LegacyValueEntry,
|
|
785
|
+
{
|
|
786
|
+
value: currentSetpointValue,
|
|
787
|
+
onChange: () => {
|
|
788
|
+
},
|
|
789
|
+
label: `${currentLabel} (Current)`,
|
|
790
|
+
unit: currentUnit,
|
|
791
|
+
precision: currentPrecision,
|
|
792
|
+
status,
|
|
793
|
+
readOnly: true,
|
|
794
|
+
forced: currentSetpointForced,
|
|
795
|
+
realValue: currentSetpointRealValue
|
|
796
|
+
}
|
|
797
|
+
) }),
|
|
677
798
|
hasSecondSetpoint && onSecondSetpointChange && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
678
799
|
LegacyValueEntry,
|
|
679
800
|
{
|
|
@@ -764,9 +885,15 @@ var StatusIndicator = ({
|
|
|
764
885
|
labelPosition = "right",
|
|
765
886
|
shape = "circle",
|
|
766
887
|
led = true,
|
|
888
|
+
visible = true,
|
|
889
|
+
forced = false,
|
|
890
|
+
realValue,
|
|
767
891
|
className = "",
|
|
768
892
|
...props
|
|
769
893
|
}) => {
|
|
894
|
+
if (!visible) {
|
|
895
|
+
return null;
|
|
896
|
+
}
|
|
770
897
|
const baseClass = "ui-status-indicator";
|
|
771
898
|
const statusClass = status ? `ui-status-indicator--${status}` : "";
|
|
772
899
|
const sizeClass = size ? `ui-status-indicator--${size}` : "";
|
|
@@ -787,28 +914,43 @@ var StatusIndicator = ({
|
|
|
787
914
|
return "ui-status-indicator-container ui-status-indicator-label-right";
|
|
788
915
|
}
|
|
789
916
|
};
|
|
917
|
+
const forcedClass = forced ? "ui-status-indicator--forced" : "";
|
|
918
|
+
const hasRealValue = forced && realValue !== void 0;
|
|
790
919
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: getContainerLayout(), children: [
|
|
791
920
|
label && (labelPosition === "left" || labelPosition === "top") && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ui-status-indicator-label", children: label }),
|
|
792
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.
|
|
793
|
-
"
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
"
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
${
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
921
|
+
hasRealValue && (labelPosition === "left" || labelPosition === "top") && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "ui-status-indicator-real-value", children: [
|
|
922
|
+
"REAL ",
|
|
923
|
+
realValue
|
|
924
|
+
] }),
|
|
925
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { style: { position: "relative", display: "inline-flex" }, children: [
|
|
926
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
927
|
+
"span",
|
|
928
|
+
{
|
|
929
|
+
role: "status",
|
|
930
|
+
"aria-label": label || `Status: ${status}`,
|
|
931
|
+
"aria-description": getStatusDescription(status),
|
|
932
|
+
"data-status": status,
|
|
933
|
+
"data-forced": forced,
|
|
934
|
+
className: `
|
|
935
|
+
${baseClass}
|
|
936
|
+
${statusClass}
|
|
937
|
+
${sizeClass}
|
|
938
|
+
${shapeClass}
|
|
939
|
+
${animationClass}
|
|
940
|
+
${ledClass}
|
|
941
|
+
${forcedClass}
|
|
942
|
+
${className}
|
|
943
|
+
`.replace(/\s+/g, " ").trim(),
|
|
944
|
+
...props
|
|
945
|
+
}
|
|
946
|
+
),
|
|
947
|
+
forced && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ui-status-indicator-forced-badge", "aria-label": "Forced", children: "F" })
|
|
948
|
+
] }),
|
|
949
|
+
label && (labelPosition === "right" || labelPosition === "bottom") && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ui-status-indicator-label", children: label }),
|
|
950
|
+
hasRealValue && (labelPosition === "right" || labelPosition === "bottom") && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "ui-status-indicator-real-value", children: [
|
|
951
|
+
"REAL ",
|
|
952
|
+
realValue
|
|
953
|
+
] })
|
|
812
954
|
] });
|
|
813
955
|
};
|
|
814
956
|
|
|
@@ -936,6 +1078,9 @@ var NodeControlsPanel = ({
|
|
|
936
1078
|
onModeChange: config.onModeChange,
|
|
937
1079
|
setpointValue: config.setpoint,
|
|
938
1080
|
onSetpointChange: config.onSetpointChange,
|
|
1081
|
+
currentSetpointValue: config.currentSetpoint,
|
|
1082
|
+
currentSetpointForced: config.currentSetpointForced,
|
|
1083
|
+
currentSetpointRealValue: config.currentSetpointRealValue,
|
|
939
1084
|
secondSetpointValue: config.secondSetpoint,
|
|
940
1085
|
onSecondSetpointChange: config.onSecondSetpointChange,
|
|
941
1086
|
modeConfigs: config.modeConfigs,
|
|
@@ -1000,31 +1145,6 @@ var NodeControlsPanel = ({
|
|
|
1000
1145
|
|
|
1001
1146
|
// src/components/DeviceControlPanel/DeviceControlPanel.tsx
|
|
1002
1147
|
var import_react5 = __toESM(require("react"), 1);
|
|
1003
|
-
|
|
1004
|
-
// src/theme/statusColors.ts
|
|
1005
|
-
var DEFAULT_STATUS_COLORS = {
|
|
1006
|
-
normal: { fill: "#888888", stroke: "#6b6b6b", bg: "#888888", text: "#ffffff", border: "#6b6b6b" },
|
|
1007
|
-
warning: { fill: "#f59e0b", stroke: "#d97706", bg: "#FFD700", text: "#000000", border: "#d97706" },
|
|
1008
|
-
alarm: { fill: "#ef4444", stroke: "#dc2626", bg: "#FF0000", text: "#ffffff", border: "#dc2626" },
|
|
1009
|
-
fault: { fill: "#dc2626", stroke: "#b91c1c", bg: "#FF0000", text: "#ffffff", border: "#b91c1c" },
|
|
1010
|
-
off: { fill: "#edeeef", stroke: "#000000", bg: "#666666", text: "#ffffff", border: "#4b5563" },
|
|
1011
|
-
starting: { fill: "#90EE90", stroke: "#22c55e", bg: "#90EE90", text: "#000000", border: "#22c55e" },
|
|
1012
|
-
stopping: { fill: "#FFD700", stroke: "#d97706", bg: "#FFD700", text: "#000000", border: "#d97706" }
|
|
1013
|
-
};
|
|
1014
|
-
var STATUS_ALIASES = {
|
|
1015
|
-
running: "normal",
|
|
1016
|
-
stopped: "off"
|
|
1017
|
-
};
|
|
1018
|
-
function resolveStatusColor(status, customMap) {
|
|
1019
|
-
const raw = (status || "off").toLowerCase();
|
|
1020
|
-
const key = STATUS_ALIASES[raw] ?? raw;
|
|
1021
|
-
const defaults = DEFAULT_STATUS_COLORS[key] ?? DEFAULT_STATUS_COLORS.off;
|
|
1022
|
-
const overrides = customMap?.[key];
|
|
1023
|
-
if (!overrides) return defaults;
|
|
1024
|
-
return { ...defaults, ...overrides };
|
|
1025
|
-
}
|
|
1026
|
-
|
|
1027
|
-
// src/components/DeviceControlPanel/DeviceControlPanel.tsx
|
|
1028
1148
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1029
1149
|
function DeviceControlPanelImpl({
|
|
1030
1150
|
binding,
|
|
@@ -1672,10 +1792,13 @@ function DeviceControlPanelImpl({
|
|
|
1672
1792
|
marginBottom: spacing.gap
|
|
1673
1793
|
},
|
|
1674
1794
|
children: [
|
|
1675
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.
|
|
1795
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1676
1796
|
"span",
|
|
1677
1797
|
{
|
|
1678
1798
|
style: {
|
|
1799
|
+
display: "flex",
|
|
1800
|
+
alignItems: "center",
|
|
1801
|
+
gap: "6px",
|
|
1679
1802
|
fontSize: `${fontSize.label}px`,
|
|
1680
1803
|
fontWeight: 600,
|
|
1681
1804
|
textTransform: "uppercase",
|
|
@@ -1683,7 +1806,29 @@ function DeviceControlPanelImpl({
|
|
|
1683
1806
|
fontFamily: "Arial, sans-serif",
|
|
1684
1807
|
color: mutedTextColor
|
|
1685
1808
|
},
|
|
1686
|
-
children:
|
|
1809
|
+
children: [
|
|
1810
|
+
param.label,
|
|
1811
|
+
param.forced?.active && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1812
|
+
"span",
|
|
1813
|
+
{
|
|
1814
|
+
"aria-label": "Forced",
|
|
1815
|
+
style: {
|
|
1816
|
+
display: "inline-flex",
|
|
1817
|
+
alignItems: "center",
|
|
1818
|
+
justifyContent: "center",
|
|
1819
|
+
width: "16px",
|
|
1820
|
+
height: "16px",
|
|
1821
|
+
fontSize: "10px",
|
|
1822
|
+
fontWeight: 700,
|
|
1823
|
+
color: FORCED_MARK_COLOR.text,
|
|
1824
|
+
backgroundColor: FORCED_MARK_COLOR.bg,
|
|
1825
|
+
border: `1px solid ${FORCED_MARK_COLOR.border}`,
|
|
1826
|
+
borderRadius: "50%"
|
|
1827
|
+
},
|
|
1828
|
+
children: "F"
|
|
1829
|
+
}
|
|
1830
|
+
)
|
|
1831
|
+
]
|
|
1687
1832
|
}
|
|
1688
1833
|
),
|
|
1689
1834
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
@@ -1705,6 +1850,27 @@ function DeviceControlPanelImpl({
|
|
|
1705
1850
|
]
|
|
1706
1851
|
}
|
|
1707
1852
|
),
|
|
1853
|
+
param.forced?.active && param.forced.realValue !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1854
|
+
"div",
|
|
1855
|
+
{
|
|
1856
|
+
style: {
|
|
1857
|
+
display: "flex",
|
|
1858
|
+
justifyContent: "flex-end",
|
|
1859
|
+
marginTop: "-4px",
|
|
1860
|
+
marginBottom: spacing.gap,
|
|
1861
|
+
fontSize: "10px",
|
|
1862
|
+
fontWeight: 500,
|
|
1863
|
+
fontFamily: "Arial, sans-serif",
|
|
1864
|
+
color: mutedTextColor
|
|
1865
|
+
},
|
|
1866
|
+
children: [
|
|
1867
|
+
"REAL",
|
|
1868
|
+
" ",
|
|
1869
|
+
typeof param.forced.realValue === "boolean" ? param.forced.realValue ? "ON" : "OFF" : String(param.forced.realValue),
|
|
1870
|
+
param.unit ? ` ${param.unit}` : ""
|
|
1871
|
+
]
|
|
1872
|
+
}
|
|
1873
|
+
),
|
|
1708
1874
|
param.type === "boolean" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1709
1875
|
"button",
|
|
1710
1876
|
{
|
|
@@ -2803,19 +2969,38 @@ var CardUnit = (0, import_styled2.default)("div")({
|
|
|
2803
2969
|
|
|
2804
2970
|
// src/components/layout/FullscreenWorkspace/FullscreenWorkspace.visuals.tsx
|
|
2805
2971
|
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
2972
|
+
var forcedTagStyle = {
|
|
2973
|
+
position: "absolute",
|
|
2974
|
+
top: "-6px",
|
|
2975
|
+
right: "-6px",
|
|
2976
|
+
width: "14px",
|
|
2977
|
+
height: "14px",
|
|
2978
|
+
display: "flex",
|
|
2979
|
+
alignItems: "center",
|
|
2980
|
+
justifyContent: "center",
|
|
2981
|
+
fontSize: "9px",
|
|
2982
|
+
fontWeight: 700,
|
|
2983
|
+
color: FORCED_MARK_COLOR.text,
|
|
2984
|
+
backgroundColor: FORCED_MARK_COLOR.bg,
|
|
2985
|
+
border: `1px solid ${FORCED_MARK_COLOR.border}`,
|
|
2986
|
+
borderRadius: "50%",
|
|
2987
|
+
pointerEvents: "none"
|
|
2988
|
+
};
|
|
2806
2989
|
var TrendLine = ({
|
|
2807
2990
|
values,
|
|
2808
2991
|
width = 60,
|
|
2809
2992
|
height = 20,
|
|
2810
2993
|
color = "#4fc3f7",
|
|
2811
2994
|
strokeWidth = 1.5,
|
|
2812
|
-
backgroundColor = "rgba(255, 255, 255, 0.1)"
|
|
2995
|
+
backgroundColor = "rgba(255, 255, 255, 0.1)",
|
|
2996
|
+
forced = false
|
|
2813
2997
|
}) => {
|
|
2814
2998
|
if (!values || values.length < 2) {
|
|
2815
|
-
return /* @__PURE__ */ (0, import_jsx_runtime12.
|
|
2999
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
2816
3000
|
"div",
|
|
2817
3001
|
{
|
|
2818
3002
|
style: {
|
|
3003
|
+
position: "relative",
|
|
2819
3004
|
width,
|
|
2820
3005
|
height,
|
|
2821
3006
|
backgroundColor,
|
|
@@ -2824,7 +3009,10 @@ var TrendLine = ({
|
|
|
2824
3009
|
alignItems: "center",
|
|
2825
3010
|
justifyContent: "center"
|
|
2826
3011
|
},
|
|
2827
|
-
children:
|
|
3012
|
+
children: [
|
|
3013
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: { fontSize: "8px", color: "#ccc" }, children: "No data" }),
|
|
3014
|
+
forced && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: forcedTagStyle, "aria-label": "Forced", children: "F" })
|
|
3015
|
+
]
|
|
2828
3016
|
}
|
|
2829
3017
|
);
|
|
2830
3018
|
}
|
|
@@ -2836,7 +3024,7 @@ var TrendLine = ({
|
|
|
2836
3024
|
const x = 4 + i / (values.length - 1) * (width - 8);
|
|
2837
3025
|
return i === 0 ? `M ${x} ${y}` : `L ${x} ${y}`;
|
|
2838
3026
|
}).join(" ");
|
|
2839
|
-
return /* @__PURE__ */ (0, import_jsx_runtime12.
|
|
3027
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
2840
3028
|
"div",
|
|
2841
3029
|
{
|
|
2842
3030
|
style: {
|
|
@@ -2845,30 +3033,41 @@ var TrendLine = ({
|
|
|
2845
3033
|
backgroundColor,
|
|
2846
3034
|
borderRadius: "2px",
|
|
2847
3035
|
position: "relative",
|
|
2848
|
-
overflow: "
|
|
3036
|
+
overflow: "visible"
|
|
2849
3037
|
},
|
|
2850
|
-
children:
|
|
2851
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.
|
|
2852
|
-
"
|
|
3038
|
+
children: [
|
|
3039
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
3040
|
+
"svg",
|
|
2853
3041
|
{
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
3042
|
+
width,
|
|
3043
|
+
height,
|
|
3044
|
+
style: { position: "absolute", top: 0, left: 0, overflow: "hidden", borderRadius: "2px" },
|
|
3045
|
+
children: [
|
|
3046
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
3047
|
+
"path",
|
|
3048
|
+
{
|
|
3049
|
+
d: pathData,
|
|
3050
|
+
fill: "none",
|
|
3051
|
+
stroke: color,
|
|
3052
|
+
strokeWidth,
|
|
3053
|
+
strokeLinecap: "round",
|
|
3054
|
+
strokeLinejoin: "round"
|
|
3055
|
+
}
|
|
3056
|
+
),
|
|
3057
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
3058
|
+
"circle",
|
|
3059
|
+
{
|
|
3060
|
+
cx: 4 + (width - 8),
|
|
3061
|
+
cy: normalizedValues[normalizedValues.length - 1],
|
|
3062
|
+
r: 1.5,
|
|
3063
|
+
fill: color
|
|
3064
|
+
}
|
|
3065
|
+
)
|
|
3066
|
+
]
|
|
2860
3067
|
}
|
|
2861
3068
|
),
|
|
2862
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2863
|
-
|
|
2864
|
-
{
|
|
2865
|
-
cx: 4 + (width - 8),
|
|
2866
|
-
cy: normalizedValues[normalizedValues.length - 1],
|
|
2867
|
-
r: 1.5,
|
|
2868
|
-
fill: color
|
|
2869
|
-
}
|
|
2870
|
-
)
|
|
2871
|
-
] })
|
|
3069
|
+
forced && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: forcedTagStyle, "aria-label": "Forced", children: "F" })
|
|
3070
|
+
]
|
|
2872
3071
|
}
|
|
2873
3072
|
);
|
|
2874
3073
|
};
|
|
@@ -2884,7 +3083,9 @@ var CircularGauge = ({
|
|
|
2884
3083
|
unit,
|
|
2885
3084
|
label,
|
|
2886
3085
|
size = 60,
|
|
2887
|
-
color = "rgba(255, 255, 255, 0.9)"
|
|
3086
|
+
color = "rgba(255, 255, 255, 0.9)",
|
|
3087
|
+
forced = false,
|
|
3088
|
+
realValue
|
|
2888
3089
|
}) => {
|
|
2889
3090
|
const percentage = Math.min(value / max * 100, 100);
|
|
2890
3091
|
const strokeWidth = 4;
|
|
@@ -2915,7 +3116,7 @@ var CircularGauge = ({
|
|
|
2915
3116
|
height: size,
|
|
2916
3117
|
borderRadius: "50%",
|
|
2917
3118
|
backgroundColor,
|
|
2918
|
-
border: `1px solid ${borderStrokeColor}`
|
|
3119
|
+
border: forced ? `2px solid ${FORCED_MARK_COLOR.border}` : `1px solid ${borderStrokeColor}`
|
|
2919
3120
|
},
|
|
2920
3121
|
children: [
|
|
2921
3122
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("svg", { width: size, height: size, style: { transform: "rotate(-90deg)" }, children: [
|
|
@@ -2991,12 +3192,39 @@ var CircularGauge = ({
|
|
|
2991
3192
|
},
|
|
2992
3193
|
children: label
|
|
2993
3194
|
}
|
|
2994
|
-
)
|
|
3195
|
+
),
|
|
3196
|
+
forced && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
3197
|
+
"span",
|
|
3198
|
+
{
|
|
3199
|
+
"aria-label": "Forced",
|
|
3200
|
+
style: {
|
|
3201
|
+
display: "inline-flex",
|
|
3202
|
+
alignItems: "center",
|
|
3203
|
+
justifyContent: "center",
|
|
3204
|
+
width: "14px",
|
|
3205
|
+
height: "14px",
|
|
3206
|
+
fontSize: "9px",
|
|
3207
|
+
fontWeight: 700,
|
|
3208
|
+
color: FORCED_MARK_COLOR.text,
|
|
3209
|
+
backgroundColor: FORCED_MARK_COLOR.bg,
|
|
3210
|
+
border: `1px solid ${FORCED_MARK_COLOR.border}`,
|
|
3211
|
+
borderRadius: "50%",
|
|
3212
|
+
marginTop: "2px"
|
|
3213
|
+
},
|
|
3214
|
+
children: "F"
|
|
3215
|
+
}
|
|
3216
|
+
),
|
|
3217
|
+
forced && realValue !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { fontSize: "8px", opacity: 0.8, color: "white", marginTop: "1px" }, children: [
|
|
3218
|
+
"REAL ",
|
|
3219
|
+
realValue.toFixed(1),
|
|
3220
|
+
" ",
|
|
3221
|
+
unit
|
|
3222
|
+
] })
|
|
2995
3223
|
]
|
|
2996
3224
|
}
|
|
2997
3225
|
);
|
|
2998
3226
|
};
|
|
2999
|
-
var Sparkline = ({ data, width, height, color }) => {
|
|
3227
|
+
var Sparkline = ({ data, width, height, color, forced = false }) => {
|
|
3000
3228
|
if (!data || data.length < 2) {
|
|
3001
3229
|
return null;
|
|
3002
3230
|
}
|
|
@@ -3011,24 +3239,52 @@ var Sparkline = ({ data, width, height, color }) => {
|
|
|
3011
3239
|
const y = height - 8 - (value - min) / range * (height - 8);
|
|
3012
3240
|
return `${x + 4},${y + 4}`;
|
|
3013
3241
|
}).join(" ");
|
|
3014
|
-
return /* @__PURE__ */ (0, import_jsx_runtime12.
|
|
3242
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
3015
3243
|
"div",
|
|
3016
3244
|
{
|
|
3017
3245
|
style: {
|
|
3246
|
+
position: "relative",
|
|
3018
3247
|
width,
|
|
3019
3248
|
height,
|
|
3020
3249
|
backgroundColor: "rgba(0, 0, 0, 0.7)",
|
|
3021
|
-
border: "1px solid rgba(255, 255, 255, 0.3)",
|
|
3250
|
+
border: forced ? `1px solid ${FORCED_MARK_COLOR.border}` : "1px solid rgba(255, 255, 255, 0.3)",
|
|
3022
3251
|
borderRadius: "4px",
|
|
3023
3252
|
display: "flex",
|
|
3024
3253
|
alignItems: "center",
|
|
3025
3254
|
justifyContent: "center",
|
|
3026
3255
|
boxShadow: "0 1px 3px rgba(0, 0, 0, 0.2)"
|
|
3027
3256
|
},
|
|
3028
|
-
children:
|
|
3257
|
+
children: [
|
|
3258
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("svg", { width, height, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("polyline", { points, fill: "none", stroke: color, strokeWidth: "1.5", opacity: "0.9" }) }),
|
|
3259
|
+
forced && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: forcedTagStyle, "aria-label": "Forced", children: "F" })
|
|
3260
|
+
]
|
|
3029
3261
|
}
|
|
3030
3262
|
);
|
|
3031
3263
|
};
|
|
3264
|
+
var EquipmentForcedBadge = () => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
3265
|
+
"span",
|
|
3266
|
+
{
|
|
3267
|
+
"aria-label": "Forced",
|
|
3268
|
+
style: {
|
|
3269
|
+
position: "absolute",
|
|
3270
|
+
top: "-4px",
|
|
3271
|
+
right: "-4px",
|
|
3272
|
+
width: "11px",
|
|
3273
|
+
height: "11px",
|
|
3274
|
+
borderRadius: "50%",
|
|
3275
|
+
backgroundColor: FORCED_MARK_COLOR.bg,
|
|
3276
|
+
border: `1px solid ${FORCED_MARK_COLOR.border}`,
|
|
3277
|
+
color: FORCED_MARK_COLOR.text,
|
|
3278
|
+
fontSize: "7px",
|
|
3279
|
+
fontWeight: 700,
|
|
3280
|
+
display: "flex",
|
|
3281
|
+
alignItems: "center",
|
|
3282
|
+
justifyContent: "center",
|
|
3283
|
+
lineHeight: 1
|
|
3284
|
+
},
|
|
3285
|
+
children: "F"
|
|
3286
|
+
}
|
|
3287
|
+
);
|
|
3032
3288
|
var EquipmentIndicatorWithSparkline = ({
|
|
3033
3289
|
svgX,
|
|
3034
3290
|
svgY,
|
|
@@ -3036,11 +3292,51 @@ var EquipmentIndicatorWithSparkline = ({
|
|
|
3036
3292
|
label,
|
|
3037
3293
|
size = 30,
|
|
3038
3294
|
sparklineData,
|
|
3039
|
-
sparklineOffset = { x: 40, y: 0 }
|
|
3295
|
+
sparklineOffset = { x: 40, y: 0 },
|
|
3296
|
+
forced = false
|
|
3040
3297
|
}) => {
|
|
3041
3298
|
const hasSparkline = sparklineData && sparklineData.length > 1 && Math.max(...sparklineData) !== Math.min(...sparklineData);
|
|
3042
3299
|
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
3043
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SVGLockedOverlay, { svgX, svgY, style: { transform: "translate(-50%, -50%)" }, children: /* @__PURE__ */ (0, import_jsx_runtime12.
|
|
3300
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SVGLockedOverlay, { svgX, svgY, style: { transform: "translate(-50%, -50%)" }, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { position: "relative", width: size, height: size }, children: [
|
|
3301
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
3302
|
+
"div",
|
|
3303
|
+
{
|
|
3304
|
+
style: {
|
|
3305
|
+
width: size,
|
|
3306
|
+
height: size,
|
|
3307
|
+
borderRadius: "50%",
|
|
3308
|
+
backgroundColor: color,
|
|
3309
|
+
display: "flex",
|
|
3310
|
+
alignItems: "center",
|
|
3311
|
+
justifyContent: "center",
|
|
3312
|
+
color: "white",
|
|
3313
|
+
fontSize: "7px",
|
|
3314
|
+
fontWeight: "700",
|
|
3315
|
+
textAlign: "center",
|
|
3316
|
+
boxShadow: "0 2px 8px rgba(0, 0, 0, 0.3)",
|
|
3317
|
+
border: forced ? `2px solid ${FORCED_MARK_COLOR.border}` : "2px solid rgba(255, 255, 255, 0.3)"
|
|
3318
|
+
},
|
|
3319
|
+
children: label
|
|
3320
|
+
}
|
|
3321
|
+
),
|
|
3322
|
+
forced && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(EquipmentForcedBadge, {})
|
|
3323
|
+
] }) }),
|
|
3324
|
+
hasSparkline && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SVGLockedOverlay, { svgX: svgX + sparklineOffset.x, svgY: svgY + sparklineOffset.y, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Sparkline, { data: sparklineData, width: 60, height: 20, color, forced }) })
|
|
3325
|
+
] });
|
|
3326
|
+
};
|
|
3327
|
+
var EquipmentIndicator = ({
|
|
3328
|
+
svgX,
|
|
3329
|
+
svgY,
|
|
3330
|
+
color,
|
|
3331
|
+
label,
|
|
3332
|
+
size = 30,
|
|
3333
|
+
style,
|
|
3334
|
+
className,
|
|
3335
|
+
forced = false
|
|
3336
|
+
}) => {
|
|
3337
|
+
const overlayStyle = style !== void 0 ? { transform: "translate(-50%, -50%)", ...style } : { transform: "translate(-50%, -50%)" };
|
|
3338
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SVGLockedOverlay, { svgX, svgY, style: overlayStyle, className, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { position: "relative", width: size, height: size }, children: [
|
|
3339
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
3044
3340
|
"div",
|
|
3045
3341
|
{
|
|
3046
3342
|
style: {
|
|
@@ -3056,45 +3352,13 @@ var EquipmentIndicatorWithSparkline = ({
|
|
|
3056
3352
|
fontWeight: "700",
|
|
3057
3353
|
textAlign: "center",
|
|
3058
3354
|
boxShadow: "0 2px 8px rgba(0, 0, 0, 0.3)",
|
|
3059
|
-
border: "2px solid rgba(255, 255, 255, 0.3)"
|
|
3355
|
+
border: forced ? `2px solid ${FORCED_MARK_COLOR.border}` : "2px solid rgba(255, 255, 255, 0.3)"
|
|
3060
3356
|
},
|
|
3061
3357
|
children: label
|
|
3062
3358
|
}
|
|
3063
|
-
)
|
|
3064
|
-
|
|
3065
|
-
] });
|
|
3066
|
-
};
|
|
3067
|
-
var EquipmentIndicator = ({
|
|
3068
|
-
svgX,
|
|
3069
|
-
svgY,
|
|
3070
|
-
color,
|
|
3071
|
-
label,
|
|
3072
|
-
size = 30,
|
|
3073
|
-
style,
|
|
3074
|
-
className
|
|
3075
|
-
}) => {
|
|
3076
|
-
const overlayStyle = style !== void 0 ? { transform: "translate(-50%, -50%)", ...style } : { transform: "translate(-50%, -50%)" };
|
|
3077
|
-
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SVGLockedOverlay, { svgX, svgY, style: overlayStyle, className, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
3078
|
-
"div",
|
|
3079
|
-
{
|
|
3080
|
-
style: {
|
|
3081
|
-
width: size,
|
|
3082
|
-
height: size,
|
|
3083
|
-
borderRadius: "50%",
|
|
3084
|
-
backgroundColor: color,
|
|
3085
|
-
display: "flex",
|
|
3086
|
-
alignItems: "center",
|
|
3087
|
-
justifyContent: "center",
|
|
3088
|
-
color: "white",
|
|
3089
|
-
fontSize: "7px",
|
|
3090
|
-
fontWeight: "700",
|
|
3091
|
-
textAlign: "center",
|
|
3092
|
-
boxShadow: "0 2px 8px rgba(0, 0, 0, 0.3)",
|
|
3093
|
-
border: "2px solid rgba(255, 255, 255, 0.3)"
|
|
3094
|
-
},
|
|
3095
|
-
children: label
|
|
3096
|
-
}
|
|
3097
|
-
) });
|
|
3359
|
+
),
|
|
3360
|
+
forced && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(EquipmentForcedBadge, {})
|
|
3361
|
+
] }) });
|
|
3098
3362
|
};
|
|
3099
3363
|
|
|
3100
3364
|
// src/components/layout/FullscreenWorkspace/FullscreenWorkspace.tsx
|
|
@@ -3384,7 +3648,7 @@ var ThemeToggle = ({
|
|
|
3384
3648
|
};
|
|
3385
3649
|
|
|
3386
3650
|
// src/components/PIDCanvas/PIDCanvas.tsx
|
|
3387
|
-
var
|
|
3651
|
+
var import_react21 = __toESM(require("react"), 1);
|
|
3388
3652
|
|
|
3389
3653
|
// src/components/PIDCanvas/NodeRenderer.tsx
|
|
3390
3654
|
var import_react10 = __toESM(require("react"), 1);
|
|
@@ -3415,6 +3679,25 @@ var mockSymbolLibrary = {
|
|
|
3415
3679
|
tags: ["valve", "gate", "powered", "actuator"]
|
|
3416
3680
|
}
|
|
3417
3681
|
},
|
|
3682
|
+
"status-indicator": {
|
|
3683
|
+
id: "status-indicator",
|
|
3684
|
+
name: "Status LED",
|
|
3685
|
+
category: "instrument",
|
|
3686
|
+
viewBox: { x: 0, y: 0, width: 24, height: 24 },
|
|
3687
|
+
ports: [],
|
|
3688
|
+
svgContent: `
|
|
3689
|
+
<rect x="2" y="2" width="20" height="20"
|
|
3690
|
+
rx="var(--led-rx, 50%)"
|
|
3691
|
+
fill="var(--symbol-fill, #64748b)"
|
|
3692
|
+
stroke="rgba(255,255,255,0.4)"
|
|
3693
|
+
stroke-width="var(--led-bezel, 0)"
|
|
3694
|
+
style="transform-box: fill-box; transform: rotate(var(--led-rotate, 0deg)); transform-origin: center; pointer-events: all;"/>
|
|
3695
|
+
`,
|
|
3696
|
+
metadata: {
|
|
3697
|
+
description: "Status LED indicator driven by telemetry status color",
|
|
3698
|
+
tags: ["status", "led", "indicator", "instrument"]
|
|
3699
|
+
}
|
|
3700
|
+
},
|
|
3418
3701
|
"pump-positive-displacement": {
|
|
3419
3702
|
id: "pump-positive-displacement",
|
|
3420
3703
|
name: "Positive Displacement Pump",
|
|
@@ -4607,8 +4890,144 @@ function getAvailableSymbols() {
|
|
|
4607
4890
|
return [...Object.keys(customSymbols), ...Object.keys(mockSymbolLibrary)];
|
|
4608
4891
|
}
|
|
4609
4892
|
|
|
4893
|
+
// src/diagram/symbols/appearanceSchema.ts
|
|
4894
|
+
var COLOR_PRESETS = {
|
|
4895
|
+
green: "#22c55e",
|
|
4896
|
+
red: "#ef4444",
|
|
4897
|
+
amber: "#f59e0b",
|
|
4898
|
+
blue: "#3b82f6",
|
|
4899
|
+
grey: "#64748b"
|
|
4900
|
+
};
|
|
4901
|
+
function resolvePresetColor(name) {
|
|
4902
|
+
return name && COLOR_PRESETS[name] || COLOR_PRESETS.grey;
|
|
4903
|
+
}
|
|
4904
|
+
var COLOR_OPTIONS = Object.keys(COLOR_PRESETS);
|
|
4905
|
+
var STATUS_LED_APPEARANCE = [
|
|
4906
|
+
{
|
|
4907
|
+
key: "shape",
|
|
4908
|
+
kind: "select",
|
|
4909
|
+
label: "Shape",
|
|
4910
|
+
options: ["circle", "square", "diamond"],
|
|
4911
|
+
default: "circle"
|
|
4912
|
+
},
|
|
4913
|
+
{
|
|
4914
|
+
key: "size",
|
|
4915
|
+
kind: "select",
|
|
4916
|
+
label: "Size",
|
|
4917
|
+
target: "scale",
|
|
4918
|
+
options: ["small", "medium", "large"],
|
|
4919
|
+
default: "medium",
|
|
4920
|
+
valueMap: { small: 0.75, medium: 1, large: 1.5 }
|
|
4921
|
+
},
|
|
4922
|
+
{ key: "led", kind: "boolean", label: "Bezel ring", default: true },
|
|
4923
|
+
{ key: "glow", kind: "boolean", label: "Diffusion (glow)", default: false },
|
|
4924
|
+
{
|
|
4925
|
+
key: "animation",
|
|
4926
|
+
kind: "select",
|
|
4927
|
+
label: "Animation",
|
|
4928
|
+
options: ["none", "pulse", "blink"],
|
|
4929
|
+
default: "none"
|
|
4930
|
+
},
|
|
4931
|
+
{
|
|
4932
|
+
key: "labelPosition",
|
|
4933
|
+
kind: "select",
|
|
4934
|
+
label: "Label position",
|
|
4935
|
+
options: ["bottom", "top", "left", "right"],
|
|
4936
|
+
default: "bottom"
|
|
4937
|
+
},
|
|
4938
|
+
// Color binding: a named signal drives the on/off color.
|
|
4939
|
+
{
|
|
4940
|
+
key: "colorSource",
|
|
4941
|
+
kind: "tag",
|
|
4942
|
+
label: "Color source (tag)",
|
|
4943
|
+
default: "",
|
|
4944
|
+
help: "Signal/tag that drives color. True (non-zero) shows On color; false shows Off color. Blank = unbound (grey)."
|
|
4945
|
+
},
|
|
4946
|
+
{
|
|
4947
|
+
key: "onColor",
|
|
4948
|
+
kind: "select",
|
|
4949
|
+
label: "On color (true)",
|
|
4950
|
+
options: COLOR_OPTIONS,
|
|
4951
|
+
default: "green",
|
|
4952
|
+
help: "Color when the Color source is true."
|
|
4953
|
+
},
|
|
4954
|
+
{
|
|
4955
|
+
key: "offColor",
|
|
4956
|
+
kind: "select",
|
|
4957
|
+
label: "Off color (false)",
|
|
4958
|
+
options: COLOR_OPTIONS,
|
|
4959
|
+
default: "red",
|
|
4960
|
+
help: "Color when the Color source is false."
|
|
4961
|
+
},
|
|
4962
|
+
// Visibility binding: an independent named signal drives show/hide.
|
|
4963
|
+
{
|
|
4964
|
+
key: "visibleSource",
|
|
4965
|
+
kind: "tag",
|
|
4966
|
+
label: "Visibility source (tag)",
|
|
4967
|
+
default: "",
|
|
4968
|
+
help: "Signal/tag that drives visibility. True shows the LED, false hides it. Blank = always visible (use the Visible checkbox)."
|
|
4969
|
+
},
|
|
4970
|
+
{
|
|
4971
|
+
key: "visible",
|
|
4972
|
+
kind: "boolean",
|
|
4973
|
+
label: "Visible",
|
|
4974
|
+
target: "visible",
|
|
4975
|
+
default: true,
|
|
4976
|
+
help: "Static show/hide, used only when no Visibility source is set."
|
|
4977
|
+
}
|
|
4978
|
+
];
|
|
4979
|
+
var APPEARANCE_REGISTRY = {
|
|
4980
|
+
"status-indicator": STATUS_LED_APPEARANCE
|
|
4981
|
+
};
|
|
4982
|
+
function getAppearanceSchema(symbolId) {
|
|
4983
|
+
return APPEARANCE_REGISTRY[symbolId] ?? [];
|
|
4984
|
+
}
|
|
4985
|
+
function getAppearanceDefaults(symbolId) {
|
|
4986
|
+
const out = {};
|
|
4987
|
+
for (const field of getAppearanceSchema(symbolId)) {
|
|
4988
|
+
if ((field.target ?? "metadata") === "metadata" && field.default !== void 0) {
|
|
4989
|
+
out[field.key] = field.default;
|
|
4990
|
+
}
|
|
4991
|
+
}
|
|
4992
|
+
return out;
|
|
4993
|
+
}
|
|
4994
|
+
function readAppearanceValue(node, field) {
|
|
4995
|
+
if (field.target === "visible") {
|
|
4996
|
+
return node.visible ?? field.default ?? true;
|
|
4997
|
+
}
|
|
4998
|
+
if (field.target === "scale") {
|
|
4999
|
+
const scale = node.transform.scale ?? 1;
|
|
5000
|
+
if (field.valueMap) {
|
|
5001
|
+
let bestOption = field.options?.[0] ?? String(scale);
|
|
5002
|
+
let bestDiff = Infinity;
|
|
5003
|
+
for (const [option, value2] of Object.entries(field.valueMap)) {
|
|
5004
|
+
const diff = Math.abs(value2 - scale);
|
|
5005
|
+
if (diff < bestDiff) {
|
|
5006
|
+
bestDiff = diff;
|
|
5007
|
+
bestOption = option;
|
|
5008
|
+
}
|
|
5009
|
+
}
|
|
5010
|
+
return bestOption;
|
|
5011
|
+
}
|
|
5012
|
+
return scale;
|
|
5013
|
+
}
|
|
5014
|
+
const value = node.metadata?.[field.key];
|
|
5015
|
+
return value ?? field.default;
|
|
5016
|
+
}
|
|
5017
|
+
function writeAppearanceValue(node, field, value) {
|
|
5018
|
+
if (field.target === "visible") {
|
|
5019
|
+
return { visible: Boolean(value) };
|
|
5020
|
+
}
|
|
5021
|
+
if (field.target === "scale") {
|
|
5022
|
+
const scale = field.valueMap ? field.valueMap[String(value)] ?? 1 : Number(value);
|
|
5023
|
+
return { transform: { ...node.transform, scale } };
|
|
5024
|
+
}
|
|
5025
|
+
return { metadata: { ...node.metadata, [field.key]: value } };
|
|
5026
|
+
}
|
|
5027
|
+
|
|
4610
5028
|
// src/components/PIDCanvas/NodeRenderer.tsx
|
|
4611
5029
|
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
5030
|
+
var HATCH_SIZE = 6;
|
|
4612
5031
|
function NodeRendererImpl({
|
|
4613
5032
|
nodes: nodes2,
|
|
4614
5033
|
selectedNodeIds,
|
|
@@ -4620,140 +5039,206 @@ function NodeRendererImpl({
|
|
|
4620
5039
|
enableDrag = false,
|
|
4621
5040
|
statusColorMap
|
|
4622
5041
|
}) {
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("g", { children: [
|
|
4629
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
4630
|
-
"circle",
|
|
4631
|
-
{
|
|
4632
|
-
cx: node.transform.x,
|
|
4633
|
-
cy: node.transform.y,
|
|
4634
|
-
r: "15",
|
|
4635
|
-
fill: "#ff0000",
|
|
4636
|
-
opacity: "0.3",
|
|
4637
|
-
stroke: "#ff0000",
|
|
4638
|
-
strokeWidth: "2"
|
|
4639
|
-
}
|
|
4640
|
-
),
|
|
4641
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
4642
|
-
"text",
|
|
4643
|
-
{
|
|
4644
|
-
x: node.transform.x,
|
|
4645
|
-
y: node.transform.y,
|
|
4646
|
-
textAnchor: "middle",
|
|
4647
|
-
dominantBaseline: "middle",
|
|
4648
|
-
fontSize: "10",
|
|
4649
|
-
fill: "#ff0000",
|
|
4650
|
-
children: "?"
|
|
4651
|
-
}
|
|
4652
|
-
)
|
|
4653
|
-
] }, node.id);
|
|
4654
|
-
}
|
|
4655
|
-
const transforms = [];
|
|
4656
|
-
const effectiveX = isDragging ? node.transform.x + dragOffset.x : node.transform.x;
|
|
4657
|
-
const effectiveY = isDragging ? node.transform.y + dragOffset.y : node.transform.y;
|
|
4658
|
-
transforms.push(`translate(${effectiveX}, ${effectiveY})`);
|
|
4659
|
-
if (node.transform.rotation) {
|
|
4660
|
-
const centerX = symbol.viewBox.width / 2;
|
|
4661
|
-
const centerY = symbol.viewBox.height / 2;
|
|
4662
|
-
transforms.push(`rotate(${node.transform.rotation}, ${centerX}, ${centerY})`);
|
|
4663
|
-
}
|
|
4664
|
-
if (node.transform.scale && node.transform.scale !== 1) {
|
|
4665
|
-
const centerX = symbol.viewBox.width / 2;
|
|
4666
|
-
const centerY = symbol.viewBox.height / 2;
|
|
4667
|
-
transforms.push(
|
|
4668
|
-
`translate(${centerX}, ${centerY}) scale(${node.transform.scale}) translate(${-centerX}, ${-centerY})`
|
|
4669
|
-
);
|
|
4670
|
-
}
|
|
4671
|
-
if (node.transform.flipX || node.transform.flipY) {
|
|
4672
|
-
const scaleX = node.transform.flipX ? -1 : 1;
|
|
4673
|
-
const scaleY = node.transform.flipY ? -1 : 1;
|
|
4674
|
-
const centerX = symbol.viewBox.width / 2;
|
|
4675
|
-
const centerY = symbol.viewBox.height / 2;
|
|
4676
|
-
transforms.push(
|
|
4677
|
-
`translate(${centerX}, ${centerY}) scale(${scaleX}, ${scaleY}) translate(${-centerX}, ${-centerY})`
|
|
4678
|
-
);
|
|
4679
|
-
}
|
|
4680
|
-
const statusEntry = resolveStatusColor(node.status, statusColorMap);
|
|
4681
|
-
const fillColor = node.customColors?.fill ?? statusEntry.fill;
|
|
4682
|
-
const strokeColor = node.customColors?.stroke ?? statusEntry.stroke;
|
|
4683
|
-
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
4684
|
-
"g",
|
|
5042
|
+
const hatchId = `pid-unknown-hatch-${import_react10.default.useId().replace(/[^A-Za-z0-9_-]/g, "")}`;
|
|
5043
|
+
const hasUnknown = nodes2.some((n) => n.positionUnknown === true && n.visible !== false);
|
|
5044
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("g", { id: "layer-nodes", children: [
|
|
5045
|
+
hasUnknown && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
5046
|
+
"pattern",
|
|
4685
5047
|
{
|
|
4686
|
-
|
|
4687
|
-
"data-
|
|
4688
|
-
"
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
"--symbol-fill": fillColor,
|
|
4693
|
-
"--symbol-stroke": strokeColor,
|
|
4694
|
-
cursor: enableDrag ? isDragging ? "grabbing" : "grab" : onNodeClick ? "pointer" : "default"
|
|
4695
|
-
},
|
|
4696
|
-
onClick: (e) => {
|
|
4697
|
-
e.stopPropagation();
|
|
4698
|
-
onNodeClick?.(node.id, e);
|
|
4699
|
-
},
|
|
4700
|
-
onDoubleClick: (e) => {
|
|
4701
|
-
e.stopPropagation();
|
|
4702
|
-
onNodeDoubleClick?.(node.id, e);
|
|
4703
|
-
},
|
|
4704
|
-
onMouseDown: (e) => {
|
|
4705
|
-
if (enableDrag) {
|
|
4706
|
-
onNodeDragStart?.(node.id, e);
|
|
4707
|
-
}
|
|
4708
|
-
},
|
|
4709
|
-
onTouchStart: (e) => {
|
|
4710
|
-
if (enableDrag) {
|
|
4711
|
-
e.stopPropagation();
|
|
4712
|
-
onNodeDragStart?.(node.id, e);
|
|
4713
|
-
}
|
|
4714
|
-
},
|
|
5048
|
+
id: hatchId,
|
|
5049
|
+
"data-testid": "position-unknown-pattern",
|
|
5050
|
+
patternUnits: "userSpaceOnUse",
|
|
5051
|
+
width: HATCH_SIZE,
|
|
5052
|
+
height: HATCH_SIZE,
|
|
5053
|
+
patternTransform: "rotate(45)",
|
|
4715
5054
|
children: [
|
|
4716
|
-
|
|
4717
|
-
|
|
5055
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("rect", { width: HATCH_SIZE, height: HATCH_SIZE, fill: UNKNOWN_MARK_COLOR.fill }),
|
|
5056
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
5057
|
+
"line",
|
|
4718
5058
|
{
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
strokeWidth: isDragging ? "3" : "2",
|
|
4726
|
-
strokeDasharray: "4 2",
|
|
4727
|
-
rx: "2",
|
|
4728
|
-
pointerEvents: "none"
|
|
5059
|
+
x1: "0",
|
|
5060
|
+
y1: "0",
|
|
5061
|
+
x2: "0",
|
|
5062
|
+
y2: HATCH_SIZE,
|
|
5063
|
+
stroke: UNKNOWN_MARK_COLOR.text,
|
|
5064
|
+
strokeWidth: "2"
|
|
4729
5065
|
}
|
|
4730
|
-
)
|
|
5066
|
+
)
|
|
5067
|
+
]
|
|
5068
|
+
}
|
|
5069
|
+
) }),
|
|
5070
|
+
nodes2.filter((node) => node.visible !== false).map((node) => {
|
|
5071
|
+
const symbol = getSymbolDefinition(node.symbolId);
|
|
5072
|
+
const isSelected = selectedNodeIds?.has(node.id) ?? false;
|
|
5073
|
+
const isDragging = draggingNodeId === node.id;
|
|
5074
|
+
if (!symbol) {
|
|
5075
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("g", { children: [
|
|
4731
5076
|
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
4732
|
-
"
|
|
5077
|
+
"circle",
|
|
4733
5078
|
{
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
5079
|
+
cx: node.transform.x,
|
|
5080
|
+
cy: node.transform.y,
|
|
5081
|
+
r: "15",
|
|
5082
|
+
fill: "#ff0000",
|
|
5083
|
+
opacity: "0.3",
|
|
5084
|
+
stroke: "#ff0000",
|
|
5085
|
+
strokeWidth: "2"
|
|
4737
5086
|
}
|
|
4738
5087
|
),
|
|
4739
5088
|
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
4740
5089
|
"text",
|
|
4741
5090
|
{
|
|
4742
|
-
x:
|
|
4743
|
-
y:
|
|
5091
|
+
x: node.transform.x,
|
|
5092
|
+
y: node.transform.y,
|
|
4744
5093
|
textAnchor: "middle",
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
fill:
|
|
4748
|
-
|
|
4749
|
-
children: node.label || node.id
|
|
5094
|
+
dominantBaseline: "middle",
|
|
5095
|
+
fontSize: "10",
|
|
5096
|
+
fill: "#ff0000",
|
|
5097
|
+
children: "?"
|
|
4750
5098
|
}
|
|
4751
5099
|
)
|
|
4752
|
-
]
|
|
4753
|
-
}
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
5100
|
+
] }, node.id);
|
|
5101
|
+
}
|
|
5102
|
+
const transforms = [];
|
|
5103
|
+
const effectiveX = isDragging ? node.transform.x + dragOffset.x : node.transform.x;
|
|
5104
|
+
const effectiveY = isDragging ? node.transform.y + dragOffset.y : node.transform.y;
|
|
5105
|
+
transforms.push(`translate(${effectiveX}, ${effectiveY})`);
|
|
5106
|
+
if (node.transform.rotation) {
|
|
5107
|
+
const centerX = symbol.viewBox.width / 2;
|
|
5108
|
+
const centerY = symbol.viewBox.height / 2;
|
|
5109
|
+
transforms.push(`rotate(${node.transform.rotation}, ${centerX}, ${centerY})`);
|
|
5110
|
+
}
|
|
5111
|
+
if (node.transform.scale && node.transform.scale !== 1) {
|
|
5112
|
+
const centerX = symbol.viewBox.width / 2;
|
|
5113
|
+
const centerY = symbol.viewBox.height / 2;
|
|
5114
|
+
transforms.push(
|
|
5115
|
+
`translate(${centerX}, ${centerY}) scale(${node.transform.scale}) translate(${-centerX}, ${-centerY})`
|
|
5116
|
+
);
|
|
5117
|
+
}
|
|
5118
|
+
if (node.transform.flipX || node.transform.flipY) {
|
|
5119
|
+
const scaleX = node.transform.flipX ? -1 : 1;
|
|
5120
|
+
const scaleY = node.transform.flipY ? -1 : 1;
|
|
5121
|
+
const centerX = symbol.viewBox.width / 2;
|
|
5122
|
+
const centerY = symbol.viewBox.height / 2;
|
|
5123
|
+
transforms.push(
|
|
5124
|
+
`translate(${centerX}, ${centerY}) scale(${scaleX}, ${scaleY}) translate(${-centerX}, ${-centerY})`
|
|
5125
|
+
);
|
|
5126
|
+
}
|
|
5127
|
+
const statusEntry = resolveStatusColor(node.status, statusColorMap);
|
|
5128
|
+
const isUnknown = node.positionUnknown === true;
|
|
5129
|
+
const fillColor = isUnknown ? `url(#${hatchId})` : node.customColors?.fill ?? statusEntry.fill;
|
|
5130
|
+
const strokeColor = isUnknown ? UNKNOWN_MARK_COLOR.stroke : node.customColors?.stroke ?? statusEntry.stroke;
|
|
5131
|
+
const appearance = { ...getAppearanceDefaults(node.symbolId), ...node.metadata ?? {} };
|
|
5132
|
+
const ledStyle = {};
|
|
5133
|
+
if (appearance.shape !== void 0) {
|
|
5134
|
+
ledStyle["--led-rx"] = appearance.shape === "circle" ? "50%" : "2";
|
|
5135
|
+
ledStyle["--led-rotate"] = appearance.shape === "diamond" ? "45deg" : "0deg";
|
|
5136
|
+
}
|
|
5137
|
+
if (appearance.led !== void 0) {
|
|
5138
|
+
ledStyle["--led-bezel"] = appearance.led ? "2" : "0";
|
|
5139
|
+
}
|
|
5140
|
+
if (appearance.glow) {
|
|
5141
|
+
ledStyle.filter = `drop-shadow(0 0 4px ${fillColor})`;
|
|
5142
|
+
}
|
|
5143
|
+
const ledAnimation = typeof appearance.animation === "string" && appearance.animation !== "none" ? appearance.animation : void 0;
|
|
5144
|
+
const vb = symbol.viewBox;
|
|
5145
|
+
const ox = node.labelOffset?.x ?? 0;
|
|
5146
|
+
const oy = node.labelOffset?.y ?? 0;
|
|
5147
|
+
const labelPos = typeof appearance.labelPosition === "string" ? appearance.labelPosition : "bottom";
|
|
5148
|
+
let labelX = vb.width / 2 + ox;
|
|
5149
|
+
let labelY = vb.height + 12 + oy;
|
|
5150
|
+
let labelAnchor = "middle";
|
|
5151
|
+
if (labelPos === "top") {
|
|
5152
|
+
labelX = vb.width / 2 + ox;
|
|
5153
|
+
labelY = -6 + oy;
|
|
5154
|
+
labelAnchor = "middle";
|
|
5155
|
+
} else if (labelPos === "left") {
|
|
5156
|
+
labelX = -6 + ox;
|
|
5157
|
+
labelY = vb.height / 2 + oy;
|
|
5158
|
+
labelAnchor = "end";
|
|
5159
|
+
} else if (labelPos === "right") {
|
|
5160
|
+
labelX = vb.width + 6 + ox;
|
|
5161
|
+
labelY = vb.height / 2 + oy;
|
|
5162
|
+
labelAnchor = "start";
|
|
5163
|
+
}
|
|
5164
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
5165
|
+
"g",
|
|
5166
|
+
{
|
|
5167
|
+
"data-node-id": node.id,
|
|
5168
|
+
"data-symbol-id": node.symbolId,
|
|
5169
|
+
"data-selected": isSelected,
|
|
5170
|
+
"data-dragging": isDragging,
|
|
5171
|
+
"data-led-animation": ledAnimation,
|
|
5172
|
+
"data-position-unknown": isUnknown ? "true" : void 0,
|
|
5173
|
+
transform: transforms.join(" "),
|
|
5174
|
+
style: {
|
|
5175
|
+
"--symbol-fill": fillColor,
|
|
5176
|
+
"--symbol-stroke": strokeColor,
|
|
5177
|
+
cursor: enableDrag ? isDragging ? "grabbing" : "grab" : onNodeClick ? "pointer" : "default",
|
|
5178
|
+
...ledStyle
|
|
5179
|
+
},
|
|
5180
|
+
onClick: (e) => {
|
|
5181
|
+
e.stopPropagation();
|
|
5182
|
+
onNodeClick?.(node.id, e);
|
|
5183
|
+
},
|
|
5184
|
+
onDoubleClick: (e) => {
|
|
5185
|
+
e.stopPropagation();
|
|
5186
|
+
onNodeDoubleClick?.(node.id, e);
|
|
5187
|
+
},
|
|
5188
|
+
onMouseDown: (e) => {
|
|
5189
|
+
if (enableDrag) {
|
|
5190
|
+
onNodeDragStart?.(node.id, e);
|
|
5191
|
+
}
|
|
5192
|
+
},
|
|
5193
|
+
onTouchStart: (e) => {
|
|
5194
|
+
if (enableDrag) {
|
|
5195
|
+
e.stopPropagation();
|
|
5196
|
+
onNodeDragStart?.(node.id, e);
|
|
5197
|
+
}
|
|
5198
|
+
},
|
|
5199
|
+
children: [
|
|
5200
|
+
isSelected && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
5201
|
+
"rect",
|
|
5202
|
+
{
|
|
5203
|
+
x: "-5",
|
|
5204
|
+
y: "-5",
|
|
5205
|
+
width: symbol.viewBox.width + 10,
|
|
5206
|
+
height: symbol.viewBox.height + 10,
|
|
5207
|
+
fill: "none",
|
|
5208
|
+
stroke: isDragging ? "#10b981" : "#3b82f6",
|
|
5209
|
+
strokeWidth: isDragging ? "3" : "2",
|
|
5210
|
+
strokeDasharray: "4 2",
|
|
5211
|
+
rx: "2",
|
|
5212
|
+
pointerEvents: "none"
|
|
5213
|
+
}
|
|
5214
|
+
),
|
|
5215
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
5216
|
+
"g",
|
|
5217
|
+
{
|
|
5218
|
+
dangerouslySetInnerHTML: { __html: symbol.svgContent },
|
|
5219
|
+
"data-symbol-content": symbol.id,
|
|
5220
|
+
style: { pointerEvents: "auto" }
|
|
5221
|
+
}
|
|
5222
|
+
),
|
|
5223
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
5224
|
+
"text",
|
|
5225
|
+
{
|
|
5226
|
+
x: labelX,
|
|
5227
|
+
y: labelY,
|
|
5228
|
+
textAnchor: labelAnchor,
|
|
5229
|
+
fontSize: node.labelFontSize ?? 10,
|
|
5230
|
+
fontWeight: "600",
|
|
5231
|
+
fill: isSelected ? "#3b82f6" : "#1f2937",
|
|
5232
|
+
transform: node.transform.rotation ? `rotate(${-node.transform.rotation}, ${labelX}, ${labelY})` : void 0,
|
|
5233
|
+
children: node.label || node.id
|
|
5234
|
+
}
|
|
5235
|
+
)
|
|
5236
|
+
]
|
|
5237
|
+
},
|
|
5238
|
+
node.id
|
|
5239
|
+
);
|
|
5240
|
+
})
|
|
5241
|
+
] });
|
|
4757
5242
|
}
|
|
4758
5243
|
var NodeRenderer = import_react10.default.memo(NodeRendererImpl);
|
|
4759
5244
|
|
|
@@ -4974,7 +5459,9 @@ function DataOverlayImpl({
|
|
|
4974
5459
|
scale = 1,
|
|
4975
5460
|
statusColorMap
|
|
4976
5461
|
}) {
|
|
4977
|
-
const { value, display, history, scaling } = telemetry;
|
|
5462
|
+
const { value, display, history, scaling, forced } = telemetry;
|
|
5463
|
+
const isForced = forced?.active === true;
|
|
5464
|
+
const hasRealValue = isForced && forced?.realValue !== void 0;
|
|
4978
5465
|
const showValue = display?.showValue ?? true;
|
|
4979
5466
|
const showStatus = display?.showStatus ?? true;
|
|
4980
5467
|
const showSparkline = display?.showSparkline ?? false;
|
|
@@ -5023,12 +5510,16 @@ function DataOverlayImpl({
|
|
|
5023
5510
|
const finalTextColor = textColor || colors.text;
|
|
5024
5511
|
const formattedValue = formatValue(value.value);
|
|
5025
5512
|
const displayText = unit ? `${formattedValue} ${unit}` : formattedValue;
|
|
5513
|
+
const realDisplayText = hasRealValue ? unit ? `REAL ${formatValue(forced.realValue)} ${unit}` : `REAL ${formatValue(forced.realValue)}` : void 0;
|
|
5514
|
+
const borderColor = isForced ? FORCED_MARK_COLOR.border : colors.border;
|
|
5515
|
+
const borderWidth = (isForced ? 2 : 1) * scale;
|
|
5026
5516
|
const hasSparkline = showSparkline && sparklinePath;
|
|
5027
|
-
const
|
|
5517
|
+
const extraMarkRows = realDisplayText ? 1 : 0;
|
|
5518
|
+
const overlayHeight = (label ? hasSparkline ? 55 : 30 : hasSparkline ? 47 : 22) * scale + extraMarkRows * 9 * scale;
|
|
5028
5519
|
const overlayWidth = 80 * scale;
|
|
5029
5520
|
const displayX = x + offsetX;
|
|
5030
5521
|
const displayY = y + offsetY;
|
|
5031
|
-
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("g", { "data-overlay-node": nodeId, "data-status": value.status, children: [
|
|
5522
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("g", { "data-overlay-node": nodeId, "data-status": value.status, "data-forced": isForced, children: [
|
|
5032
5523
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
5033
5524
|
"rect",
|
|
5034
5525
|
{
|
|
@@ -5038,8 +5529,8 @@ function DataOverlayImpl({
|
|
|
5038
5529
|
height: overlayHeight,
|
|
5039
5530
|
rx: 4 * scale,
|
|
5040
5531
|
fill: colors.bg,
|
|
5041
|
-
stroke:
|
|
5042
|
-
strokeWidth:
|
|
5532
|
+
stroke: borderColor,
|
|
5533
|
+
strokeWidth: borderWidth,
|
|
5043
5534
|
opacity: "0.95",
|
|
5044
5535
|
filter: "drop-shadow(0 2px 4px rgba(0,0,0,0.2))"
|
|
5045
5536
|
}
|
|
@@ -5088,6 +5579,48 @@ function DataOverlayImpl({
|
|
|
5088
5579
|
]
|
|
5089
5580
|
}
|
|
5090
5581
|
),
|
|
5582
|
+
isForced && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
5583
|
+
"g",
|
|
5584
|
+
{
|
|
5585
|
+
transform: `translate(${displayX + overlayWidth / 2}, ${displayY - 25 * scale})`,
|
|
5586
|
+
"aria-label": "Forced",
|
|
5587
|
+
children: [
|
|
5588
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
5589
|
+
"circle",
|
|
5590
|
+
{
|
|
5591
|
+
r: 7 * scale,
|
|
5592
|
+
fill: FORCED_MARK_COLOR.bg,
|
|
5593
|
+
stroke: FORCED_MARK_COLOR.border,
|
|
5594
|
+
strokeWidth: 1.5 * scale
|
|
5595
|
+
}
|
|
5596
|
+
),
|
|
5597
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
5598
|
+
"text",
|
|
5599
|
+
{
|
|
5600
|
+
textAnchor: "middle",
|
|
5601
|
+
dominantBaseline: "central",
|
|
5602
|
+
fontSize: 8 * scale,
|
|
5603
|
+
fontWeight: "700",
|
|
5604
|
+
fill: FORCED_MARK_COLOR.text,
|
|
5605
|
+
children: "F"
|
|
5606
|
+
}
|
|
5607
|
+
)
|
|
5608
|
+
]
|
|
5609
|
+
}
|
|
5610
|
+
),
|
|
5611
|
+
realDisplayText && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
5612
|
+
"text",
|
|
5613
|
+
{
|
|
5614
|
+
x: displayX,
|
|
5615
|
+
y: displayY + (value.quality !== void 0 && value.quality < 100 ? 14 : 5) * scale,
|
|
5616
|
+
textAnchor: "middle",
|
|
5617
|
+
fontSize: 7 * scale,
|
|
5618
|
+
fontWeight: "500",
|
|
5619
|
+
fill: finalTextColor,
|
|
5620
|
+
opacity: "0.85",
|
|
5621
|
+
children: realDisplayText
|
|
5622
|
+
}
|
|
5623
|
+
),
|
|
5091
5624
|
hasSparkline && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("g", { transform: `translate(${displayX - 35 * scale}, ${displayY + (label ? 5 : 0) * scale})`, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
5092
5625
|
"path",
|
|
5093
5626
|
{
|
|
@@ -5855,8 +6388,49 @@ function useTelemetryStatus(telemetry, diagram, setDiagram, options = {}) {
|
|
|
5855
6388
|
}, [telemetry, diagram, setDiagram, enabled, mapStatus]);
|
|
5856
6389
|
}
|
|
5857
6390
|
|
|
5858
|
-
// src/diagram/hooks/
|
|
6391
|
+
// src/diagram/hooks/useBooleanIndicators.ts
|
|
5859
6392
|
var import_react18 = require("react");
|
|
6393
|
+
function useBooleanIndicators(telemetry, diagram, setDiagram, options = {}) {
|
|
6394
|
+
const { enabled = true, symbolId = "status-indicator" } = options;
|
|
6395
|
+
(0, import_react18.useEffect)(() => {
|
|
6396
|
+
if (!enabled) return;
|
|
6397
|
+
const tagIndex = /* @__PURE__ */ new Map();
|
|
6398
|
+
telemetry.forEach((binding) => {
|
|
6399
|
+
if (binding.tag) tagIndex.set(binding.tag, binding.value.value);
|
|
6400
|
+
});
|
|
6401
|
+
let needsUpdate = false;
|
|
6402
|
+
const updatedNodes = diagram.nodes.map((node) => {
|
|
6403
|
+
if (node.symbolId !== symbolId) return node;
|
|
6404
|
+
const meta = node.metadata ?? {};
|
|
6405
|
+
const colorSource = typeof meta.colorSource === "string" ? meta.colorSource : "";
|
|
6406
|
+
const visibleSource = typeof meta.visibleSource === "string" ? meta.visibleSource : "";
|
|
6407
|
+
let next = node;
|
|
6408
|
+
if (colorSource) {
|
|
6409
|
+
const isTrue = Boolean(tagIndex.get(colorSource));
|
|
6410
|
+
const fill = resolvePresetColor(
|
|
6411
|
+
String(isTrue ? meta.onColor ?? "green" : meta.offColor ?? "red")
|
|
6412
|
+
);
|
|
6413
|
+
if (node.customColors?.fill !== fill) {
|
|
6414
|
+
next = { ...next, customColors: { ...next.customColors, fill } };
|
|
6415
|
+
}
|
|
6416
|
+
}
|
|
6417
|
+
if (visibleSource) {
|
|
6418
|
+
const vis = Boolean(tagIndex.get(visibleSource));
|
|
6419
|
+
if ((next.visible ?? true) !== vis) {
|
|
6420
|
+
next = { ...next, visible: vis };
|
|
6421
|
+
}
|
|
6422
|
+
}
|
|
6423
|
+
if (next !== node) needsUpdate = true;
|
|
6424
|
+
return next;
|
|
6425
|
+
});
|
|
6426
|
+
if (needsUpdate) {
|
|
6427
|
+
setDiagram({ ...diagram, nodes: updatedNodes });
|
|
6428
|
+
}
|
|
6429
|
+
}, [telemetry, diagram, setDiagram, enabled, symbolId]);
|
|
6430
|
+
}
|
|
6431
|
+
|
|
6432
|
+
// src/diagram/hooks/useDrag.ts
|
|
6433
|
+
var import_react19 = require("react");
|
|
5860
6434
|
function useDrag(options = {}) {
|
|
5861
6435
|
const {
|
|
5862
6436
|
onDragStart,
|
|
@@ -5866,23 +6440,23 @@ function useDrag(options = {}) {
|
|
|
5866
6440
|
dragThreshold = 3,
|
|
5867
6441
|
screenToWorld = (x, y) => ({ x, y })
|
|
5868
6442
|
} = options;
|
|
5869
|
-
const [dragState, setDragState] = (0,
|
|
6443
|
+
const [dragState, setDragState] = (0, import_react19.useState)({
|
|
5870
6444
|
isDragging: false,
|
|
5871
6445
|
startPosition: null,
|
|
5872
6446
|
offset: { x: 0, y: 0 },
|
|
5873
6447
|
draggedId: null
|
|
5874
6448
|
});
|
|
5875
|
-
const [isListening, setIsListening] = (0,
|
|
5876
|
-
const dragStartRef = (0,
|
|
5877
|
-
const hasMovedRef = (0,
|
|
5878
|
-
const applySnap = (0,
|
|
6449
|
+
const [isListening, setIsListening] = (0, import_react19.useState)(false);
|
|
6450
|
+
const dragStartRef = (0, import_react19.useRef)(null);
|
|
6451
|
+
const hasMovedRef = (0, import_react19.useRef)(false);
|
|
6452
|
+
const applySnap = (0, import_react19.useCallback)(
|
|
5879
6453
|
(value) => {
|
|
5880
6454
|
if (snapToGrid <= 0) return value;
|
|
5881
6455
|
return Math.round(value / snapToGrid) * snapToGrid;
|
|
5882
6456
|
},
|
|
5883
6457
|
[snapToGrid]
|
|
5884
6458
|
);
|
|
5885
|
-
const handleMouseMove = (0,
|
|
6459
|
+
const handleMouseMove = (0, import_react19.useCallback)(
|
|
5886
6460
|
(event) => {
|
|
5887
6461
|
if (!dragStartRef.current) return;
|
|
5888
6462
|
const { id, screenStart: _screenStart, itemPosition, clickOffset } = dragStartRef.current;
|
|
@@ -5923,7 +6497,7 @@ function useDrag(options = {}) {
|
|
|
5923
6497
|
},
|
|
5924
6498
|
[screenToWorld, dragThreshold, applySnap, onDragStart, onDragMove]
|
|
5925
6499
|
);
|
|
5926
|
-
const handleMouseUp = (0,
|
|
6500
|
+
const handleMouseUp = (0, import_react19.useCallback)(
|
|
5927
6501
|
(event) => {
|
|
5928
6502
|
if (!dragStartRef.current || !hasMovedRef.current) {
|
|
5929
6503
|
dragStartRef.current = null;
|
|
@@ -5960,7 +6534,7 @@ function useDrag(options = {}) {
|
|
|
5960
6534
|
},
|
|
5961
6535
|
[screenToWorld, applySnap, onDragEnd]
|
|
5962
6536
|
);
|
|
5963
|
-
const handleTouchMove = (0,
|
|
6537
|
+
const handleTouchMove = (0, import_react19.useCallback)(
|
|
5964
6538
|
(event) => {
|
|
5965
6539
|
if (!dragStartRef.current || event.touches.length !== 1) return;
|
|
5966
6540
|
const touch = event.touches[0];
|
|
@@ -6003,7 +6577,7 @@ function useDrag(options = {}) {
|
|
|
6003
6577
|
},
|
|
6004
6578
|
[screenToWorld, dragThreshold, applySnap, onDragStart, onDragMove]
|
|
6005
6579
|
);
|
|
6006
|
-
const handleTouchEnd = (0,
|
|
6580
|
+
const handleTouchEnd = (0, import_react19.useCallback)(
|
|
6007
6581
|
(event) => {
|
|
6008
6582
|
if (!dragStartRef.current || !hasMovedRef.current) {
|
|
6009
6583
|
dragStartRef.current = null;
|
|
@@ -6041,7 +6615,7 @@ function useDrag(options = {}) {
|
|
|
6041
6615
|
},
|
|
6042
6616
|
[screenToWorld, applySnap, onDragEnd]
|
|
6043
6617
|
);
|
|
6044
|
-
(0,
|
|
6618
|
+
(0, import_react19.useEffect)(() => {
|
|
6045
6619
|
if (!isListening) return;
|
|
6046
6620
|
document.addEventListener("mousemove", handleMouseMove);
|
|
6047
6621
|
document.addEventListener("mouseup", handleMouseUp);
|
|
@@ -6056,7 +6630,7 @@ function useDrag(options = {}) {
|
|
|
6056
6630
|
document.removeEventListener("touchcancel", handleTouchEnd);
|
|
6057
6631
|
};
|
|
6058
6632
|
}, [isListening, handleMouseMove, handleMouseUp, handleTouchMove, handleTouchEnd]);
|
|
6059
|
-
const startDrag = (0,
|
|
6633
|
+
const startDrag = (0, import_react19.useCallback)(
|
|
6060
6634
|
(id, event, itemPosition) => {
|
|
6061
6635
|
event.stopPropagation();
|
|
6062
6636
|
let clientX;
|
|
@@ -6086,7 +6660,7 @@ function useDrag(options = {}) {
|
|
|
6086
6660
|
},
|
|
6087
6661
|
[screenToWorld]
|
|
6088
6662
|
);
|
|
6089
|
-
const cancelDrag = (0,
|
|
6663
|
+
const cancelDrag = (0, import_react19.useCallback)(() => {
|
|
6090
6664
|
dragStartRef.current = null;
|
|
6091
6665
|
hasMovedRef.current = false;
|
|
6092
6666
|
setIsListening(false);
|
|
@@ -6097,7 +6671,7 @@ function useDrag(options = {}) {
|
|
|
6097
6671
|
draggedId: null
|
|
6098
6672
|
});
|
|
6099
6673
|
}, []);
|
|
6100
|
-
const isDraggingItem = (0,
|
|
6674
|
+
const isDraggingItem = (0, import_react19.useCallback)(
|
|
6101
6675
|
(id) => dragState.isDragging && dragState.draggedId === id,
|
|
6102
6676
|
[dragState.isDragging, dragState.draggedId]
|
|
6103
6677
|
);
|
|
@@ -6110,7 +6684,7 @@ function useDrag(options = {}) {
|
|
|
6110
6684
|
}
|
|
6111
6685
|
|
|
6112
6686
|
// src/diagram/hooks/useKeyboardShortcuts.ts
|
|
6113
|
-
var
|
|
6687
|
+
var import_react20 = require("react");
|
|
6114
6688
|
function useKeyboardShortcuts(options) {
|
|
6115
6689
|
const {
|
|
6116
6690
|
onDelete,
|
|
@@ -6121,7 +6695,7 @@ function useKeyboardShortcuts(options) {
|
|
|
6121
6695
|
onSelectAll,
|
|
6122
6696
|
enabled = true
|
|
6123
6697
|
} = options;
|
|
6124
|
-
(0,
|
|
6698
|
+
(0, import_react20.useEffect)(() => {
|
|
6125
6699
|
if (!enabled) return;
|
|
6126
6700
|
const handleKeyDown = (event) => {
|
|
6127
6701
|
const target = event.target;
|
|
@@ -6259,21 +6833,21 @@ function PIDCanvasImpl({
|
|
|
6259
6833
|
statusColorMap,
|
|
6260
6834
|
...props
|
|
6261
6835
|
}) {
|
|
6262
|
-
const [localDiagram, setLocalDiagram] = (0,
|
|
6263
|
-
const [dragOverPosition, setDragOverPosition] = (0,
|
|
6264
|
-
const [isConnecting, setIsConnecting] = (0,
|
|
6265
|
-
const [connectionSource, setConnectionSource] = (0,
|
|
6266
|
-
const [connectionSourcePort, setConnectionSourcePort] = (0,
|
|
6267
|
-
const [connectionCursor, setConnectionCursor] = (0,
|
|
6268
|
-
const [hoveredNode, setHoveredNode] = (0,
|
|
6269
|
-
const [hoveredPort, setHoveredPort] = (0,
|
|
6270
|
-
const [selectedWaypoint, setSelectedWaypoint] = (0,
|
|
6271
|
-
const historyStack = (0,
|
|
6272
|
-
const redoStack = (0,
|
|
6273
|
-
const isUndoRedoAction = (0,
|
|
6274
|
-
const isInternalChange = (0,
|
|
6275
|
-
const lastInternalDiagram = (0,
|
|
6276
|
-
(0,
|
|
6836
|
+
const [localDiagram, setLocalDiagram] = (0, import_react21.useState)(diagram);
|
|
6837
|
+
const [dragOverPosition, setDragOverPosition] = (0, import_react21.useState)(null);
|
|
6838
|
+
const [isConnecting, setIsConnecting] = (0, import_react21.useState)(false);
|
|
6839
|
+
const [connectionSource, setConnectionSource] = (0, import_react21.useState)(null);
|
|
6840
|
+
const [connectionSourcePort, setConnectionSourcePort] = (0, import_react21.useState)(null);
|
|
6841
|
+
const [connectionCursor, setConnectionCursor] = (0, import_react21.useState)(null);
|
|
6842
|
+
const [hoveredNode, setHoveredNode] = (0, import_react21.useState)(null);
|
|
6843
|
+
const [hoveredPort, setHoveredPort] = (0, import_react21.useState)(null);
|
|
6844
|
+
const [selectedWaypoint, setSelectedWaypoint] = (0, import_react21.useState)(null);
|
|
6845
|
+
const historyStack = (0, import_react21.useRef)([]);
|
|
6846
|
+
const redoStack = (0, import_react21.useRef)([]);
|
|
6847
|
+
const isUndoRedoAction = (0, import_react21.useRef)(false);
|
|
6848
|
+
const isInternalChange = (0, import_react21.useRef)(false);
|
|
6849
|
+
const lastInternalDiagram = (0, import_react21.useRef)(null);
|
|
6850
|
+
(0, import_react21.useEffect)(() => {
|
|
6277
6851
|
const isExternal = !isInternalChange.current && diagram !== lastInternalDiagram.current;
|
|
6278
6852
|
if (isExternal) {
|
|
6279
6853
|
setLocalDiagram(diagram);
|
|
@@ -6295,7 +6869,7 @@ function PIDCanvasImpl({
|
|
|
6295
6869
|
enablePan: features.pan ?? true,
|
|
6296
6870
|
enableZoom: features.zoom ?? true
|
|
6297
6871
|
});
|
|
6298
|
-
const calculateContentBounds = (0,
|
|
6872
|
+
const calculateContentBounds = (0, import_react21.useCallback)(() => {
|
|
6299
6873
|
const nodes2 = localDiagram.nodes.filter((n) => n.visible !== false);
|
|
6300
6874
|
if (nodes2.length === 0) {
|
|
6301
6875
|
return null;
|
|
@@ -6318,7 +6892,7 @@ function PIDCanvasImpl({
|
|
|
6318
6892
|
});
|
|
6319
6893
|
return { minX, minY, maxX, maxY };
|
|
6320
6894
|
}, [localDiagram.nodes]);
|
|
6321
|
-
(0,
|
|
6895
|
+
(0, import_react21.useEffect)(() => {
|
|
6322
6896
|
if (onMounted) {
|
|
6323
6897
|
const controls = {
|
|
6324
6898
|
fitToContent: (padding = 50) => {
|
|
@@ -6359,8 +6933,8 @@ function PIDCanvasImpl({
|
|
|
6359
6933
|
});
|
|
6360
6934
|
const dragEnabled = features.dragNodes ?? false;
|
|
6361
6935
|
const selectionEnabled = features.selection ?? false;
|
|
6362
|
-
const containerRef = (0,
|
|
6363
|
-
const pushToHistory = (0,
|
|
6936
|
+
const containerRef = (0, import_react21.useRef)(null);
|
|
6937
|
+
const pushToHistory = (0, import_react21.useCallback)((currentDiagram) => {
|
|
6364
6938
|
if (isUndoRedoAction.current) return;
|
|
6365
6939
|
const snapshot = JSON.parse(JSON.stringify(currentDiagram));
|
|
6366
6940
|
historyStack.current.push(snapshot);
|
|
@@ -6369,7 +6943,7 @@ function PIDCanvasImpl({
|
|
|
6369
6943
|
}
|
|
6370
6944
|
redoStack.current = [];
|
|
6371
6945
|
}, []);
|
|
6372
|
-
const undo = (0,
|
|
6946
|
+
const undo = (0, import_react21.useCallback)(() => {
|
|
6373
6947
|
if (historyStack.current.length === 0) return;
|
|
6374
6948
|
isUndoRedoAction.current = true;
|
|
6375
6949
|
const currentSnapshot = JSON.parse(JSON.stringify(localDiagram));
|
|
@@ -6383,7 +6957,7 @@ function PIDCanvasImpl({
|
|
|
6383
6957
|
isUndoRedoAction.current = false;
|
|
6384
6958
|
}, 0);
|
|
6385
6959
|
}, [localDiagram, onDiagramChange]);
|
|
6386
|
-
const redo = (0,
|
|
6960
|
+
const redo = (0, import_react21.useCallback)(() => {
|
|
6387
6961
|
if (redoStack.current.length === 0) return;
|
|
6388
6962
|
isUndoRedoAction.current = true;
|
|
6389
6963
|
const currentSnapshot = JSON.parse(JSON.stringify(localDiagram));
|
|
@@ -6397,7 +6971,7 @@ function PIDCanvasImpl({
|
|
|
6397
6971
|
isUndoRedoAction.current = false;
|
|
6398
6972
|
}, 0);
|
|
6399
6973
|
}, [localDiagram, onDiagramChange]);
|
|
6400
|
-
(0,
|
|
6974
|
+
(0, import_react21.useEffect)(() => {
|
|
6401
6975
|
const handleKeyDown = (e) => {
|
|
6402
6976
|
const isCtrlOrCmd = e.ctrlKey || e.metaKey;
|
|
6403
6977
|
if (isCtrlOrCmd && e.key === "z" && !e.shiftKey) {
|
|
@@ -6414,7 +6988,7 @@ function PIDCanvasImpl({
|
|
|
6414
6988
|
window.addEventListener("keydown", handleKeyDown);
|
|
6415
6989
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
6416
6990
|
}, [undo, redo]);
|
|
6417
|
-
(0,
|
|
6991
|
+
(0, import_react21.useEffect)(() => {
|
|
6418
6992
|
if (!features.dragNodes) return;
|
|
6419
6993
|
const handleKeyDown = (e) => {
|
|
6420
6994
|
if (selection.selectedNodeIds.size === 0 && !selectedWaypoint) return;
|
|
@@ -6499,7 +7073,7 @@ function PIDCanvasImpl({
|
|
|
6499
7073
|
onNodeMove,
|
|
6500
7074
|
pushToHistory
|
|
6501
7075
|
]);
|
|
6502
|
-
const handlePositionChange = (0,
|
|
7076
|
+
const handlePositionChange = (0, import_react21.useCallback)(
|
|
6503
7077
|
(nodeId, x, y) => {
|
|
6504
7078
|
pushToHistory(localDiagram);
|
|
6505
7079
|
const updatedNodes = localDiagram.nodes.map(
|
|
@@ -6521,7 +7095,7 @@ function PIDCanvasImpl({
|
|
|
6521
7095
|
},
|
|
6522
7096
|
[localDiagram, onDiagramChange, onNodeMove, pushToHistory]
|
|
6523
7097
|
);
|
|
6524
|
-
const handleWaypointPositionChange = (0,
|
|
7098
|
+
const handleWaypointPositionChange = (0, import_react21.useCallback)(
|
|
6525
7099
|
(pipeId, pointIndex, x, y) => {
|
|
6526
7100
|
pushToHistory(localDiagram);
|
|
6527
7101
|
const updatedPipes = localDiagram.pipes.map((pipe) => {
|
|
@@ -6539,7 +7113,7 @@ function PIDCanvasImpl({
|
|
|
6539
7113
|
},
|
|
6540
7114
|
[localDiagram, onDiagramChange, pushToHistory]
|
|
6541
7115
|
);
|
|
6542
|
-
const handleDragEnd = (0,
|
|
7116
|
+
const handleDragEnd = (0, import_react21.useCallback)(
|
|
6543
7117
|
(nodeId, offset, finalPosition) => {
|
|
6544
7118
|
const dragDistance = Math.sqrt(offset.x ** 2 + offset.y ** 2);
|
|
6545
7119
|
if (dragDistance < 2) {
|
|
@@ -6620,7 +7194,7 @@ function PIDCanvasImpl({
|
|
|
6620
7194
|
onDiagramChange?.(updatedDiagram);
|
|
6621
7195
|
}
|
|
6622
7196
|
});
|
|
6623
|
-
const handleNodeDragStart = (0,
|
|
7197
|
+
const handleNodeDragStart = (0, import_react21.useCallback)(
|
|
6624
7198
|
(nodeId, event) => {
|
|
6625
7199
|
const node = localDiagram.nodes.find((n) => n.id === nodeId);
|
|
6626
7200
|
if (!node) return;
|
|
@@ -6628,7 +7202,7 @@ function PIDCanvasImpl({
|
|
|
6628
7202
|
},
|
|
6629
7203
|
[localDiagram.nodes, startDrag]
|
|
6630
7204
|
);
|
|
6631
|
-
const handleWaypointClick = (0,
|
|
7205
|
+
const handleWaypointClick = (0, import_react21.useCallback)(
|
|
6632
7206
|
(pipeId, pointIndex) => {
|
|
6633
7207
|
setSelectedWaypoint({ pipeId, pointIndex });
|
|
6634
7208
|
if (selectionEnabled) {
|
|
@@ -6637,7 +7211,7 @@ function PIDCanvasImpl({
|
|
|
6637
7211
|
},
|
|
6638
7212
|
[selectionEnabled, clearSelection]
|
|
6639
7213
|
);
|
|
6640
|
-
const handleWaypointDragStart = (0,
|
|
7214
|
+
const handleWaypointDragStart = (0, import_react21.useCallback)(
|
|
6641
7215
|
(pipeId, pointIndex, event) => {
|
|
6642
7216
|
const pipe = localDiagram.pipes.find((p) => p.id === pipeId);
|
|
6643
7217
|
if (!pipe || pointIndex >= pipe.routePoints.length) return;
|
|
@@ -6646,7 +7220,7 @@ function PIDCanvasImpl({
|
|
|
6646
7220
|
},
|
|
6647
7221
|
[localDiagram.pipes, startWaypointDrag]
|
|
6648
7222
|
);
|
|
6649
|
-
const handlePipeSegmentClick = (0,
|
|
7223
|
+
const handlePipeSegmentClick = (0, import_react21.useCallback)(
|
|
6650
7224
|
(pipeId, position, segmentIndex) => {
|
|
6651
7225
|
pushToHistory(localDiagram);
|
|
6652
7226
|
const updatedPipes = localDiagram.pipes.map((pipe) => {
|
|
@@ -6665,7 +7239,7 @@ function PIDCanvasImpl({
|
|
|
6665
7239
|
[localDiagram, onDiagramChange, pushToHistory]
|
|
6666
7240
|
);
|
|
6667
7241
|
const telemetryEnabled = features.telemetry ?? false;
|
|
6668
|
-
const handleDelete = (0,
|
|
7242
|
+
const handleDelete = (0, import_react21.useCallback)(() => {
|
|
6669
7243
|
if (!selectionEnabled) return;
|
|
6670
7244
|
const { selectedNodeIds, selectedPipeIds } = selection;
|
|
6671
7245
|
if (selectedNodeIds.size === 0 && selectedPipeIds.size === 0) return;
|
|
@@ -6694,17 +7268,17 @@ function PIDCanvasImpl({
|
|
|
6694
7268
|
onDelete,
|
|
6695
7269
|
pushToHistory
|
|
6696
7270
|
]);
|
|
6697
|
-
const handleCopy = (0,
|
|
7271
|
+
const handleCopy = (0, import_react21.useCallback)(() => {
|
|
6698
7272
|
if (!selectionEnabled) return;
|
|
6699
7273
|
const { selectedNodeIds, selectedPipeIds } = selection;
|
|
6700
7274
|
if (selectedNodeIds.size === 0 && selectedPipeIds.size === 0) return;
|
|
6701
7275
|
onItemsCopied?.(Array.from(selectedNodeIds), Array.from(selectedPipeIds));
|
|
6702
7276
|
}, [selection, selectionEnabled, onItemsCopied]);
|
|
6703
|
-
const handlePaste = (0,
|
|
7277
|
+
const handlePaste = (0, import_react21.useCallback)(() => {
|
|
6704
7278
|
if (!selectionEnabled) return;
|
|
6705
7279
|
onPaste?.();
|
|
6706
7280
|
}, [selectionEnabled, onPaste]);
|
|
6707
|
-
const handleNodeDoubleClick = (0,
|
|
7281
|
+
const handleNodeDoubleClick = (0, import_react21.useCallback)(
|
|
6708
7282
|
(nodeId, event) => {
|
|
6709
7283
|
if (!selectionEnabled) return;
|
|
6710
7284
|
console.log("Node double-clicked:", nodeId);
|
|
@@ -6718,7 +7292,7 @@ function PIDCanvasImpl({
|
|
|
6718
7292
|
onCopy: handleCopy,
|
|
6719
7293
|
onPaste: handlePaste
|
|
6720
7294
|
});
|
|
6721
|
-
const handleNodeClick = (0,
|
|
7295
|
+
const handleNodeClick = (0, import_react21.useCallback)(
|
|
6722
7296
|
(nodeId, event) => {
|
|
6723
7297
|
const connectionModeEnabled = features.connectionMode ?? false;
|
|
6724
7298
|
if (connectionModeEnabled && isConnecting) {
|
|
@@ -6760,7 +7334,7 @@ function PIDCanvasImpl({
|
|
|
6760
7334
|
onNodeClick
|
|
6761
7335
|
]
|
|
6762
7336
|
);
|
|
6763
|
-
const handlePipeClick = (0,
|
|
7337
|
+
const handlePipeClick = (0, import_react21.useCallback)(
|
|
6764
7338
|
(pipeId, event) => {
|
|
6765
7339
|
if (selectionEnabled) {
|
|
6766
7340
|
selectPipe(pipeId, event.ctrlKey || event.metaKey);
|
|
@@ -6779,7 +7353,7 @@ function PIDCanvasImpl({
|
|
|
6779
7353
|
}
|
|
6780
7354
|
setSelectedWaypoint(null);
|
|
6781
7355
|
};
|
|
6782
|
-
const handleDragOver = (0,
|
|
7356
|
+
const handleDragOver = (0, import_react21.useCallback)(
|
|
6783
7357
|
(event) => {
|
|
6784
7358
|
if (!features.allowSymbolDrop) return;
|
|
6785
7359
|
event.preventDefault();
|
|
@@ -6790,7 +7364,7 @@ function PIDCanvasImpl({
|
|
|
6790
7364
|
},
|
|
6791
7365
|
[features.allowSymbolDrop, screenToWorld, svgRef]
|
|
6792
7366
|
);
|
|
6793
|
-
const handleDrop = (0,
|
|
7367
|
+
const handleDrop = (0, import_react21.useCallback)(
|
|
6794
7368
|
(event) => {
|
|
6795
7369
|
if (!features.allowSymbolDrop) return;
|
|
6796
7370
|
event.preventDefault();
|
|
@@ -6803,10 +7377,10 @@ function PIDCanvasImpl({
|
|
|
6803
7377
|
},
|
|
6804
7378
|
[features.allowSymbolDrop, screenToWorld, onSymbolDrop, svgRef]
|
|
6805
7379
|
);
|
|
6806
|
-
const handleDragLeave = (0,
|
|
7380
|
+
const handleDragLeave = (0, import_react21.useCallback)(() => {
|
|
6807
7381
|
setDragOverPosition(null);
|
|
6808
7382
|
}, []);
|
|
6809
|
-
const handleMouseMove = (0,
|
|
7383
|
+
const handleMouseMove = (0, import_react21.useCallback)(
|
|
6810
7384
|
(event) => {
|
|
6811
7385
|
const connectionModeEnabled = features.connectionMode ?? false;
|
|
6812
7386
|
if (connectionModeEnabled) {
|
|
@@ -6951,6 +7525,7 @@ function PIDCanvasImpl({
|
|
|
6951
7525
|
}
|
|
6952
7526
|
),
|
|
6953
7527
|
telemetryEnabled && telemetry && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("g", { id: "layer-telemetry", children: displayDiagram.nodes.map((node) => {
|
|
7528
|
+
if (node.symbolId === "status-indicator") return null;
|
|
6954
7529
|
const binding = telemetry.get(node.id);
|
|
6955
7530
|
if (!binding) return null;
|
|
6956
7531
|
const symbol = getSymbolDefinition(node.symbolId);
|
|
@@ -7116,10 +7691,10 @@ function PIDCanvasImpl({
|
|
|
7116
7691
|
}
|
|
7117
7692
|
);
|
|
7118
7693
|
}
|
|
7119
|
-
var PIDCanvas =
|
|
7694
|
+
var PIDCanvas = import_react21.default.memo(PIDCanvasImpl);
|
|
7120
7695
|
|
|
7121
7696
|
// src/components/SymbolLibrary/SymbolLibrary.tsx
|
|
7122
|
-
var
|
|
7697
|
+
var import_react22 = require("react");
|
|
7123
7698
|
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
7124
7699
|
function SymbolLibrary({
|
|
7125
7700
|
className = "",
|
|
@@ -7127,8 +7702,8 @@ function SymbolLibrary({
|
|
|
7127
7702
|
showCategories = true,
|
|
7128
7703
|
categories = ["Valves", "Pumps", "Tanks", "Instruments", "Displays"]
|
|
7129
7704
|
}) {
|
|
7130
|
-
const [selectedCategory, setSelectedCategory] = (0,
|
|
7131
|
-
const [searchQuery, setSearchQuery] = (0,
|
|
7705
|
+
const [selectedCategory, setSelectedCategory] = (0, import_react22.useState)("all");
|
|
7706
|
+
const [searchQuery, setSearchQuery] = (0, import_react22.useState)("");
|
|
7132
7707
|
const symbolIds = getAvailableSymbols();
|
|
7133
7708
|
const allSymbols = symbolIds.map((id) => getSymbolDefinition(id)).filter((symbol) => symbol !== void 0);
|
|
7134
7709
|
const categoryMap = {
|
|
@@ -7318,6 +7893,8 @@ function NodeConfigPanel({
|
|
|
7318
7893
|
onUpdateNode,
|
|
7319
7894
|
onUpdateTelemetry,
|
|
7320
7895
|
onAddTelemetry,
|
|
7896
|
+
onRemoveTelemetry,
|
|
7897
|
+
availableTags = [],
|
|
7321
7898
|
onRemove,
|
|
7322
7899
|
className = "",
|
|
7323
7900
|
style = {}
|
|
@@ -7330,6 +7907,8 @@ function NodeConfigPanel({
|
|
|
7330
7907
|
padding: "20px",
|
|
7331
7908
|
...style
|
|
7332
7909
|
};
|
|
7910
|
+
const appearanceFields = getAppearanceSchema(node.symbolId);
|
|
7911
|
+
const showGenericTelemetry = appearanceFields.length === 0;
|
|
7333
7912
|
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className, style: defaultStyle, children: [
|
|
7334
7913
|
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("h2", { style: { margin: "0 0 16px 0", fontSize: "1rem", fontWeight: 600 }, children: [
|
|
7335
7914
|
"Configure: ",
|
|
@@ -7451,7 +8030,136 @@ function NodeConfigPanel({
|
|
|
7451
8030
|
)
|
|
7452
8031
|
] })
|
|
7453
8032
|
] }),
|
|
7454
|
-
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { marginBottom: "20px" }, children: [
|
|
8033
|
+
appearanceFields.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { marginBottom: "20px" }, children: [
|
|
8034
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Appearance" }),
|
|
8035
|
+
appearanceFields.map((field) => {
|
|
8036
|
+
const value = readAppearanceValue(node, field);
|
|
8037
|
+
const fieldLabel = field.label ?? field.key;
|
|
8038
|
+
const inputStyle = {
|
|
8039
|
+
width: "100%",
|
|
8040
|
+
padding: "6px 8px",
|
|
8041
|
+
borderRadius: "4px",
|
|
8042
|
+
border: "1px solid #cbd5e1",
|
|
8043
|
+
fontSize: "0.875rem"
|
|
8044
|
+
};
|
|
8045
|
+
let control;
|
|
8046
|
+
if (field.kind === "boolean") {
|
|
8047
|
+
control = /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { style: { fontSize: "0.75rem", display: "block" }, children: [
|
|
8048
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
8049
|
+
"input",
|
|
8050
|
+
{
|
|
8051
|
+
type: "checkbox",
|
|
8052
|
+
checked: Boolean(value),
|
|
8053
|
+
onChange: (e) => onUpdateNode(writeAppearanceValue(node, field, e.target.checked)),
|
|
8054
|
+
style: { marginRight: "6px" }
|
|
8055
|
+
}
|
|
8056
|
+
),
|
|
8057
|
+
fieldLabel
|
|
8058
|
+
] });
|
|
8059
|
+
} else if (field.kind === "select") {
|
|
8060
|
+
control = /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
|
|
8061
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
|
|
8062
|
+
fieldLabel,
|
|
8063
|
+
":"
|
|
8064
|
+
] }),
|
|
8065
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
8066
|
+
"select",
|
|
8067
|
+
{
|
|
8068
|
+
value: String(value),
|
|
8069
|
+
onChange: (e) => onUpdateNode(writeAppearanceValue(node, field, e.target.value)),
|
|
8070
|
+
style: inputStyle,
|
|
8071
|
+
children: field.options?.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("option", { value: opt, children: opt }, opt))
|
|
8072
|
+
}
|
|
8073
|
+
)
|
|
8074
|
+
] });
|
|
8075
|
+
} else if (field.kind === "number") {
|
|
8076
|
+
control = /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
|
|
8077
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
|
|
8078
|
+
fieldLabel,
|
|
8079
|
+
":"
|
|
8080
|
+
] }),
|
|
8081
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
8082
|
+
"input",
|
|
8083
|
+
{
|
|
8084
|
+
type: "number",
|
|
8085
|
+
value: Number(value),
|
|
8086
|
+
onChange: (e) => onUpdateNode(writeAppearanceValue(node, field, parseFloat(e.target.value) || 0)),
|
|
8087
|
+
style: inputStyle
|
|
8088
|
+
}
|
|
8089
|
+
)
|
|
8090
|
+
] });
|
|
8091
|
+
} else if (field.kind === "tag") {
|
|
8092
|
+
const tagValue = String(value);
|
|
8093
|
+
const listId = `tags-${node.id}-${field.key}`;
|
|
8094
|
+
const known = tagValue.length > 0 && availableTags.includes(tagValue);
|
|
8095
|
+
const unknown = tagValue.length > 0 && !known;
|
|
8096
|
+
control = /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
|
|
8097
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
|
|
8098
|
+
fieldLabel,
|
|
8099
|
+
":"
|
|
8100
|
+
] }),
|
|
8101
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
8102
|
+
"input",
|
|
8103
|
+
{
|
|
8104
|
+
type: "text",
|
|
8105
|
+
value: tagValue,
|
|
8106
|
+
list: listId,
|
|
8107
|
+
onChange: (e) => onUpdateNode(writeAppearanceValue(node, field, e.target.value)),
|
|
8108
|
+
placeholder: "type or pick a signal\u2026",
|
|
8109
|
+
style: {
|
|
8110
|
+
...inputStyle,
|
|
8111
|
+
border: `1px solid ${unknown ? "#f59e0b" : known ? "#22c55e" : "#cbd5e1"}`
|
|
8112
|
+
}
|
|
8113
|
+
}
|
|
8114
|
+
),
|
|
8115
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("datalist", { id: listId, children: availableTags.map((t) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("option", { value: t }, t)) }),
|
|
8116
|
+
tagValue.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
8117
|
+
"div",
|
|
8118
|
+
{
|
|
8119
|
+
style: {
|
|
8120
|
+
fontSize: "0.7rem",
|
|
8121
|
+
marginTop: "3px",
|
|
8122
|
+
color: known ? "#16a34a" : "#b45309"
|
|
8123
|
+
},
|
|
8124
|
+
children: known ? "\u2713 matched signal" : "\u26A0 no matching signal (reads as false until published)"
|
|
8125
|
+
}
|
|
8126
|
+
)
|
|
8127
|
+
] });
|
|
8128
|
+
} else {
|
|
8129
|
+
control = /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
|
|
8130
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
|
|
8131
|
+
fieldLabel,
|
|
8132
|
+
":"
|
|
8133
|
+
] }),
|
|
8134
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
8135
|
+
"input",
|
|
8136
|
+
{
|
|
8137
|
+
type: "text",
|
|
8138
|
+
value: String(value),
|
|
8139
|
+
onChange: (e) => onUpdateNode(writeAppearanceValue(node, field, e.target.value)),
|
|
8140
|
+
style: inputStyle
|
|
8141
|
+
}
|
|
8142
|
+
)
|
|
8143
|
+
] });
|
|
8144
|
+
}
|
|
8145
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { marginBottom: "10px" }, children: [
|
|
8146
|
+
control,
|
|
8147
|
+
field.help && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
8148
|
+
"div",
|
|
8149
|
+
{
|
|
8150
|
+
style: {
|
|
8151
|
+
fontSize: "0.7rem",
|
|
8152
|
+
color: "#64748b",
|
|
8153
|
+
marginTop: "3px",
|
|
8154
|
+
lineHeight: 1.35
|
|
8155
|
+
},
|
|
8156
|
+
children: field.help
|
|
8157
|
+
}
|
|
8158
|
+
)
|
|
8159
|
+
] }, field.key);
|
|
8160
|
+
})
|
|
8161
|
+
] }),
|
|
8162
|
+
showGenericTelemetry && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { marginBottom: "20px" }, children: [
|
|
7455
8163
|
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Telemetry Data" }),
|
|
7456
8164
|
!binding ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
7457
8165
|
"button",
|
|
@@ -7497,6 +8205,27 @@ function NodeConfigPanel({
|
|
|
7497
8205
|
children: "+ Add Telemetry"
|
|
7498
8206
|
}
|
|
7499
8207
|
) : /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
|
|
8208
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Tag (attribute):" }),
|
|
8209
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
8210
|
+
"input",
|
|
8211
|
+
{
|
|
8212
|
+
type: "text",
|
|
8213
|
+
value: binding.tag || "",
|
|
8214
|
+
onChange: (e) => onUpdateTelemetry({
|
|
8215
|
+
nodeId: node.id,
|
|
8216
|
+
tag: e.target.value
|
|
8217
|
+
}),
|
|
8218
|
+
placeholder: "e.g. pump.running",
|
|
8219
|
+
style: {
|
|
8220
|
+
width: "100%",
|
|
8221
|
+
padding: "6px 8px",
|
|
8222
|
+
borderRadius: "4px",
|
|
8223
|
+
border: "1px solid #cbd5e1",
|
|
8224
|
+
fontSize: "0.875rem",
|
|
8225
|
+
marginBottom: "8px"
|
|
8226
|
+
}
|
|
8227
|
+
}
|
|
8228
|
+
),
|
|
7500
8229
|
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Initial Value:" }),
|
|
7501
8230
|
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
7502
8231
|
"input",
|
|
@@ -7804,10 +8533,28 @@ function NodeConfigPanel({
|
|
|
7804
8533
|
] })
|
|
7805
8534
|
] }),
|
|
7806
8535
|
" "
|
|
7807
|
-
] })
|
|
8536
|
+
] }),
|
|
8537
|
+
onRemoveTelemetry && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
8538
|
+
"button",
|
|
8539
|
+
{
|
|
8540
|
+
onClick: onRemoveTelemetry,
|
|
8541
|
+
style: {
|
|
8542
|
+
width: "100%",
|
|
8543
|
+
padding: "6px 8px",
|
|
8544
|
+
marginTop: "8px",
|
|
8545
|
+
borderRadius: "4px",
|
|
8546
|
+
border: "1px solid #ef4444",
|
|
8547
|
+
background: "transparent",
|
|
8548
|
+
color: "#ef4444",
|
|
8549
|
+
fontSize: "0.8125rem",
|
|
8550
|
+
cursor: "pointer"
|
|
8551
|
+
},
|
|
8552
|
+
children: "Remove Telemetry"
|
|
8553
|
+
}
|
|
8554
|
+
)
|
|
7808
8555
|
] })
|
|
7809
8556
|
] }),
|
|
7810
|
-
binding && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { marginBottom: "20px" }, children: [
|
|
8557
|
+
showGenericTelemetry && binding && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { marginBottom: "20px" }, children: [
|
|
7811
8558
|
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Thresholds" }),
|
|
7812
8559
|
["highHigh", "high", "low", "lowLow"].map((key) => {
|
|
7813
8560
|
const label = key === "highHigh" ? "High-High (\u2265)" : key === "high" ? "High (\u2265)" : key === "low" ? "Low (\u2264)" : "Low-Low (\u2264)";
|
|
@@ -7837,7 +8584,7 @@ function NodeConfigPanel({
|
|
|
7837
8584
|
] }, key);
|
|
7838
8585
|
})
|
|
7839
8586
|
] }),
|
|
7840
|
-
binding && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { marginBottom: "20px" }, children: [
|
|
8587
|
+
showGenericTelemetry && binding && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { marginBottom: "20px" }, children: [
|
|
7841
8588
|
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Status Colors" }),
|
|
7842
8589
|
["normal", "warning", "alarm", "fault", "off"].map((status) => {
|
|
7843
8590
|
const defaultColors = {
|
|
@@ -8179,13 +8926,13 @@ function createControlBinding(nodeId, deviceConfig, actions) {
|
|
|
8179
8926
|
}
|
|
8180
8927
|
|
|
8181
8928
|
// src/hooks/useDeviceControls.ts
|
|
8182
|
-
var
|
|
8929
|
+
var import_react23 = require("react");
|
|
8183
8930
|
function commandKey(nodeId, kind, suffix) {
|
|
8184
8931
|
return suffix ? `${nodeId}:${kind}:${suffix}` : `${nodeId}:${kind}`;
|
|
8185
8932
|
}
|
|
8186
8933
|
function useDeviceControls(initialBindings, options) {
|
|
8187
8934
|
const { commandTimeoutMs } = options ?? {};
|
|
8188
|
-
const [controls, setControls] = (0,
|
|
8935
|
+
const [controls, setControls] = (0, import_react23.useState)(() => {
|
|
8189
8936
|
const map = /* @__PURE__ */ new Map();
|
|
8190
8937
|
if (initialBindings) {
|
|
8191
8938
|
initialBindings.forEach((binding) => {
|
|
@@ -8194,12 +8941,12 @@ function useDeviceControls(initialBindings, options) {
|
|
|
8194
8941
|
}
|
|
8195
8942
|
return map;
|
|
8196
8943
|
});
|
|
8197
|
-
const pendingRef = (0,
|
|
8198
|
-
const [pendingCommands, setPendingCommands] = (0,
|
|
8199
|
-
const syncPending = (0,
|
|
8944
|
+
const pendingRef = (0, import_react23.useRef)(/* @__PURE__ */ new Map());
|
|
8945
|
+
const [pendingCommands, setPendingCommands] = (0, import_react23.useState)(() => /* @__PURE__ */ new Set());
|
|
8946
|
+
const syncPending = (0, import_react23.useCallback)(() => {
|
|
8200
8947
|
setPendingCommands(new Set(pendingRef.current.keys()));
|
|
8201
8948
|
}, []);
|
|
8202
|
-
const updateControl = (0,
|
|
8949
|
+
const updateControl = (0, import_react23.useCallback)((nodeId, updates) => {
|
|
8203
8950
|
setControls((prev) => {
|
|
8204
8951
|
const newMap = new Map(prev);
|
|
8205
8952
|
const existing = newMap.get(nodeId);
|
|
@@ -8213,7 +8960,7 @@ function useDeviceControls(initialBindings, options) {
|
|
|
8213
8960
|
return newMap;
|
|
8214
8961
|
});
|
|
8215
8962
|
}, []);
|
|
8216
|
-
const updateControlBatch = (0,
|
|
8963
|
+
const updateControlBatch = (0, import_react23.useCallback)((updates) => {
|
|
8217
8964
|
setControls((prev) => {
|
|
8218
8965
|
const newMap = new Map(prev);
|
|
8219
8966
|
Object.entries(updates).forEach(([nodeId, update]) => {
|
|
@@ -8225,7 +8972,7 @@ function useDeviceControls(initialBindings, options) {
|
|
|
8225
8972
|
return newMap;
|
|
8226
8973
|
});
|
|
8227
8974
|
}, []);
|
|
8228
|
-
const updateDeviceState = (0,
|
|
8975
|
+
const updateDeviceState = (0, import_react23.useCallback)(
|
|
8229
8976
|
(nodeId, stateUpdates) => {
|
|
8230
8977
|
setControls((prev) => {
|
|
8231
8978
|
const newMap = new Map(prev);
|
|
@@ -8241,7 +8988,7 @@ function useDeviceControls(initialBindings, options) {
|
|
|
8241
8988
|
},
|
|
8242
8989
|
[]
|
|
8243
8990
|
);
|
|
8244
|
-
const updateParameter = (0,
|
|
8991
|
+
const updateParameter = (0, import_react23.useCallback)(
|
|
8245
8992
|
(nodeId, parameterId, value) => {
|
|
8246
8993
|
setControls((prev) => {
|
|
8247
8994
|
const newMap = new Map(prev);
|
|
@@ -8268,27 +9015,27 @@ function useDeviceControls(initialBindings, options) {
|
|
|
8268
9015
|
},
|
|
8269
9016
|
[]
|
|
8270
9017
|
);
|
|
8271
|
-
const setControlBinding = (0,
|
|
9018
|
+
const setControlBinding = (0, import_react23.useCallback)((binding) => {
|
|
8272
9019
|
setControls((prev) => {
|
|
8273
9020
|
const newMap = new Map(prev);
|
|
8274
9021
|
newMap.set(binding.nodeId, binding);
|
|
8275
9022
|
return newMap;
|
|
8276
9023
|
});
|
|
8277
9024
|
}, []);
|
|
8278
|
-
const removeControlBinding = (0,
|
|
9025
|
+
const removeControlBinding = (0, import_react23.useCallback)((nodeId) => {
|
|
8279
9026
|
setControls((prev) => {
|
|
8280
9027
|
const newMap = new Map(prev);
|
|
8281
9028
|
newMap.delete(nodeId);
|
|
8282
9029
|
return newMap;
|
|
8283
9030
|
});
|
|
8284
9031
|
}, []);
|
|
8285
|
-
const getControlBinding = (0,
|
|
9032
|
+
const getControlBinding = (0, import_react23.useCallback)(
|
|
8286
9033
|
(nodeId) => {
|
|
8287
9034
|
return controls.get(nodeId);
|
|
8288
9035
|
},
|
|
8289
9036
|
[controls]
|
|
8290
9037
|
);
|
|
8291
|
-
const isCommandPending = (0,
|
|
9038
|
+
const isCommandPending = (0, import_react23.useCallback)(
|
|
8292
9039
|
(nodeId, kind) => {
|
|
8293
9040
|
if (kind) {
|
|
8294
9041
|
const prefix2 = `${nodeId}:${kind}`;
|
|
@@ -8305,7 +9052,7 @@ function useDeviceControls(initialBindings, options) {
|
|
|
8305
9052
|
},
|
|
8306
9053
|
[pendingCommands]
|
|
8307
9054
|
);
|
|
8308
|
-
const markPending = (0,
|
|
9055
|
+
const markPending = (0, import_react23.useCallback)(
|
|
8309
9056
|
(key, delta) => {
|
|
8310
9057
|
const next = (pendingRef.current.get(key) ?? 0) + delta;
|
|
8311
9058
|
if (next > 0) pendingRef.current.set(key, next);
|
|
@@ -8314,7 +9061,7 @@ function useDeviceControls(initialBindings, options) {
|
|
|
8314
9061
|
},
|
|
8315
9062
|
[syncPending]
|
|
8316
9063
|
);
|
|
8317
|
-
const runCommand = (0,
|
|
9064
|
+
const runCommand = (0, import_react23.useCallback)(
|
|
8318
9065
|
async (nodeId, key, invoke, messages) => {
|
|
8319
9066
|
const binding = controls.get(nodeId);
|
|
8320
9067
|
if (!binding) return;
|
|
@@ -8354,7 +9101,7 @@ function useDeviceControls(initialBindings, options) {
|
|
|
8354
9101
|
},
|
|
8355
9102
|
[controls, updateDeviceState, markPending, commandTimeoutMs]
|
|
8356
9103
|
);
|
|
8357
|
-
const sendModeChange = (0,
|
|
9104
|
+
const sendModeChange = (0, import_react23.useCallback)(
|
|
8358
9105
|
(nodeId, mode) => runCommand(
|
|
8359
9106
|
nodeId,
|
|
8360
9107
|
commandKey(nodeId, "mode"),
|
|
@@ -8363,7 +9110,7 @@ function useDeviceControls(initialBindings, options) {
|
|
|
8363
9110
|
),
|
|
8364
9111
|
[runCommand]
|
|
8365
9112
|
);
|
|
8366
|
-
const sendParameterChange = (0,
|
|
9113
|
+
const sendParameterChange = (0, import_react23.useCallback)(
|
|
8367
9114
|
(nodeId, parameterId, value) => runCommand(
|
|
8368
9115
|
nodeId,
|
|
8369
9116
|
commandKey(nodeId, "parameter", parameterId),
|
|
@@ -8372,21 +9119,21 @@ function useDeviceControls(initialBindings, options) {
|
|
|
8372
9119
|
),
|
|
8373
9120
|
[runCommand]
|
|
8374
9121
|
);
|
|
8375
|
-
const sendStartCommand = (0,
|
|
9122
|
+
const sendStartCommand = (0, import_react23.useCallback)(
|
|
8376
9123
|
(nodeId) => runCommand(nodeId, commandKey(nodeId, "start"), (binding) => binding.actions.onStart?.(), {
|
|
8377
9124
|
success: "Start command sent",
|
|
8378
9125
|
failure: "Start command failed"
|
|
8379
9126
|
}),
|
|
8380
9127
|
[runCommand]
|
|
8381
9128
|
);
|
|
8382
|
-
const sendStopCommand = (0,
|
|
9129
|
+
const sendStopCommand = (0, import_react23.useCallback)(
|
|
8383
9130
|
(nodeId) => runCommand(nodeId, commandKey(nodeId, "stop"), (binding) => binding.actions.onStop?.(), {
|
|
8384
9131
|
success: "Stop command sent",
|
|
8385
9132
|
failure: "Stop command failed"
|
|
8386
9133
|
}),
|
|
8387
9134
|
[runCommand]
|
|
8388
9135
|
);
|
|
8389
|
-
const sendCustomAction = (0,
|
|
9136
|
+
const sendCustomAction = (0, import_react23.useCallback)(
|
|
8390
9137
|
(nodeId, actionId) => runCommand(
|
|
8391
9138
|
nodeId,
|
|
8392
9139
|
commandKey(nodeId, "action", actionId),
|
|
@@ -8439,9 +9186,9 @@ function createConfigBinding(nodeId, tag, parameters, actions, options) {
|
|
|
8439
9186
|
}
|
|
8440
9187
|
|
|
8441
9188
|
// src/hooks/useDeviceConfigs.ts
|
|
8442
|
-
var
|
|
9189
|
+
var import_react24 = require("react");
|
|
8443
9190
|
function useDeviceConfigs(initialConfigs) {
|
|
8444
|
-
const [configs, setConfigs] = (0,
|
|
9191
|
+
const [configs, setConfigs] = (0, import_react24.useState)(() => {
|
|
8445
9192
|
const map = /* @__PURE__ */ new Map();
|
|
8446
9193
|
if (initialConfigs) {
|
|
8447
9194
|
initialConfigs.forEach((config) => {
|
|
@@ -8450,13 +9197,13 @@ function useDeviceConfigs(initialConfigs) {
|
|
|
8450
9197
|
}
|
|
8451
9198
|
return map;
|
|
8452
9199
|
});
|
|
8453
|
-
const getConfig = (0,
|
|
9200
|
+
const getConfig = (0, import_react24.useCallback)(
|
|
8454
9201
|
(nodeId) => {
|
|
8455
9202
|
return configs.get(nodeId);
|
|
8456
9203
|
},
|
|
8457
9204
|
[configs]
|
|
8458
9205
|
);
|
|
8459
|
-
const updateConfig = (0,
|
|
9206
|
+
const updateConfig = (0, import_react24.useCallback)((nodeId, updates) => {
|
|
8460
9207
|
setConfigs((prev) => {
|
|
8461
9208
|
const newMap = new Map(prev);
|
|
8462
9209
|
const existing = newMap.get(nodeId);
|
|
@@ -8470,7 +9217,7 @@ function useDeviceConfigs(initialConfigs) {
|
|
|
8470
9217
|
return newMap;
|
|
8471
9218
|
});
|
|
8472
9219
|
}, []);
|
|
8473
|
-
const updateConfigState = (0,
|
|
9220
|
+
const updateConfigState = (0, import_react24.useCallback)((nodeId, stateUpdates) => {
|
|
8474
9221
|
setConfigs((prev) => {
|
|
8475
9222
|
const newMap = new Map(prev);
|
|
8476
9223
|
const existing = newMap.get(nodeId);
|
|
@@ -8483,7 +9230,7 @@ function useDeviceConfigs(initialConfigs) {
|
|
|
8483
9230
|
return newMap;
|
|
8484
9231
|
});
|
|
8485
9232
|
}, []);
|
|
8486
|
-
const updateConfigBatch = (0,
|
|
9233
|
+
const updateConfigBatch = (0, import_react24.useCallback)((updates) => {
|
|
8487
9234
|
setConfigs((prev) => {
|
|
8488
9235
|
const newMap = new Map(prev);
|
|
8489
9236
|
Object.entries(updates).forEach(([nodeId, update]) => {
|
|
@@ -8495,7 +9242,7 @@ function useDeviceConfigs(initialConfigs) {
|
|
|
8495
9242
|
return newMap;
|
|
8496
9243
|
});
|
|
8497
9244
|
}, []);
|
|
8498
|
-
const updateParameterValue = (0,
|
|
9245
|
+
const updateParameterValue = (0, import_react24.useCallback)((nodeId, parameterId, value) => {
|
|
8499
9246
|
setConfigs((prev) => {
|
|
8500
9247
|
const newMap = new Map(prev);
|
|
8501
9248
|
const existing = newMap.get(nodeId);
|
|
@@ -8512,7 +9259,7 @@ function useDeviceConfigs(initialConfigs) {
|
|
|
8512
9259
|
return newMap;
|
|
8513
9260
|
});
|
|
8514
9261
|
}, []);
|
|
8515
|
-
const applyConfig = (0,
|
|
9262
|
+
const applyConfig = (0, import_react24.useCallback)(
|
|
8516
9263
|
async (nodeId) => {
|
|
8517
9264
|
const config = configs.get(nodeId);
|
|
8518
9265
|
if (!config || !config.actions.onApply) {
|
|
@@ -8545,7 +9292,7 @@ function useDeviceConfigs(initialConfigs) {
|
|
|
8545
9292
|
},
|
|
8546
9293
|
[configs, updateConfigState]
|
|
8547
9294
|
);
|
|
8548
|
-
const saveConfig = (0,
|
|
9295
|
+
const saveConfig = (0, import_react24.useCallback)(
|
|
8549
9296
|
async (nodeId) => {
|
|
8550
9297
|
const config = configs.get(nodeId);
|
|
8551
9298
|
if (!config || !config.actions.onSave) {
|
|
@@ -8579,7 +9326,7 @@ function useDeviceConfigs(initialConfigs) {
|
|
|
8579
9326
|
},
|
|
8580
9327
|
[configs, updateConfigState]
|
|
8581
9328
|
);
|
|
8582
|
-
const resetConfig = (0,
|
|
9329
|
+
const resetConfig = (0, import_react24.useCallback)(
|
|
8583
9330
|
async (nodeId) => {
|
|
8584
9331
|
const config = configs.get(nodeId);
|
|
8585
9332
|
if (!config) {
|
|
@@ -8609,7 +9356,7 @@ function useDeviceConfigs(initialConfigs) {
|
|
|
8609
9356
|
},
|
|
8610
9357
|
[configs, updateConfig, updateConfigState]
|
|
8611
9358
|
);
|
|
8612
|
-
const cancelConfig = (0,
|
|
9359
|
+
const cancelConfig = (0, import_react24.useCallback)(
|
|
8613
9360
|
(nodeId) => {
|
|
8614
9361
|
const config = configs.get(nodeId);
|
|
8615
9362
|
if (config?.actions.onCancel) {
|
|
@@ -8618,7 +9365,7 @@ function useDeviceConfigs(initialConfigs) {
|
|
|
8618
9365
|
},
|
|
8619
9366
|
[configs]
|
|
8620
9367
|
);
|
|
8621
|
-
const validateConfig = (0,
|
|
9368
|
+
const validateConfig = (0, import_react24.useCallback)(
|
|
8622
9369
|
(nodeId) => {
|
|
8623
9370
|
const config = configs.get(nodeId);
|
|
8624
9371
|
if (!config) {
|
|
@@ -8660,21 +9407,21 @@ function useDeviceConfigs(initialConfigs) {
|
|
|
8660
9407
|
},
|
|
8661
9408
|
[configs, updateConfigState]
|
|
8662
9409
|
);
|
|
8663
|
-
const setConfig = (0,
|
|
9410
|
+
const setConfig = (0, import_react24.useCallback)((config) => {
|
|
8664
9411
|
setConfigs((prev) => {
|
|
8665
9412
|
const newMap = new Map(prev);
|
|
8666
9413
|
newMap.set(config.nodeId, config);
|
|
8667
9414
|
return newMap;
|
|
8668
9415
|
});
|
|
8669
9416
|
}, []);
|
|
8670
|
-
const removeConfig = (0,
|
|
9417
|
+
const removeConfig = (0, import_react24.useCallback)((nodeId) => {
|
|
8671
9418
|
setConfigs((prev) => {
|
|
8672
9419
|
const newMap = new Map(prev);
|
|
8673
9420
|
newMap.delete(nodeId);
|
|
8674
9421
|
return newMap;
|
|
8675
9422
|
});
|
|
8676
9423
|
}, []);
|
|
8677
|
-
const clearConfigs = (0,
|
|
9424
|
+
const clearConfigs = (0, import_react24.useCallback)(() => {
|
|
8678
9425
|
setConfigs(/* @__PURE__ */ new Map());
|
|
8679
9426
|
}, []);
|
|
8680
9427
|
return {
|
|
@@ -8696,7 +9443,7 @@ function useDeviceConfigs(initialConfigs) {
|
|
|
8696
9443
|
}
|
|
8697
9444
|
|
|
8698
9445
|
// src/components/DeviceConfigPanel/DeviceConfigPanel.tsx
|
|
8699
|
-
var
|
|
9446
|
+
var import_react25 = __toESM(require("react"), 1);
|
|
8700
9447
|
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
8701
9448
|
function DeviceConfigPanelImpl({
|
|
8702
9449
|
binding,
|
|
@@ -8716,7 +9463,7 @@ function DeviceConfigPanelImpl({
|
|
|
8716
9463
|
showBuiltInToast = true,
|
|
8717
9464
|
embedded = false
|
|
8718
9465
|
}) {
|
|
8719
|
-
const [localValues, setLocalValues] = (0,
|
|
9466
|
+
const [localValues, setLocalValues] = (0, import_react25.useState)(() => {
|
|
8720
9467
|
if (binding) {
|
|
8721
9468
|
const values = {};
|
|
8722
9469
|
binding.parameters.forEach((param) => {
|
|
@@ -8726,7 +9473,7 @@ function DeviceConfigPanelImpl({
|
|
|
8726
9473
|
}
|
|
8727
9474
|
return {};
|
|
8728
9475
|
});
|
|
8729
|
-
const [collapsedSections, setCollapsedSections] = (0,
|
|
9476
|
+
const [collapsedSections, setCollapsedSections] = (0, import_react25.useState)(() => {
|
|
8730
9477
|
const collapsed = /* @__PURE__ */ new Set();
|
|
8731
9478
|
if (binding?.sections) {
|
|
8732
9479
|
binding.sections.forEach((section) => {
|
|
@@ -8737,9 +9484,9 @@ function DeviceConfigPanelImpl({
|
|
|
8737
9484
|
}
|
|
8738
9485
|
return collapsed;
|
|
8739
9486
|
});
|
|
8740
|
-
const [showToast, setShowToast] = (0,
|
|
8741
|
-
const [bindingId, setBindingId] = (0,
|
|
8742
|
-
const lastResultTimestampRef = (0,
|
|
9487
|
+
const [showToast, setShowToast] = (0, import_react25.useState)(true);
|
|
9488
|
+
const [bindingId, setBindingId] = (0, import_react25.useState)(binding?.nodeId || null);
|
|
9489
|
+
const lastResultTimestampRef = (0, import_react25.useRef)(0);
|
|
8743
9490
|
if (binding && binding.nodeId !== bindingId) {
|
|
8744
9491
|
const values = {};
|
|
8745
9492
|
binding.parameters.forEach((param) => {
|
|
@@ -8755,7 +9502,7 @@ function DeviceConfigPanelImpl({
|
|
|
8755
9502
|
setCollapsedSections(collapsed);
|
|
8756
9503
|
setBindingId(binding.nodeId);
|
|
8757
9504
|
}
|
|
8758
|
-
(0,
|
|
9505
|
+
(0, import_react25.useEffect)(() => {
|
|
8759
9506
|
const currentTimestamp = binding?.state.lastSaved || 0;
|
|
8760
9507
|
if (binding?.state.lastSaveResult && currentTimestamp !== lastResultTimestampRef.current) {
|
|
8761
9508
|
lastResultTimestampRef.current = currentTimestamp;
|
|
@@ -8772,7 +9519,7 @@ function DeviceConfigPanelImpl({
|
|
|
8772
9519
|
};
|
|
8773
9520
|
}
|
|
8774
9521
|
}, [binding?.state.lastSaveResult, binding?.state.lastSaved, toastDuration]);
|
|
8775
|
-
const parametersBySection = (0,
|
|
9522
|
+
const parametersBySection = (0, import_react25.useMemo)(() => {
|
|
8776
9523
|
if (!binding) return { _unsectioned: [] };
|
|
8777
9524
|
const groups = { _unsectioned: [] };
|
|
8778
9525
|
binding.parameters.forEach((param) => {
|
|
@@ -8787,7 +9534,7 @@ function DeviceConfigPanelImpl({
|
|
|
8787
9534
|
});
|
|
8788
9535
|
return groups;
|
|
8789
9536
|
}, [binding]);
|
|
8790
|
-
const sortedSections = (0,
|
|
9537
|
+
const sortedSections = (0, import_react25.useMemo)(() => {
|
|
8791
9538
|
if (!binding?.sections) return [];
|
|
8792
9539
|
return [...binding.sections].sort((a, b) => (a.order || 0) - (b.order || 0));
|
|
8793
9540
|
}, [binding]);
|
|
@@ -8890,7 +9637,49 @@ function DeviceConfigPanelImpl({
|
|
|
8890
9637
|
" (",
|
|
8891
9638
|
param.unit,
|
|
8892
9639
|
")"
|
|
8893
|
-
] })
|
|
9640
|
+
] }),
|
|
9641
|
+
param.forced?.active && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
9642
|
+
"span",
|
|
9643
|
+
{
|
|
9644
|
+
"aria-label": "Forced",
|
|
9645
|
+
style: {
|
|
9646
|
+
display: "inline-flex",
|
|
9647
|
+
alignItems: "center",
|
|
9648
|
+
justifyContent: "center",
|
|
9649
|
+
width: "16px",
|
|
9650
|
+
height: "16px",
|
|
9651
|
+
marginLeft: "6px",
|
|
9652
|
+
fontSize: "10px",
|
|
9653
|
+
fontWeight: 700,
|
|
9654
|
+
textTransform: "none",
|
|
9655
|
+
letterSpacing: "normal",
|
|
9656
|
+
color: FORCED_MARK_COLOR.text,
|
|
9657
|
+
backgroundColor: FORCED_MARK_COLOR.bg,
|
|
9658
|
+
border: `1px solid ${FORCED_MARK_COLOR.border}`,
|
|
9659
|
+
borderRadius: "50%",
|
|
9660
|
+
verticalAlign: "middle"
|
|
9661
|
+
},
|
|
9662
|
+
children: "F"
|
|
9663
|
+
}
|
|
9664
|
+
)
|
|
9665
|
+
]
|
|
9666
|
+
}
|
|
9667
|
+
),
|
|
9668
|
+
param.forced?.active && param.forced.realValue !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
9669
|
+
"div",
|
|
9670
|
+
{
|
|
9671
|
+
style: {
|
|
9672
|
+
fontSize: `${fontSize.description}px`,
|
|
9673
|
+
color: mutedTextColor,
|
|
9674
|
+
marginTop: "-2px",
|
|
9675
|
+
marginBottom: "6px",
|
|
9676
|
+
fontFamily: "Arial, sans-serif"
|
|
9677
|
+
},
|
|
9678
|
+
children: [
|
|
9679
|
+
"REAL",
|
|
9680
|
+
" ",
|
|
9681
|
+
typeof param.forced.realValue === "boolean" ? param.forced.realValue ? "ON" : "OFF" : String(param.forced.realValue),
|
|
9682
|
+
param.unit ? ` ${param.unit}` : ""
|
|
8894
9683
|
]
|
|
8895
9684
|
}
|
|
8896
9685
|
),
|
|
@@ -9401,10 +10190,10 @@ function DeviceConfigPanelImpl({
|
|
|
9401
10190
|
)
|
|
9402
10191
|
] });
|
|
9403
10192
|
}
|
|
9404
|
-
var DeviceConfigPanel =
|
|
10193
|
+
var DeviceConfigPanel = import_react25.default.memo(DeviceConfigPanelImpl);
|
|
9405
10194
|
|
|
9406
10195
|
// src/diagram/hooks/useSimulation.ts
|
|
9407
|
-
var
|
|
10196
|
+
var import_react26 = require("react");
|
|
9408
10197
|
function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
|
|
9409
10198
|
const {
|
|
9410
10199
|
interval = 2e3,
|
|
@@ -9415,7 +10204,7 @@ function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
|
|
|
9415
10204
|
historyLength = 10,
|
|
9416
10205
|
generateValue
|
|
9417
10206
|
} = options;
|
|
9418
|
-
(0,
|
|
10207
|
+
(0, import_react26.useEffect)(() => {
|
|
9419
10208
|
if (!enabled) return;
|
|
9420
10209
|
const intervalId = setInterval(() => {
|
|
9421
10210
|
const updates = [];
|
|
@@ -9466,6 +10255,7 @@ function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
|
|
|
9466
10255
|
// Annotate the CommonJS export names for ESM import in node:
|
|
9467
10256
|
0 && (module.exports = {
|
|
9468
10257
|
Button,
|
|
10258
|
+
COLOR_PRESETS,
|
|
9469
10259
|
CardHeader,
|
|
9470
10260
|
CardUnit,
|
|
9471
10261
|
CardValue,
|
|
@@ -9479,6 +10269,7 @@ function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
|
|
|
9479
10269
|
DisplayModeToggle,
|
|
9480
10270
|
EquipmentIndicator,
|
|
9481
10271
|
EquipmentIndicatorWithSparkline,
|
|
10272
|
+
FORCED_MARK_COLOR,
|
|
9482
10273
|
FixedSVGContainer,
|
|
9483
10274
|
FooterPanel,
|
|
9484
10275
|
FullscreenContainer,
|
|
@@ -9494,6 +10285,7 @@ function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
|
|
|
9494
10285
|
PanelTabs,
|
|
9495
10286
|
RightPanel,
|
|
9496
10287
|
RightToggleButton,
|
|
10288
|
+
STATUS_LED_APPEARANCE,
|
|
9497
10289
|
SVGArea,
|
|
9498
10290
|
SVGLockedOverlay,
|
|
9499
10291
|
ScrollableSVGWrapper,
|
|
@@ -9504,6 +10296,8 @@ function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
|
|
|
9504
10296
|
ThemeProvider,
|
|
9505
10297
|
ThemeToggle,
|
|
9506
10298
|
TrendLine,
|
|
10299
|
+
UNKNOWN_MARK_COLOR,
|
|
10300
|
+
UNKNOWN_MARK_COLOR_DARK,
|
|
9507
10301
|
ValueEntry,
|
|
9508
10302
|
ZoomButton,
|
|
9509
10303
|
ZoomControls,
|
|
@@ -9513,6 +10307,8 @@ function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
|
|
|
9513
10307
|
exampleDiagram,
|
|
9514
10308
|
exportDiagram,
|
|
9515
10309
|
generateRoutePoints,
|
|
10310
|
+
getAppearanceDefaults,
|
|
10311
|
+
getAppearanceSchema,
|
|
9516
10312
|
getAvailableSymbols,
|
|
9517
10313
|
getPortWorldPosition,
|
|
9518
10314
|
getSymbolDefinition,
|
|
@@ -9520,9 +10316,12 @@ function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
|
|
|
9520
10316
|
mockSymbolLibrary,
|
|
9521
10317
|
nodeHasPort,
|
|
9522
10318
|
overlayStyles,
|
|
10319
|
+
readAppearanceValue,
|
|
9523
10320
|
registerSymbol,
|
|
9524
10321
|
registerSymbols,
|
|
10322
|
+
resolvePresetColor,
|
|
9525
10323
|
resolveStatusColor,
|
|
10324
|
+
useBooleanIndicators,
|
|
9526
10325
|
useDeviceConfigs,
|
|
9527
10326
|
useDeviceControls,
|
|
9528
10327
|
useDrag,
|
|
@@ -9533,6 +10332,7 @@ function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
|
|
|
9533
10332
|
useTelemetryStatus,
|
|
9534
10333
|
useTheme,
|
|
9535
10334
|
useViewBox,
|
|
9536
|
-
validateDiagram
|
|
10335
|
+
validateDiagram,
|
|
10336
|
+
writeAppearanceValue
|
|
9537
10337
|
});
|
|
9538
10338
|
//# sourceMappingURL=index.cjs.map
|