@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.js
CHANGED
|
@@ -174,6 +174,8 @@ var ValueEntry = ({
|
|
|
174
174
|
inputType = "numeric",
|
|
175
175
|
label,
|
|
176
176
|
readOnly = false,
|
|
177
|
+
forced = false,
|
|
178
|
+
realValue,
|
|
177
179
|
className = "",
|
|
178
180
|
disabled,
|
|
179
181
|
...props
|
|
@@ -224,9 +226,14 @@ var ValueEntry = ({
|
|
|
224
226
|
const unitClass = unit ? "ui-value-entry--with-unit" : "";
|
|
225
227
|
const currentStatus = disabled || readOnly ? "disabled" : status;
|
|
226
228
|
const statusVariantClass = currentStatus ? `ui-value-entry--${currentStatus}` : "";
|
|
229
|
+
const forcedClass = forced ? "ui-value-entry--forced" : "";
|
|
230
|
+
const hasRealValue = forced && realValue !== void 0;
|
|
227
231
|
const displayText = isEditing ? displayValue : inputType === "numeric" ? Number(value).toFixed(precision) : String(value);
|
|
228
232
|
return /* @__PURE__ */ jsxs2("div", { className: "ui-value-entry-container", children: [
|
|
229
|
-
label && /* @__PURE__ */
|
|
233
|
+
label && /* @__PURE__ */ jsxs2("label", { className: "ui-value-entry-label", children: [
|
|
234
|
+
label,
|
|
235
|
+
forced && /* @__PURE__ */ jsx3("span", { className: "ui-value-entry-forced-badge", "aria-label": "Forced", children: "F" })
|
|
236
|
+
] }),
|
|
230
237
|
/* @__PURE__ */ jsxs2("div", { className: "ui-value-entry-wrapper", children: [
|
|
231
238
|
/* @__PURE__ */ jsx3(
|
|
232
239
|
"input",
|
|
@@ -239,19 +246,71 @@ var ValueEntry = ({
|
|
|
239
246
|
onKeyDown: handleKeyDown,
|
|
240
247
|
disabled,
|
|
241
248
|
readOnly,
|
|
242
|
-
className: `${baseClass} ${statusVariantClass} ${unitClass} ${className}`.trim(),
|
|
249
|
+
className: `${baseClass} ${statusVariantClass} ${forcedClass} ${unitClass} ${className}`.trim(),
|
|
243
250
|
...props
|
|
244
251
|
}
|
|
245
252
|
),
|
|
246
253
|
unit && /* @__PURE__ */ jsx3("span", { className: "ui-value-entry-unit", children: unit }),
|
|
247
254
|
status === "alarm" && /* @__PURE__ */ jsx3("div", { className: "ui-value-entry-badge ui-value-entry-badge--alarm" }),
|
|
248
|
-
status === "warning" && /* @__PURE__ */ jsx3("div", { className: "ui-value-entry-badge ui-value-entry-badge--warning" })
|
|
255
|
+
status === "warning" && /* @__PURE__ */ jsx3("div", { className: "ui-value-entry-badge ui-value-entry-badge--warning" }),
|
|
256
|
+
!label && forced && /* @__PURE__ */ jsx3("span", { className: "ui-value-entry-forced-badge", "aria-label": "Forced", children: "F" })
|
|
257
|
+
] }),
|
|
258
|
+
hasRealValue && /* @__PURE__ */ jsxs2("div", { className: "ui-value-entry-real-value", children: [
|
|
259
|
+
"REAL ",
|
|
260
|
+
String(realValue),
|
|
261
|
+
unit ? ` ${unit}` : ""
|
|
249
262
|
] })
|
|
250
263
|
] });
|
|
251
264
|
};
|
|
252
265
|
|
|
253
266
|
// src/components/ValueEntry/LegacyValueEntry.tsx
|
|
254
267
|
import { useState as useState3, useCallback as useCallback2 } from "react";
|
|
268
|
+
|
|
269
|
+
// src/theme/statusColors.ts
|
|
270
|
+
var DEFAULT_STATUS_COLORS = {
|
|
271
|
+
normal: { fill: "#888888", stroke: "#6b6b6b", bg: "#888888", text: "#ffffff", border: "#6b6b6b" },
|
|
272
|
+
warning: { fill: "#f59e0b", stroke: "#d97706", bg: "#FFD700", text: "#000000", border: "#d97706" },
|
|
273
|
+
alarm: { fill: "#ef4444", stroke: "#dc2626", bg: "#FF0000", text: "#ffffff", border: "#dc2626" },
|
|
274
|
+
fault: { fill: "#dc2626", stroke: "#b91c1c", bg: "#FF0000", text: "#ffffff", border: "#b91c1c" },
|
|
275
|
+
off: { fill: "#edeeef", stroke: "#000000", bg: "#666666", text: "#ffffff", border: "#4b5563" },
|
|
276
|
+
starting: { fill: "#90EE90", stroke: "#22c55e", bg: "#90EE90", text: "#000000", border: "#22c55e" },
|
|
277
|
+
stopping: { fill: "#FFD700", stroke: "#d97706", bg: "#FFD700", text: "#000000", border: "#d97706" }
|
|
278
|
+
};
|
|
279
|
+
var FORCED_MARK_COLOR = {
|
|
280
|
+
fill: "#ede9fe",
|
|
281
|
+
stroke: "#5b21b6",
|
|
282
|
+
bg: "#ede9fe",
|
|
283
|
+
text: "#5b21b6",
|
|
284
|
+
border: "#7c3aed"
|
|
285
|
+
};
|
|
286
|
+
var UNKNOWN_MARK_COLOR = {
|
|
287
|
+
fill: "#ebebf5",
|
|
288
|
+
stroke: "#8f8fc2",
|
|
289
|
+
bg: "#ebebf5",
|
|
290
|
+
text: "#4f4f8a",
|
|
291
|
+
border: "#8f8fc2"
|
|
292
|
+
};
|
|
293
|
+
var UNKNOWN_MARK_COLOR_DARK = {
|
|
294
|
+
fill: "#23263a",
|
|
295
|
+
stroke: "#6f74a3",
|
|
296
|
+
bg: "#23263a",
|
|
297
|
+
text: "#b9bbdb",
|
|
298
|
+
border: "#6f74a3"
|
|
299
|
+
};
|
|
300
|
+
var STATUS_ALIASES = {
|
|
301
|
+
running: "normal",
|
|
302
|
+
stopped: "off"
|
|
303
|
+
};
|
|
304
|
+
function resolveStatusColor(status, customMap) {
|
|
305
|
+
const raw = (status || "off").toLowerCase();
|
|
306
|
+
const key = STATUS_ALIASES[raw] ?? raw;
|
|
307
|
+
const defaults = DEFAULT_STATUS_COLORS[key] ?? DEFAULT_STATUS_COLORS.off;
|
|
308
|
+
const overrides = customMap?.[key];
|
|
309
|
+
if (!overrides) return defaults;
|
|
310
|
+
return { ...defaults, ...overrides };
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// src/components/ValueEntry/LegacyValueEntry.tsx
|
|
255
314
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
256
315
|
var LegacyValueEntry = ({
|
|
257
316
|
value,
|
|
@@ -264,6 +323,8 @@ var LegacyValueEntry = ({
|
|
|
264
323
|
inputType = "numeric",
|
|
265
324
|
label,
|
|
266
325
|
readOnly = false,
|
|
326
|
+
forced = false,
|
|
327
|
+
realValue,
|
|
267
328
|
className = "",
|
|
268
329
|
disabled,
|
|
269
330
|
...props
|
|
@@ -344,6 +405,27 @@ var LegacyValueEntry = ({
|
|
|
344
405
|
}
|
|
345
406
|
};
|
|
346
407
|
const statusStyles = getStatusStyles();
|
|
408
|
+
const forcedBadgeStyle = {
|
|
409
|
+
display: "inline-flex",
|
|
410
|
+
alignItems: "center",
|
|
411
|
+
justifyContent: "center",
|
|
412
|
+
width: "1.1rem",
|
|
413
|
+
height: "1.1rem",
|
|
414
|
+
fontSize: "0.7rem",
|
|
415
|
+
fontWeight: 700,
|
|
416
|
+
color: FORCED_MARK_COLOR.text,
|
|
417
|
+
backgroundColor: FORCED_MARK_COLOR.bg,
|
|
418
|
+
border: `1px solid ${FORCED_MARK_COLOR.border}`,
|
|
419
|
+
borderRadius: "50%",
|
|
420
|
+
marginLeft: "8px",
|
|
421
|
+
lineHeight: 1
|
|
422
|
+
};
|
|
423
|
+
const realValueStyle = {
|
|
424
|
+
fontSize: "0.75rem",
|
|
425
|
+
fontWeight: 500,
|
|
426
|
+
color: "#94a3b8",
|
|
427
|
+
letterSpacing: "0.02em"
|
|
428
|
+
};
|
|
347
429
|
const inputStyle = {
|
|
348
430
|
width: "12rem",
|
|
349
431
|
height: "4rem",
|
|
@@ -392,17 +474,22 @@ var LegacyValueEntry = ({
|
|
|
392
474
|
gap: "0.75rem"
|
|
393
475
|
},
|
|
394
476
|
children: [
|
|
395
|
-
label && /* @__PURE__ */
|
|
477
|
+
(label || forced) && /* @__PURE__ */ jsxs3(
|
|
396
478
|
"label",
|
|
397
479
|
{
|
|
398
480
|
style: {
|
|
481
|
+
display: "flex",
|
|
482
|
+
alignItems: "center",
|
|
399
483
|
fontSize: "0.875rem",
|
|
400
484
|
fontWeight: "600",
|
|
401
485
|
color: "#cbd5e1",
|
|
402
486
|
textTransform: "uppercase",
|
|
403
487
|
letterSpacing: "0.05em"
|
|
404
488
|
},
|
|
405
|
-
children:
|
|
489
|
+
children: [
|
|
490
|
+
label,
|
|
491
|
+
forced && /* @__PURE__ */ jsx4("span", { style: forcedBadgeStyle, "aria-label": "Forced", children: "F" })
|
|
492
|
+
]
|
|
406
493
|
}
|
|
407
494
|
),
|
|
408
495
|
/* @__PURE__ */ jsxs3("div", { style: { position: "relative", display: "inline-flex", alignItems: "center" }, children: [
|
|
@@ -459,6 +546,11 @@ var LegacyValueEntry = ({
|
|
|
459
546
|
}
|
|
460
547
|
}
|
|
461
548
|
)
|
|
549
|
+
] }),
|
|
550
|
+
forced && realValue !== void 0 && /* @__PURE__ */ jsxs3("div", { style: realValueStyle, children: [
|
|
551
|
+
"REAL ",
|
|
552
|
+
String(realValue),
|
|
553
|
+
unit ? ` ${unit}` : ""
|
|
462
554
|
] })
|
|
463
555
|
]
|
|
464
556
|
}
|
|
@@ -474,6 +566,9 @@ var ControlPanel = ({
|
|
|
474
566
|
onModeChange,
|
|
475
567
|
setpointValue,
|
|
476
568
|
onSetpointChange,
|
|
569
|
+
currentSetpointValue,
|
|
570
|
+
currentSetpointForced = false,
|
|
571
|
+
currentSetpointRealValue,
|
|
477
572
|
secondSetpointValue,
|
|
478
573
|
onSecondSetpointChange,
|
|
479
574
|
modeConfigs = {},
|
|
@@ -570,6 +665,21 @@ var ControlPanel = ({
|
|
|
570
665
|
disabled: status === "disabled"
|
|
571
666
|
}
|
|
572
667
|
) }),
|
|
668
|
+
currentSetpointValue !== void 0 && /* @__PURE__ */ jsx5("div", { children: /* @__PURE__ */ jsx5(
|
|
669
|
+
LegacyValueEntry,
|
|
670
|
+
{
|
|
671
|
+
value: currentSetpointValue,
|
|
672
|
+
onChange: () => {
|
|
673
|
+
},
|
|
674
|
+
label: `${currentLabel} (Current)`,
|
|
675
|
+
unit: currentUnit,
|
|
676
|
+
precision: currentPrecision,
|
|
677
|
+
status,
|
|
678
|
+
readOnly: true,
|
|
679
|
+
forced: currentSetpointForced,
|
|
680
|
+
realValue: currentSetpointRealValue
|
|
681
|
+
}
|
|
682
|
+
) }),
|
|
573
683
|
hasSecondSetpoint && onSecondSetpointChange && /* @__PURE__ */ jsx5("div", { children: /* @__PURE__ */ jsx5(
|
|
574
684
|
LegacyValueEntry,
|
|
575
685
|
{
|
|
@@ -660,9 +770,15 @@ var StatusIndicator = ({
|
|
|
660
770
|
labelPosition = "right",
|
|
661
771
|
shape = "circle",
|
|
662
772
|
led = true,
|
|
773
|
+
visible = true,
|
|
774
|
+
forced = false,
|
|
775
|
+
realValue,
|
|
663
776
|
className = "",
|
|
664
777
|
...props
|
|
665
778
|
}) => {
|
|
779
|
+
if (!visible) {
|
|
780
|
+
return null;
|
|
781
|
+
}
|
|
666
782
|
const baseClass = "ui-status-indicator";
|
|
667
783
|
const statusClass = status ? `ui-status-indicator--${status}` : "";
|
|
668
784
|
const sizeClass = size ? `ui-status-indicator--${size}` : "";
|
|
@@ -683,28 +799,43 @@ var StatusIndicator = ({
|
|
|
683
799
|
return "ui-status-indicator-container ui-status-indicator-label-right";
|
|
684
800
|
}
|
|
685
801
|
};
|
|
802
|
+
const forcedClass = forced ? "ui-status-indicator--forced" : "";
|
|
803
|
+
const hasRealValue = forced && realValue !== void 0;
|
|
686
804
|
return /* @__PURE__ */ jsxs5("span", { className: getContainerLayout(), children: [
|
|
687
805
|
label && (labelPosition === "left" || labelPosition === "top") && /* @__PURE__ */ jsx6("span", { className: "ui-status-indicator-label", children: label }),
|
|
688
|
-
/* @__PURE__ */
|
|
689
|
-
"
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
"
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
${
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
806
|
+
hasRealValue && (labelPosition === "left" || labelPosition === "top") && /* @__PURE__ */ jsxs5("span", { className: "ui-status-indicator-real-value", children: [
|
|
807
|
+
"REAL ",
|
|
808
|
+
realValue
|
|
809
|
+
] }),
|
|
810
|
+
/* @__PURE__ */ jsxs5("span", { style: { position: "relative", display: "inline-flex" }, children: [
|
|
811
|
+
/* @__PURE__ */ jsx6(
|
|
812
|
+
"span",
|
|
813
|
+
{
|
|
814
|
+
role: "status",
|
|
815
|
+
"aria-label": label || `Status: ${status}`,
|
|
816
|
+
"aria-description": getStatusDescription(status),
|
|
817
|
+
"data-status": status,
|
|
818
|
+
"data-forced": forced,
|
|
819
|
+
className: `
|
|
820
|
+
${baseClass}
|
|
821
|
+
${statusClass}
|
|
822
|
+
${sizeClass}
|
|
823
|
+
${shapeClass}
|
|
824
|
+
${animationClass}
|
|
825
|
+
${ledClass}
|
|
826
|
+
${forcedClass}
|
|
827
|
+
${className}
|
|
828
|
+
`.replace(/\s+/g, " ").trim(),
|
|
829
|
+
...props
|
|
830
|
+
}
|
|
831
|
+
),
|
|
832
|
+
forced && /* @__PURE__ */ jsx6("span", { className: "ui-status-indicator-forced-badge", "aria-label": "Forced", children: "F" })
|
|
833
|
+
] }),
|
|
834
|
+
label && (labelPosition === "right" || labelPosition === "bottom") && /* @__PURE__ */ jsx6("span", { className: "ui-status-indicator-label", children: label }),
|
|
835
|
+
hasRealValue && (labelPosition === "right" || labelPosition === "bottom") && /* @__PURE__ */ jsxs5("span", { className: "ui-status-indicator-real-value", children: [
|
|
836
|
+
"REAL ",
|
|
837
|
+
realValue
|
|
838
|
+
] })
|
|
708
839
|
] });
|
|
709
840
|
};
|
|
710
841
|
|
|
@@ -832,6 +963,9 @@ var NodeControlsPanel = ({
|
|
|
832
963
|
onModeChange: config.onModeChange,
|
|
833
964
|
setpointValue: config.setpoint,
|
|
834
965
|
onSetpointChange: config.onSetpointChange,
|
|
966
|
+
currentSetpointValue: config.currentSetpoint,
|
|
967
|
+
currentSetpointForced: config.currentSetpointForced,
|
|
968
|
+
currentSetpointRealValue: config.currentSetpointRealValue,
|
|
835
969
|
secondSetpointValue: config.secondSetpoint,
|
|
836
970
|
onSecondSetpointChange: config.onSecondSetpointChange,
|
|
837
971
|
modeConfigs: config.modeConfigs,
|
|
@@ -896,31 +1030,6 @@ var NodeControlsPanel = ({
|
|
|
896
1030
|
|
|
897
1031
|
// src/components/DeviceControlPanel/DeviceControlPanel.tsx
|
|
898
1032
|
import React5, { useState as useState5, useEffect as useEffect2 } from "react";
|
|
899
|
-
|
|
900
|
-
// src/theme/statusColors.ts
|
|
901
|
-
var DEFAULT_STATUS_COLORS = {
|
|
902
|
-
normal: { fill: "#888888", stroke: "#6b6b6b", bg: "#888888", text: "#ffffff", border: "#6b6b6b" },
|
|
903
|
-
warning: { fill: "#f59e0b", stroke: "#d97706", bg: "#FFD700", text: "#000000", border: "#d97706" },
|
|
904
|
-
alarm: { fill: "#ef4444", stroke: "#dc2626", bg: "#FF0000", text: "#ffffff", border: "#dc2626" },
|
|
905
|
-
fault: { fill: "#dc2626", stroke: "#b91c1c", bg: "#FF0000", text: "#ffffff", border: "#b91c1c" },
|
|
906
|
-
off: { fill: "#edeeef", stroke: "#000000", bg: "#666666", text: "#ffffff", border: "#4b5563" },
|
|
907
|
-
starting: { fill: "#90EE90", stroke: "#22c55e", bg: "#90EE90", text: "#000000", border: "#22c55e" },
|
|
908
|
-
stopping: { fill: "#FFD700", stroke: "#d97706", bg: "#FFD700", text: "#000000", border: "#d97706" }
|
|
909
|
-
};
|
|
910
|
-
var STATUS_ALIASES = {
|
|
911
|
-
running: "normal",
|
|
912
|
-
stopped: "off"
|
|
913
|
-
};
|
|
914
|
-
function resolveStatusColor(status, customMap) {
|
|
915
|
-
const raw = (status || "off").toLowerCase();
|
|
916
|
-
const key = STATUS_ALIASES[raw] ?? raw;
|
|
917
|
-
const defaults = DEFAULT_STATUS_COLORS[key] ?? DEFAULT_STATUS_COLORS.off;
|
|
918
|
-
const overrides = customMap?.[key];
|
|
919
|
-
if (!overrides) return defaults;
|
|
920
|
-
return { ...defaults, ...overrides };
|
|
921
|
-
}
|
|
922
|
-
|
|
923
|
-
// src/components/DeviceControlPanel/DeviceControlPanel.tsx
|
|
924
1033
|
import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
925
1034
|
function DeviceControlPanelImpl({
|
|
926
1035
|
binding,
|
|
@@ -1568,10 +1677,13 @@ function DeviceControlPanelImpl({
|
|
|
1568
1677
|
marginBottom: spacing.gap
|
|
1569
1678
|
},
|
|
1570
1679
|
children: [
|
|
1571
|
-
/* @__PURE__ */
|
|
1680
|
+
/* @__PURE__ */ jsxs7(
|
|
1572
1681
|
"span",
|
|
1573
1682
|
{
|
|
1574
1683
|
style: {
|
|
1684
|
+
display: "flex",
|
|
1685
|
+
alignItems: "center",
|
|
1686
|
+
gap: "6px",
|
|
1575
1687
|
fontSize: `${fontSize.label}px`,
|
|
1576
1688
|
fontWeight: 600,
|
|
1577
1689
|
textTransform: "uppercase",
|
|
@@ -1579,7 +1691,29 @@ function DeviceControlPanelImpl({
|
|
|
1579
1691
|
fontFamily: "Arial, sans-serif",
|
|
1580
1692
|
color: mutedTextColor
|
|
1581
1693
|
},
|
|
1582
|
-
children:
|
|
1694
|
+
children: [
|
|
1695
|
+
param.label,
|
|
1696
|
+
param.forced?.active && /* @__PURE__ */ jsx8(
|
|
1697
|
+
"span",
|
|
1698
|
+
{
|
|
1699
|
+
"aria-label": "Forced",
|
|
1700
|
+
style: {
|
|
1701
|
+
display: "inline-flex",
|
|
1702
|
+
alignItems: "center",
|
|
1703
|
+
justifyContent: "center",
|
|
1704
|
+
width: "16px",
|
|
1705
|
+
height: "16px",
|
|
1706
|
+
fontSize: "10px",
|
|
1707
|
+
fontWeight: 700,
|
|
1708
|
+
color: FORCED_MARK_COLOR.text,
|
|
1709
|
+
backgroundColor: FORCED_MARK_COLOR.bg,
|
|
1710
|
+
border: `1px solid ${FORCED_MARK_COLOR.border}`,
|
|
1711
|
+
borderRadius: "50%"
|
|
1712
|
+
},
|
|
1713
|
+
children: "F"
|
|
1714
|
+
}
|
|
1715
|
+
)
|
|
1716
|
+
]
|
|
1583
1717
|
}
|
|
1584
1718
|
),
|
|
1585
1719
|
/* @__PURE__ */ jsxs7(
|
|
@@ -1601,6 +1735,27 @@ function DeviceControlPanelImpl({
|
|
|
1601
1735
|
]
|
|
1602
1736
|
}
|
|
1603
1737
|
),
|
|
1738
|
+
param.forced?.active && param.forced.realValue !== void 0 && /* @__PURE__ */ jsxs7(
|
|
1739
|
+
"div",
|
|
1740
|
+
{
|
|
1741
|
+
style: {
|
|
1742
|
+
display: "flex",
|
|
1743
|
+
justifyContent: "flex-end",
|
|
1744
|
+
marginTop: "-4px",
|
|
1745
|
+
marginBottom: spacing.gap,
|
|
1746
|
+
fontSize: "10px",
|
|
1747
|
+
fontWeight: 500,
|
|
1748
|
+
fontFamily: "Arial, sans-serif",
|
|
1749
|
+
color: mutedTextColor
|
|
1750
|
+
},
|
|
1751
|
+
children: [
|
|
1752
|
+
"REAL",
|
|
1753
|
+
" ",
|
|
1754
|
+
typeof param.forced.realValue === "boolean" ? param.forced.realValue ? "ON" : "OFF" : String(param.forced.realValue),
|
|
1755
|
+
param.unit ? ` ${param.unit}` : ""
|
|
1756
|
+
]
|
|
1757
|
+
}
|
|
1758
|
+
),
|
|
1604
1759
|
param.type === "boolean" ? /* @__PURE__ */ jsx8(
|
|
1605
1760
|
"button",
|
|
1606
1761
|
{
|
|
@@ -2699,19 +2854,38 @@ var CardUnit = styled2("div")({
|
|
|
2699
2854
|
|
|
2700
2855
|
// src/components/layout/FullscreenWorkspace/FullscreenWorkspace.visuals.tsx
|
|
2701
2856
|
import { Fragment as Fragment3, jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2857
|
+
var forcedTagStyle = {
|
|
2858
|
+
position: "absolute",
|
|
2859
|
+
top: "-6px",
|
|
2860
|
+
right: "-6px",
|
|
2861
|
+
width: "14px",
|
|
2862
|
+
height: "14px",
|
|
2863
|
+
display: "flex",
|
|
2864
|
+
alignItems: "center",
|
|
2865
|
+
justifyContent: "center",
|
|
2866
|
+
fontSize: "9px",
|
|
2867
|
+
fontWeight: 700,
|
|
2868
|
+
color: FORCED_MARK_COLOR.text,
|
|
2869
|
+
backgroundColor: FORCED_MARK_COLOR.bg,
|
|
2870
|
+
border: `1px solid ${FORCED_MARK_COLOR.border}`,
|
|
2871
|
+
borderRadius: "50%",
|
|
2872
|
+
pointerEvents: "none"
|
|
2873
|
+
};
|
|
2702
2874
|
var TrendLine = ({
|
|
2703
2875
|
values,
|
|
2704
2876
|
width = 60,
|
|
2705
2877
|
height = 20,
|
|
2706
2878
|
color = "#4fc3f7",
|
|
2707
2879
|
strokeWidth = 1.5,
|
|
2708
|
-
backgroundColor = "rgba(255, 255, 255, 0.1)"
|
|
2880
|
+
backgroundColor = "rgba(255, 255, 255, 0.1)",
|
|
2881
|
+
forced = false
|
|
2709
2882
|
}) => {
|
|
2710
2883
|
if (!values || values.length < 2) {
|
|
2711
|
-
return /* @__PURE__ */
|
|
2884
|
+
return /* @__PURE__ */ jsxs9(
|
|
2712
2885
|
"div",
|
|
2713
2886
|
{
|
|
2714
2887
|
style: {
|
|
2888
|
+
position: "relative",
|
|
2715
2889
|
width,
|
|
2716
2890
|
height,
|
|
2717
2891
|
backgroundColor,
|
|
@@ -2720,7 +2894,10 @@ var TrendLine = ({
|
|
|
2720
2894
|
alignItems: "center",
|
|
2721
2895
|
justifyContent: "center"
|
|
2722
2896
|
},
|
|
2723
|
-
children:
|
|
2897
|
+
children: [
|
|
2898
|
+
/* @__PURE__ */ jsx12("span", { style: { fontSize: "8px", color: "#ccc" }, children: "No data" }),
|
|
2899
|
+
forced && /* @__PURE__ */ jsx12("span", { style: forcedTagStyle, "aria-label": "Forced", children: "F" })
|
|
2900
|
+
]
|
|
2724
2901
|
}
|
|
2725
2902
|
);
|
|
2726
2903
|
}
|
|
@@ -2732,7 +2909,7 @@ var TrendLine = ({
|
|
|
2732
2909
|
const x = 4 + i / (values.length - 1) * (width - 8);
|
|
2733
2910
|
return i === 0 ? `M ${x} ${y}` : `L ${x} ${y}`;
|
|
2734
2911
|
}).join(" ");
|
|
2735
|
-
return /* @__PURE__ */
|
|
2912
|
+
return /* @__PURE__ */ jsxs9(
|
|
2736
2913
|
"div",
|
|
2737
2914
|
{
|
|
2738
2915
|
style: {
|
|
@@ -2741,30 +2918,41 @@ var TrendLine = ({
|
|
|
2741
2918
|
backgroundColor,
|
|
2742
2919
|
borderRadius: "2px",
|
|
2743
2920
|
position: "relative",
|
|
2744
|
-
overflow: "
|
|
2921
|
+
overflow: "visible"
|
|
2745
2922
|
},
|
|
2746
|
-
children:
|
|
2747
|
-
/* @__PURE__ */
|
|
2748
|
-
"
|
|
2923
|
+
children: [
|
|
2924
|
+
/* @__PURE__ */ jsxs9(
|
|
2925
|
+
"svg",
|
|
2749
2926
|
{
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2927
|
+
width,
|
|
2928
|
+
height,
|
|
2929
|
+
style: { position: "absolute", top: 0, left: 0, overflow: "hidden", borderRadius: "2px" },
|
|
2930
|
+
children: [
|
|
2931
|
+
/* @__PURE__ */ jsx12(
|
|
2932
|
+
"path",
|
|
2933
|
+
{
|
|
2934
|
+
d: pathData,
|
|
2935
|
+
fill: "none",
|
|
2936
|
+
stroke: color,
|
|
2937
|
+
strokeWidth,
|
|
2938
|
+
strokeLinecap: "round",
|
|
2939
|
+
strokeLinejoin: "round"
|
|
2940
|
+
}
|
|
2941
|
+
),
|
|
2942
|
+
/* @__PURE__ */ jsx12(
|
|
2943
|
+
"circle",
|
|
2944
|
+
{
|
|
2945
|
+
cx: 4 + (width - 8),
|
|
2946
|
+
cy: normalizedValues[normalizedValues.length - 1],
|
|
2947
|
+
r: 1.5,
|
|
2948
|
+
fill: color
|
|
2949
|
+
}
|
|
2950
|
+
)
|
|
2951
|
+
]
|
|
2756
2952
|
}
|
|
2757
2953
|
),
|
|
2758
|
-
/* @__PURE__ */ jsx12(
|
|
2759
|
-
|
|
2760
|
-
{
|
|
2761
|
-
cx: 4 + (width - 8),
|
|
2762
|
-
cy: normalizedValues[normalizedValues.length - 1],
|
|
2763
|
-
r: 1.5,
|
|
2764
|
-
fill: color
|
|
2765
|
-
}
|
|
2766
|
-
)
|
|
2767
|
-
] })
|
|
2954
|
+
forced && /* @__PURE__ */ jsx12("span", { style: forcedTagStyle, "aria-label": "Forced", children: "F" })
|
|
2955
|
+
]
|
|
2768
2956
|
}
|
|
2769
2957
|
);
|
|
2770
2958
|
};
|
|
@@ -2780,7 +2968,9 @@ var CircularGauge = ({
|
|
|
2780
2968
|
unit,
|
|
2781
2969
|
label,
|
|
2782
2970
|
size = 60,
|
|
2783
|
-
color = "rgba(255, 255, 255, 0.9)"
|
|
2971
|
+
color = "rgba(255, 255, 255, 0.9)",
|
|
2972
|
+
forced = false,
|
|
2973
|
+
realValue
|
|
2784
2974
|
}) => {
|
|
2785
2975
|
const percentage = Math.min(value / max * 100, 100);
|
|
2786
2976
|
const strokeWidth = 4;
|
|
@@ -2811,7 +3001,7 @@ var CircularGauge = ({
|
|
|
2811
3001
|
height: size,
|
|
2812
3002
|
borderRadius: "50%",
|
|
2813
3003
|
backgroundColor,
|
|
2814
|
-
border: `1px solid ${borderStrokeColor}`
|
|
3004
|
+
border: forced ? `2px solid ${FORCED_MARK_COLOR.border}` : `1px solid ${borderStrokeColor}`
|
|
2815
3005
|
},
|
|
2816
3006
|
children: [
|
|
2817
3007
|
/* @__PURE__ */ jsxs9("svg", { width: size, height: size, style: { transform: "rotate(-90deg)" }, children: [
|
|
@@ -2887,12 +3077,39 @@ var CircularGauge = ({
|
|
|
2887
3077
|
},
|
|
2888
3078
|
children: label
|
|
2889
3079
|
}
|
|
2890
|
-
)
|
|
3080
|
+
),
|
|
3081
|
+
forced && /* @__PURE__ */ jsx12(
|
|
3082
|
+
"span",
|
|
3083
|
+
{
|
|
3084
|
+
"aria-label": "Forced",
|
|
3085
|
+
style: {
|
|
3086
|
+
display: "inline-flex",
|
|
3087
|
+
alignItems: "center",
|
|
3088
|
+
justifyContent: "center",
|
|
3089
|
+
width: "14px",
|
|
3090
|
+
height: "14px",
|
|
3091
|
+
fontSize: "9px",
|
|
3092
|
+
fontWeight: 700,
|
|
3093
|
+
color: FORCED_MARK_COLOR.text,
|
|
3094
|
+
backgroundColor: FORCED_MARK_COLOR.bg,
|
|
3095
|
+
border: `1px solid ${FORCED_MARK_COLOR.border}`,
|
|
3096
|
+
borderRadius: "50%",
|
|
3097
|
+
marginTop: "2px"
|
|
3098
|
+
},
|
|
3099
|
+
children: "F"
|
|
3100
|
+
}
|
|
3101
|
+
),
|
|
3102
|
+
forced && realValue !== void 0 && /* @__PURE__ */ jsxs9("div", { style: { fontSize: "8px", opacity: 0.8, color: "white", marginTop: "1px" }, children: [
|
|
3103
|
+
"REAL ",
|
|
3104
|
+
realValue.toFixed(1),
|
|
3105
|
+
" ",
|
|
3106
|
+
unit
|
|
3107
|
+
] })
|
|
2891
3108
|
]
|
|
2892
3109
|
}
|
|
2893
3110
|
);
|
|
2894
3111
|
};
|
|
2895
|
-
var Sparkline = ({ data, width, height, color }) => {
|
|
3112
|
+
var Sparkline = ({ data, width, height, color, forced = false }) => {
|
|
2896
3113
|
if (!data || data.length < 2) {
|
|
2897
3114
|
return null;
|
|
2898
3115
|
}
|
|
@@ -2907,24 +3124,52 @@ var Sparkline = ({ data, width, height, color }) => {
|
|
|
2907
3124
|
const y = height - 8 - (value - min) / range * (height - 8);
|
|
2908
3125
|
return `${x + 4},${y + 4}`;
|
|
2909
3126
|
}).join(" ");
|
|
2910
|
-
return /* @__PURE__ */
|
|
3127
|
+
return /* @__PURE__ */ jsxs9(
|
|
2911
3128
|
"div",
|
|
2912
3129
|
{
|
|
2913
3130
|
style: {
|
|
3131
|
+
position: "relative",
|
|
2914
3132
|
width,
|
|
2915
3133
|
height,
|
|
2916
3134
|
backgroundColor: "rgba(0, 0, 0, 0.7)",
|
|
2917
|
-
border: "1px solid rgba(255, 255, 255, 0.3)",
|
|
3135
|
+
border: forced ? `1px solid ${FORCED_MARK_COLOR.border}` : "1px solid rgba(255, 255, 255, 0.3)",
|
|
2918
3136
|
borderRadius: "4px",
|
|
2919
3137
|
display: "flex",
|
|
2920
3138
|
alignItems: "center",
|
|
2921
3139
|
justifyContent: "center",
|
|
2922
3140
|
boxShadow: "0 1px 3px rgba(0, 0, 0, 0.2)"
|
|
2923
3141
|
},
|
|
2924
|
-
children:
|
|
3142
|
+
children: [
|
|
3143
|
+
/* @__PURE__ */ jsx12("svg", { width, height, children: /* @__PURE__ */ jsx12("polyline", { points, fill: "none", stroke: color, strokeWidth: "1.5", opacity: "0.9" }) }),
|
|
3144
|
+
forced && /* @__PURE__ */ jsx12("span", { style: forcedTagStyle, "aria-label": "Forced", children: "F" })
|
|
3145
|
+
]
|
|
2925
3146
|
}
|
|
2926
3147
|
);
|
|
2927
3148
|
};
|
|
3149
|
+
var EquipmentForcedBadge = () => /* @__PURE__ */ jsx12(
|
|
3150
|
+
"span",
|
|
3151
|
+
{
|
|
3152
|
+
"aria-label": "Forced",
|
|
3153
|
+
style: {
|
|
3154
|
+
position: "absolute",
|
|
3155
|
+
top: "-4px",
|
|
3156
|
+
right: "-4px",
|
|
3157
|
+
width: "11px",
|
|
3158
|
+
height: "11px",
|
|
3159
|
+
borderRadius: "50%",
|
|
3160
|
+
backgroundColor: FORCED_MARK_COLOR.bg,
|
|
3161
|
+
border: `1px solid ${FORCED_MARK_COLOR.border}`,
|
|
3162
|
+
color: FORCED_MARK_COLOR.text,
|
|
3163
|
+
fontSize: "7px",
|
|
3164
|
+
fontWeight: 700,
|
|
3165
|
+
display: "flex",
|
|
3166
|
+
alignItems: "center",
|
|
3167
|
+
justifyContent: "center",
|
|
3168
|
+
lineHeight: 1
|
|
3169
|
+
},
|
|
3170
|
+
children: "F"
|
|
3171
|
+
}
|
|
3172
|
+
);
|
|
2928
3173
|
var EquipmentIndicatorWithSparkline = ({
|
|
2929
3174
|
svgX,
|
|
2930
3175
|
svgY,
|
|
@@ -2932,11 +3177,51 @@ var EquipmentIndicatorWithSparkline = ({
|
|
|
2932
3177
|
label,
|
|
2933
3178
|
size = 30,
|
|
2934
3179
|
sparklineData,
|
|
2935
|
-
sparklineOffset = { x: 40, y: 0 }
|
|
3180
|
+
sparklineOffset = { x: 40, y: 0 },
|
|
3181
|
+
forced = false
|
|
2936
3182
|
}) => {
|
|
2937
3183
|
const hasSparkline = sparklineData && sparklineData.length > 1 && Math.max(...sparklineData) !== Math.min(...sparklineData);
|
|
2938
3184
|
return /* @__PURE__ */ jsxs9(Fragment3, { children: [
|
|
2939
|
-
/* @__PURE__ */ jsx12(SVGLockedOverlay, { svgX, svgY, style: { transform: "translate(-50%, -50%)" }, children: /* @__PURE__ */
|
|
3185
|
+
/* @__PURE__ */ jsx12(SVGLockedOverlay, { svgX, svgY, style: { transform: "translate(-50%, -50%)" }, children: /* @__PURE__ */ jsxs9("div", { style: { position: "relative", width: size, height: size }, children: [
|
|
3186
|
+
/* @__PURE__ */ jsx12(
|
|
3187
|
+
"div",
|
|
3188
|
+
{
|
|
3189
|
+
style: {
|
|
3190
|
+
width: size,
|
|
3191
|
+
height: size,
|
|
3192
|
+
borderRadius: "50%",
|
|
3193
|
+
backgroundColor: color,
|
|
3194
|
+
display: "flex",
|
|
3195
|
+
alignItems: "center",
|
|
3196
|
+
justifyContent: "center",
|
|
3197
|
+
color: "white",
|
|
3198
|
+
fontSize: "7px",
|
|
3199
|
+
fontWeight: "700",
|
|
3200
|
+
textAlign: "center",
|
|
3201
|
+
boxShadow: "0 2px 8px rgba(0, 0, 0, 0.3)",
|
|
3202
|
+
border: forced ? `2px solid ${FORCED_MARK_COLOR.border}` : "2px solid rgba(255, 255, 255, 0.3)"
|
|
3203
|
+
},
|
|
3204
|
+
children: label
|
|
3205
|
+
}
|
|
3206
|
+
),
|
|
3207
|
+
forced && /* @__PURE__ */ jsx12(EquipmentForcedBadge, {})
|
|
3208
|
+
] }) }),
|
|
3209
|
+
hasSparkline && /* @__PURE__ */ jsx12(SVGLockedOverlay, { svgX: svgX + sparklineOffset.x, svgY: svgY + sparklineOffset.y, children: /* @__PURE__ */ jsx12(Sparkline, { data: sparklineData, width: 60, height: 20, color, forced }) })
|
|
3210
|
+
] });
|
|
3211
|
+
};
|
|
3212
|
+
var EquipmentIndicator = ({
|
|
3213
|
+
svgX,
|
|
3214
|
+
svgY,
|
|
3215
|
+
color,
|
|
3216
|
+
label,
|
|
3217
|
+
size = 30,
|
|
3218
|
+
style,
|
|
3219
|
+
className,
|
|
3220
|
+
forced = false
|
|
3221
|
+
}) => {
|
|
3222
|
+
const overlayStyle = style !== void 0 ? { transform: "translate(-50%, -50%)", ...style } : { transform: "translate(-50%, -50%)" };
|
|
3223
|
+
return /* @__PURE__ */ jsx12(SVGLockedOverlay, { svgX, svgY, style: overlayStyle, className, children: /* @__PURE__ */ jsxs9("div", { style: { position: "relative", width: size, height: size }, children: [
|
|
3224
|
+
/* @__PURE__ */ jsx12(
|
|
2940
3225
|
"div",
|
|
2941
3226
|
{
|
|
2942
3227
|
style: {
|
|
@@ -2952,45 +3237,13 @@ var EquipmentIndicatorWithSparkline = ({
|
|
|
2952
3237
|
fontWeight: "700",
|
|
2953
3238
|
textAlign: "center",
|
|
2954
3239
|
boxShadow: "0 2px 8px rgba(0, 0, 0, 0.3)",
|
|
2955
|
-
border: "2px solid rgba(255, 255, 255, 0.3)"
|
|
3240
|
+
border: forced ? `2px solid ${FORCED_MARK_COLOR.border}` : "2px solid rgba(255, 255, 255, 0.3)"
|
|
2956
3241
|
},
|
|
2957
3242
|
children: label
|
|
2958
3243
|
}
|
|
2959
|
-
)
|
|
2960
|
-
|
|
2961
|
-
] });
|
|
2962
|
-
};
|
|
2963
|
-
var EquipmentIndicator = ({
|
|
2964
|
-
svgX,
|
|
2965
|
-
svgY,
|
|
2966
|
-
color,
|
|
2967
|
-
label,
|
|
2968
|
-
size = 30,
|
|
2969
|
-
style,
|
|
2970
|
-
className
|
|
2971
|
-
}) => {
|
|
2972
|
-
const overlayStyle = style !== void 0 ? { transform: "translate(-50%, -50%)", ...style } : { transform: "translate(-50%, -50%)" };
|
|
2973
|
-
return /* @__PURE__ */ jsx12(SVGLockedOverlay, { svgX, svgY, style: overlayStyle, className, children: /* @__PURE__ */ jsx12(
|
|
2974
|
-
"div",
|
|
2975
|
-
{
|
|
2976
|
-
style: {
|
|
2977
|
-
width: size,
|
|
2978
|
-
height: size,
|
|
2979
|
-
borderRadius: "50%",
|
|
2980
|
-
backgroundColor: color,
|
|
2981
|
-
display: "flex",
|
|
2982
|
-
alignItems: "center",
|
|
2983
|
-
justifyContent: "center",
|
|
2984
|
-
color: "white",
|
|
2985
|
-
fontSize: "7px",
|
|
2986
|
-
fontWeight: "700",
|
|
2987
|
-
textAlign: "center",
|
|
2988
|
-
boxShadow: "0 2px 8px rgba(0, 0, 0, 0.3)",
|
|
2989
|
-
border: "2px solid rgba(255, 255, 255, 0.3)"
|
|
2990
|
-
},
|
|
2991
|
-
children: label
|
|
2992
|
-
}
|
|
2993
|
-
) });
|
|
3244
|
+
),
|
|
3245
|
+
forced && /* @__PURE__ */ jsx12(EquipmentForcedBadge, {})
|
|
3246
|
+
] }) });
|
|
2994
3247
|
};
|
|
2995
3248
|
|
|
2996
3249
|
// src/components/layout/FullscreenWorkspace/FullscreenWorkspace.tsx
|
|
@@ -3280,7 +3533,7 @@ var ThemeToggle = ({
|
|
|
3280
3533
|
};
|
|
3281
3534
|
|
|
3282
3535
|
// src/components/PIDCanvas/PIDCanvas.tsx
|
|
3283
|
-
import React13, { useCallback as useCallback8, useState as useState14, useEffect as
|
|
3536
|
+
import React13, { useCallback as useCallback8, useState as useState14, useEffect as useEffect13, useRef as useRef6 } from "react";
|
|
3284
3537
|
|
|
3285
3538
|
// src/components/PIDCanvas/NodeRenderer.tsx
|
|
3286
3539
|
import React9 from "react";
|
|
@@ -3311,6 +3564,25 @@ var mockSymbolLibrary = {
|
|
|
3311
3564
|
tags: ["valve", "gate", "powered", "actuator"]
|
|
3312
3565
|
}
|
|
3313
3566
|
},
|
|
3567
|
+
"status-indicator": {
|
|
3568
|
+
id: "status-indicator",
|
|
3569
|
+
name: "Status LED",
|
|
3570
|
+
category: "instrument",
|
|
3571
|
+
viewBox: { x: 0, y: 0, width: 24, height: 24 },
|
|
3572
|
+
ports: [],
|
|
3573
|
+
svgContent: `
|
|
3574
|
+
<rect x="2" y="2" width="20" height="20"
|
|
3575
|
+
rx="var(--led-rx, 50%)"
|
|
3576
|
+
fill="var(--symbol-fill, #64748b)"
|
|
3577
|
+
stroke="rgba(255,255,255,0.4)"
|
|
3578
|
+
stroke-width="var(--led-bezel, 0)"
|
|
3579
|
+
style="transform-box: fill-box; transform: rotate(var(--led-rotate, 0deg)); transform-origin: center; pointer-events: all;"/>
|
|
3580
|
+
`,
|
|
3581
|
+
metadata: {
|
|
3582
|
+
description: "Status LED indicator driven by telemetry status color",
|
|
3583
|
+
tags: ["status", "led", "indicator", "instrument"]
|
|
3584
|
+
}
|
|
3585
|
+
},
|
|
3314
3586
|
"pump-positive-displacement": {
|
|
3315
3587
|
id: "pump-positive-displacement",
|
|
3316
3588
|
name: "Positive Displacement Pump",
|
|
@@ -4503,8 +4775,144 @@ function getAvailableSymbols() {
|
|
|
4503
4775
|
return [...Object.keys(customSymbols), ...Object.keys(mockSymbolLibrary)];
|
|
4504
4776
|
}
|
|
4505
4777
|
|
|
4778
|
+
// src/diagram/symbols/appearanceSchema.ts
|
|
4779
|
+
var COLOR_PRESETS = {
|
|
4780
|
+
green: "#22c55e",
|
|
4781
|
+
red: "#ef4444",
|
|
4782
|
+
amber: "#f59e0b",
|
|
4783
|
+
blue: "#3b82f6",
|
|
4784
|
+
grey: "#64748b"
|
|
4785
|
+
};
|
|
4786
|
+
function resolvePresetColor(name) {
|
|
4787
|
+
return name && COLOR_PRESETS[name] || COLOR_PRESETS.grey;
|
|
4788
|
+
}
|
|
4789
|
+
var COLOR_OPTIONS = Object.keys(COLOR_PRESETS);
|
|
4790
|
+
var STATUS_LED_APPEARANCE = [
|
|
4791
|
+
{
|
|
4792
|
+
key: "shape",
|
|
4793
|
+
kind: "select",
|
|
4794
|
+
label: "Shape",
|
|
4795
|
+
options: ["circle", "square", "diamond"],
|
|
4796
|
+
default: "circle"
|
|
4797
|
+
},
|
|
4798
|
+
{
|
|
4799
|
+
key: "size",
|
|
4800
|
+
kind: "select",
|
|
4801
|
+
label: "Size",
|
|
4802
|
+
target: "scale",
|
|
4803
|
+
options: ["small", "medium", "large"],
|
|
4804
|
+
default: "medium",
|
|
4805
|
+
valueMap: { small: 0.75, medium: 1, large: 1.5 }
|
|
4806
|
+
},
|
|
4807
|
+
{ key: "led", kind: "boolean", label: "Bezel ring", default: true },
|
|
4808
|
+
{ key: "glow", kind: "boolean", label: "Diffusion (glow)", default: false },
|
|
4809
|
+
{
|
|
4810
|
+
key: "animation",
|
|
4811
|
+
kind: "select",
|
|
4812
|
+
label: "Animation",
|
|
4813
|
+
options: ["none", "pulse", "blink"],
|
|
4814
|
+
default: "none"
|
|
4815
|
+
},
|
|
4816
|
+
{
|
|
4817
|
+
key: "labelPosition",
|
|
4818
|
+
kind: "select",
|
|
4819
|
+
label: "Label position",
|
|
4820
|
+
options: ["bottom", "top", "left", "right"],
|
|
4821
|
+
default: "bottom"
|
|
4822
|
+
},
|
|
4823
|
+
// Color binding: a named signal drives the on/off color.
|
|
4824
|
+
{
|
|
4825
|
+
key: "colorSource",
|
|
4826
|
+
kind: "tag",
|
|
4827
|
+
label: "Color source (tag)",
|
|
4828
|
+
default: "",
|
|
4829
|
+
help: "Signal/tag that drives color. True (non-zero) shows On color; false shows Off color. Blank = unbound (grey)."
|
|
4830
|
+
},
|
|
4831
|
+
{
|
|
4832
|
+
key: "onColor",
|
|
4833
|
+
kind: "select",
|
|
4834
|
+
label: "On color (true)",
|
|
4835
|
+
options: COLOR_OPTIONS,
|
|
4836
|
+
default: "green",
|
|
4837
|
+
help: "Color when the Color source is true."
|
|
4838
|
+
},
|
|
4839
|
+
{
|
|
4840
|
+
key: "offColor",
|
|
4841
|
+
kind: "select",
|
|
4842
|
+
label: "Off color (false)",
|
|
4843
|
+
options: COLOR_OPTIONS,
|
|
4844
|
+
default: "red",
|
|
4845
|
+
help: "Color when the Color source is false."
|
|
4846
|
+
},
|
|
4847
|
+
// Visibility binding: an independent named signal drives show/hide.
|
|
4848
|
+
{
|
|
4849
|
+
key: "visibleSource",
|
|
4850
|
+
kind: "tag",
|
|
4851
|
+
label: "Visibility source (tag)",
|
|
4852
|
+
default: "",
|
|
4853
|
+
help: "Signal/tag that drives visibility. True shows the LED, false hides it. Blank = always visible (use the Visible checkbox)."
|
|
4854
|
+
},
|
|
4855
|
+
{
|
|
4856
|
+
key: "visible",
|
|
4857
|
+
kind: "boolean",
|
|
4858
|
+
label: "Visible",
|
|
4859
|
+
target: "visible",
|
|
4860
|
+
default: true,
|
|
4861
|
+
help: "Static show/hide, used only when no Visibility source is set."
|
|
4862
|
+
}
|
|
4863
|
+
];
|
|
4864
|
+
var APPEARANCE_REGISTRY = {
|
|
4865
|
+
"status-indicator": STATUS_LED_APPEARANCE
|
|
4866
|
+
};
|
|
4867
|
+
function getAppearanceSchema(symbolId) {
|
|
4868
|
+
return APPEARANCE_REGISTRY[symbolId] ?? [];
|
|
4869
|
+
}
|
|
4870
|
+
function getAppearanceDefaults(symbolId) {
|
|
4871
|
+
const out = {};
|
|
4872
|
+
for (const field of getAppearanceSchema(symbolId)) {
|
|
4873
|
+
if ((field.target ?? "metadata") === "metadata" && field.default !== void 0) {
|
|
4874
|
+
out[field.key] = field.default;
|
|
4875
|
+
}
|
|
4876
|
+
}
|
|
4877
|
+
return out;
|
|
4878
|
+
}
|
|
4879
|
+
function readAppearanceValue(node, field) {
|
|
4880
|
+
if (field.target === "visible") {
|
|
4881
|
+
return node.visible ?? field.default ?? true;
|
|
4882
|
+
}
|
|
4883
|
+
if (field.target === "scale") {
|
|
4884
|
+
const scale = node.transform.scale ?? 1;
|
|
4885
|
+
if (field.valueMap) {
|
|
4886
|
+
let bestOption = field.options?.[0] ?? String(scale);
|
|
4887
|
+
let bestDiff = Infinity;
|
|
4888
|
+
for (const [option, value2] of Object.entries(field.valueMap)) {
|
|
4889
|
+
const diff = Math.abs(value2 - scale);
|
|
4890
|
+
if (diff < bestDiff) {
|
|
4891
|
+
bestDiff = diff;
|
|
4892
|
+
bestOption = option;
|
|
4893
|
+
}
|
|
4894
|
+
}
|
|
4895
|
+
return bestOption;
|
|
4896
|
+
}
|
|
4897
|
+
return scale;
|
|
4898
|
+
}
|
|
4899
|
+
const value = node.metadata?.[field.key];
|
|
4900
|
+
return value ?? field.default;
|
|
4901
|
+
}
|
|
4902
|
+
function writeAppearanceValue(node, field, value) {
|
|
4903
|
+
if (field.target === "visible") {
|
|
4904
|
+
return { visible: Boolean(value) };
|
|
4905
|
+
}
|
|
4906
|
+
if (field.target === "scale") {
|
|
4907
|
+
const scale = field.valueMap ? field.valueMap[String(value)] ?? 1 : Number(value);
|
|
4908
|
+
return { transform: { ...node.transform, scale } };
|
|
4909
|
+
}
|
|
4910
|
+
return { metadata: { ...node.metadata, [field.key]: value } };
|
|
4911
|
+
}
|
|
4912
|
+
|
|
4506
4913
|
// src/components/PIDCanvas/NodeRenderer.tsx
|
|
4507
4914
|
import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
4915
|
+
var HATCH_SIZE = 6;
|
|
4508
4916
|
function NodeRendererImpl({
|
|
4509
4917
|
nodes: nodes2,
|
|
4510
4918
|
selectedNodeIds,
|
|
@@ -4516,140 +4924,206 @@ function NodeRendererImpl({
|
|
|
4516
4924
|
enableDrag = false,
|
|
4517
4925
|
statusColorMap
|
|
4518
4926
|
}) {
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
return /* @__PURE__ */ jsxs12("g", { children: [
|
|
4525
|
-
/* @__PURE__ */ jsx16(
|
|
4526
|
-
"circle",
|
|
4527
|
-
{
|
|
4528
|
-
cx: node.transform.x,
|
|
4529
|
-
cy: node.transform.y,
|
|
4530
|
-
r: "15",
|
|
4531
|
-
fill: "#ff0000",
|
|
4532
|
-
opacity: "0.3",
|
|
4533
|
-
stroke: "#ff0000",
|
|
4534
|
-
strokeWidth: "2"
|
|
4535
|
-
}
|
|
4536
|
-
),
|
|
4537
|
-
/* @__PURE__ */ jsx16(
|
|
4538
|
-
"text",
|
|
4539
|
-
{
|
|
4540
|
-
x: node.transform.x,
|
|
4541
|
-
y: node.transform.y,
|
|
4542
|
-
textAnchor: "middle",
|
|
4543
|
-
dominantBaseline: "middle",
|
|
4544
|
-
fontSize: "10",
|
|
4545
|
-
fill: "#ff0000",
|
|
4546
|
-
children: "?"
|
|
4547
|
-
}
|
|
4548
|
-
)
|
|
4549
|
-
] }, node.id);
|
|
4550
|
-
}
|
|
4551
|
-
const transforms = [];
|
|
4552
|
-
const effectiveX = isDragging ? node.transform.x + dragOffset.x : node.transform.x;
|
|
4553
|
-
const effectiveY = isDragging ? node.transform.y + dragOffset.y : node.transform.y;
|
|
4554
|
-
transforms.push(`translate(${effectiveX}, ${effectiveY})`);
|
|
4555
|
-
if (node.transform.rotation) {
|
|
4556
|
-
const centerX = symbol.viewBox.width / 2;
|
|
4557
|
-
const centerY = symbol.viewBox.height / 2;
|
|
4558
|
-
transforms.push(`rotate(${node.transform.rotation}, ${centerX}, ${centerY})`);
|
|
4559
|
-
}
|
|
4560
|
-
if (node.transform.scale && node.transform.scale !== 1) {
|
|
4561
|
-
const centerX = symbol.viewBox.width / 2;
|
|
4562
|
-
const centerY = symbol.viewBox.height / 2;
|
|
4563
|
-
transforms.push(
|
|
4564
|
-
`translate(${centerX}, ${centerY}) scale(${node.transform.scale}) translate(${-centerX}, ${-centerY})`
|
|
4565
|
-
);
|
|
4566
|
-
}
|
|
4567
|
-
if (node.transform.flipX || node.transform.flipY) {
|
|
4568
|
-
const scaleX = node.transform.flipX ? -1 : 1;
|
|
4569
|
-
const scaleY = node.transform.flipY ? -1 : 1;
|
|
4570
|
-
const centerX = symbol.viewBox.width / 2;
|
|
4571
|
-
const centerY = symbol.viewBox.height / 2;
|
|
4572
|
-
transforms.push(
|
|
4573
|
-
`translate(${centerX}, ${centerY}) scale(${scaleX}, ${scaleY}) translate(${-centerX}, ${-centerY})`
|
|
4574
|
-
);
|
|
4575
|
-
}
|
|
4576
|
-
const statusEntry = resolveStatusColor(node.status, statusColorMap);
|
|
4577
|
-
const fillColor = node.customColors?.fill ?? statusEntry.fill;
|
|
4578
|
-
const strokeColor = node.customColors?.stroke ?? statusEntry.stroke;
|
|
4579
|
-
return /* @__PURE__ */ jsxs12(
|
|
4580
|
-
"g",
|
|
4927
|
+
const hatchId = `pid-unknown-hatch-${React9.useId().replace(/[^A-Za-z0-9_-]/g, "")}`;
|
|
4928
|
+
const hasUnknown = nodes2.some((n) => n.positionUnknown === true && n.visible !== false);
|
|
4929
|
+
return /* @__PURE__ */ jsxs12("g", { id: "layer-nodes", children: [
|
|
4930
|
+
hasUnknown && /* @__PURE__ */ jsx16("defs", { children: /* @__PURE__ */ jsxs12(
|
|
4931
|
+
"pattern",
|
|
4581
4932
|
{
|
|
4582
|
-
|
|
4583
|
-
"data-
|
|
4584
|
-
"
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
"--symbol-fill": fillColor,
|
|
4589
|
-
"--symbol-stroke": strokeColor,
|
|
4590
|
-
cursor: enableDrag ? isDragging ? "grabbing" : "grab" : onNodeClick ? "pointer" : "default"
|
|
4591
|
-
},
|
|
4592
|
-
onClick: (e) => {
|
|
4593
|
-
e.stopPropagation();
|
|
4594
|
-
onNodeClick?.(node.id, e);
|
|
4595
|
-
},
|
|
4596
|
-
onDoubleClick: (e) => {
|
|
4597
|
-
e.stopPropagation();
|
|
4598
|
-
onNodeDoubleClick?.(node.id, e);
|
|
4599
|
-
},
|
|
4600
|
-
onMouseDown: (e) => {
|
|
4601
|
-
if (enableDrag) {
|
|
4602
|
-
onNodeDragStart?.(node.id, e);
|
|
4603
|
-
}
|
|
4604
|
-
},
|
|
4605
|
-
onTouchStart: (e) => {
|
|
4606
|
-
if (enableDrag) {
|
|
4607
|
-
e.stopPropagation();
|
|
4608
|
-
onNodeDragStart?.(node.id, e);
|
|
4609
|
-
}
|
|
4610
|
-
},
|
|
4933
|
+
id: hatchId,
|
|
4934
|
+
"data-testid": "position-unknown-pattern",
|
|
4935
|
+
patternUnits: "userSpaceOnUse",
|
|
4936
|
+
width: HATCH_SIZE,
|
|
4937
|
+
height: HATCH_SIZE,
|
|
4938
|
+
patternTransform: "rotate(45)",
|
|
4611
4939
|
children: [
|
|
4612
|
-
|
|
4613
|
-
|
|
4940
|
+
/* @__PURE__ */ jsx16("rect", { width: HATCH_SIZE, height: HATCH_SIZE, fill: UNKNOWN_MARK_COLOR.fill }),
|
|
4941
|
+
/* @__PURE__ */ jsx16(
|
|
4942
|
+
"line",
|
|
4614
4943
|
{
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
strokeWidth: isDragging ? "3" : "2",
|
|
4622
|
-
strokeDasharray: "4 2",
|
|
4623
|
-
rx: "2",
|
|
4624
|
-
pointerEvents: "none"
|
|
4944
|
+
x1: "0",
|
|
4945
|
+
y1: "0",
|
|
4946
|
+
x2: "0",
|
|
4947
|
+
y2: HATCH_SIZE,
|
|
4948
|
+
stroke: UNKNOWN_MARK_COLOR.text,
|
|
4949
|
+
strokeWidth: "2"
|
|
4625
4950
|
}
|
|
4626
|
-
)
|
|
4951
|
+
)
|
|
4952
|
+
]
|
|
4953
|
+
}
|
|
4954
|
+
) }),
|
|
4955
|
+
nodes2.filter((node) => node.visible !== false).map((node) => {
|
|
4956
|
+
const symbol = getSymbolDefinition(node.symbolId);
|
|
4957
|
+
const isSelected = selectedNodeIds?.has(node.id) ?? false;
|
|
4958
|
+
const isDragging = draggingNodeId === node.id;
|
|
4959
|
+
if (!symbol) {
|
|
4960
|
+
return /* @__PURE__ */ jsxs12("g", { children: [
|
|
4627
4961
|
/* @__PURE__ */ jsx16(
|
|
4628
|
-
"
|
|
4962
|
+
"circle",
|
|
4629
4963
|
{
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4964
|
+
cx: node.transform.x,
|
|
4965
|
+
cy: node.transform.y,
|
|
4966
|
+
r: "15",
|
|
4967
|
+
fill: "#ff0000",
|
|
4968
|
+
opacity: "0.3",
|
|
4969
|
+
stroke: "#ff0000",
|
|
4970
|
+
strokeWidth: "2"
|
|
4633
4971
|
}
|
|
4634
4972
|
),
|
|
4635
4973
|
/* @__PURE__ */ jsx16(
|
|
4636
4974
|
"text",
|
|
4637
4975
|
{
|
|
4638
|
-
x:
|
|
4639
|
-
y:
|
|
4976
|
+
x: node.transform.x,
|
|
4977
|
+
y: node.transform.y,
|
|
4640
4978
|
textAnchor: "middle",
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
fill:
|
|
4644
|
-
|
|
4645
|
-
children: node.label || node.id
|
|
4979
|
+
dominantBaseline: "middle",
|
|
4980
|
+
fontSize: "10",
|
|
4981
|
+
fill: "#ff0000",
|
|
4982
|
+
children: "?"
|
|
4646
4983
|
}
|
|
4647
4984
|
)
|
|
4648
|
-
]
|
|
4649
|
-
}
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4985
|
+
] }, node.id);
|
|
4986
|
+
}
|
|
4987
|
+
const transforms = [];
|
|
4988
|
+
const effectiveX = isDragging ? node.transform.x + dragOffset.x : node.transform.x;
|
|
4989
|
+
const effectiveY = isDragging ? node.transform.y + dragOffset.y : node.transform.y;
|
|
4990
|
+
transforms.push(`translate(${effectiveX}, ${effectiveY})`);
|
|
4991
|
+
if (node.transform.rotation) {
|
|
4992
|
+
const centerX = symbol.viewBox.width / 2;
|
|
4993
|
+
const centerY = symbol.viewBox.height / 2;
|
|
4994
|
+
transforms.push(`rotate(${node.transform.rotation}, ${centerX}, ${centerY})`);
|
|
4995
|
+
}
|
|
4996
|
+
if (node.transform.scale && node.transform.scale !== 1) {
|
|
4997
|
+
const centerX = symbol.viewBox.width / 2;
|
|
4998
|
+
const centerY = symbol.viewBox.height / 2;
|
|
4999
|
+
transforms.push(
|
|
5000
|
+
`translate(${centerX}, ${centerY}) scale(${node.transform.scale}) translate(${-centerX}, ${-centerY})`
|
|
5001
|
+
);
|
|
5002
|
+
}
|
|
5003
|
+
if (node.transform.flipX || node.transform.flipY) {
|
|
5004
|
+
const scaleX = node.transform.flipX ? -1 : 1;
|
|
5005
|
+
const scaleY = node.transform.flipY ? -1 : 1;
|
|
5006
|
+
const centerX = symbol.viewBox.width / 2;
|
|
5007
|
+
const centerY = symbol.viewBox.height / 2;
|
|
5008
|
+
transforms.push(
|
|
5009
|
+
`translate(${centerX}, ${centerY}) scale(${scaleX}, ${scaleY}) translate(${-centerX}, ${-centerY})`
|
|
5010
|
+
);
|
|
5011
|
+
}
|
|
5012
|
+
const statusEntry = resolveStatusColor(node.status, statusColorMap);
|
|
5013
|
+
const isUnknown = node.positionUnknown === true;
|
|
5014
|
+
const fillColor = isUnknown ? `url(#${hatchId})` : node.customColors?.fill ?? statusEntry.fill;
|
|
5015
|
+
const strokeColor = isUnknown ? UNKNOWN_MARK_COLOR.stroke : node.customColors?.stroke ?? statusEntry.stroke;
|
|
5016
|
+
const appearance = { ...getAppearanceDefaults(node.symbolId), ...node.metadata ?? {} };
|
|
5017
|
+
const ledStyle = {};
|
|
5018
|
+
if (appearance.shape !== void 0) {
|
|
5019
|
+
ledStyle["--led-rx"] = appearance.shape === "circle" ? "50%" : "2";
|
|
5020
|
+
ledStyle["--led-rotate"] = appearance.shape === "diamond" ? "45deg" : "0deg";
|
|
5021
|
+
}
|
|
5022
|
+
if (appearance.led !== void 0) {
|
|
5023
|
+
ledStyle["--led-bezel"] = appearance.led ? "2" : "0";
|
|
5024
|
+
}
|
|
5025
|
+
if (appearance.glow) {
|
|
5026
|
+
ledStyle.filter = `drop-shadow(0 0 4px ${fillColor})`;
|
|
5027
|
+
}
|
|
5028
|
+
const ledAnimation = typeof appearance.animation === "string" && appearance.animation !== "none" ? appearance.animation : void 0;
|
|
5029
|
+
const vb = symbol.viewBox;
|
|
5030
|
+
const ox = node.labelOffset?.x ?? 0;
|
|
5031
|
+
const oy = node.labelOffset?.y ?? 0;
|
|
5032
|
+
const labelPos = typeof appearance.labelPosition === "string" ? appearance.labelPosition : "bottom";
|
|
5033
|
+
let labelX = vb.width / 2 + ox;
|
|
5034
|
+
let labelY = vb.height + 12 + oy;
|
|
5035
|
+
let labelAnchor = "middle";
|
|
5036
|
+
if (labelPos === "top") {
|
|
5037
|
+
labelX = vb.width / 2 + ox;
|
|
5038
|
+
labelY = -6 + oy;
|
|
5039
|
+
labelAnchor = "middle";
|
|
5040
|
+
} else if (labelPos === "left") {
|
|
5041
|
+
labelX = -6 + ox;
|
|
5042
|
+
labelY = vb.height / 2 + oy;
|
|
5043
|
+
labelAnchor = "end";
|
|
5044
|
+
} else if (labelPos === "right") {
|
|
5045
|
+
labelX = vb.width + 6 + ox;
|
|
5046
|
+
labelY = vb.height / 2 + oy;
|
|
5047
|
+
labelAnchor = "start";
|
|
5048
|
+
}
|
|
5049
|
+
return /* @__PURE__ */ jsxs12(
|
|
5050
|
+
"g",
|
|
5051
|
+
{
|
|
5052
|
+
"data-node-id": node.id,
|
|
5053
|
+
"data-symbol-id": node.symbolId,
|
|
5054
|
+
"data-selected": isSelected,
|
|
5055
|
+
"data-dragging": isDragging,
|
|
5056
|
+
"data-led-animation": ledAnimation,
|
|
5057
|
+
"data-position-unknown": isUnknown ? "true" : void 0,
|
|
5058
|
+
transform: transforms.join(" "),
|
|
5059
|
+
style: {
|
|
5060
|
+
"--symbol-fill": fillColor,
|
|
5061
|
+
"--symbol-stroke": strokeColor,
|
|
5062
|
+
cursor: enableDrag ? isDragging ? "grabbing" : "grab" : onNodeClick ? "pointer" : "default",
|
|
5063
|
+
...ledStyle
|
|
5064
|
+
},
|
|
5065
|
+
onClick: (e) => {
|
|
5066
|
+
e.stopPropagation();
|
|
5067
|
+
onNodeClick?.(node.id, e);
|
|
5068
|
+
},
|
|
5069
|
+
onDoubleClick: (e) => {
|
|
5070
|
+
e.stopPropagation();
|
|
5071
|
+
onNodeDoubleClick?.(node.id, e);
|
|
5072
|
+
},
|
|
5073
|
+
onMouseDown: (e) => {
|
|
5074
|
+
if (enableDrag) {
|
|
5075
|
+
onNodeDragStart?.(node.id, e);
|
|
5076
|
+
}
|
|
5077
|
+
},
|
|
5078
|
+
onTouchStart: (e) => {
|
|
5079
|
+
if (enableDrag) {
|
|
5080
|
+
e.stopPropagation();
|
|
5081
|
+
onNodeDragStart?.(node.id, e);
|
|
5082
|
+
}
|
|
5083
|
+
},
|
|
5084
|
+
children: [
|
|
5085
|
+
isSelected && /* @__PURE__ */ jsx16(
|
|
5086
|
+
"rect",
|
|
5087
|
+
{
|
|
5088
|
+
x: "-5",
|
|
5089
|
+
y: "-5",
|
|
5090
|
+
width: symbol.viewBox.width + 10,
|
|
5091
|
+
height: symbol.viewBox.height + 10,
|
|
5092
|
+
fill: "none",
|
|
5093
|
+
stroke: isDragging ? "#10b981" : "#3b82f6",
|
|
5094
|
+
strokeWidth: isDragging ? "3" : "2",
|
|
5095
|
+
strokeDasharray: "4 2",
|
|
5096
|
+
rx: "2",
|
|
5097
|
+
pointerEvents: "none"
|
|
5098
|
+
}
|
|
5099
|
+
),
|
|
5100
|
+
/* @__PURE__ */ jsx16(
|
|
5101
|
+
"g",
|
|
5102
|
+
{
|
|
5103
|
+
dangerouslySetInnerHTML: { __html: symbol.svgContent },
|
|
5104
|
+
"data-symbol-content": symbol.id,
|
|
5105
|
+
style: { pointerEvents: "auto" }
|
|
5106
|
+
}
|
|
5107
|
+
),
|
|
5108
|
+
/* @__PURE__ */ jsx16(
|
|
5109
|
+
"text",
|
|
5110
|
+
{
|
|
5111
|
+
x: labelX,
|
|
5112
|
+
y: labelY,
|
|
5113
|
+
textAnchor: labelAnchor,
|
|
5114
|
+
fontSize: node.labelFontSize ?? 10,
|
|
5115
|
+
fontWeight: "600",
|
|
5116
|
+
fill: isSelected ? "#3b82f6" : "#1f2937",
|
|
5117
|
+
transform: node.transform.rotation ? `rotate(${-node.transform.rotation}, ${labelX}, ${labelY})` : void 0,
|
|
5118
|
+
children: node.label || node.id
|
|
5119
|
+
}
|
|
5120
|
+
)
|
|
5121
|
+
]
|
|
5122
|
+
},
|
|
5123
|
+
node.id
|
|
5124
|
+
);
|
|
5125
|
+
})
|
|
5126
|
+
] });
|
|
4653
5127
|
}
|
|
4654
5128
|
var NodeRenderer = React9.memo(NodeRendererImpl);
|
|
4655
5129
|
|
|
@@ -4870,7 +5344,9 @@ function DataOverlayImpl({
|
|
|
4870
5344
|
scale = 1,
|
|
4871
5345
|
statusColorMap
|
|
4872
5346
|
}) {
|
|
4873
|
-
const { value, display, history, scaling } = telemetry;
|
|
5347
|
+
const { value, display, history, scaling, forced } = telemetry;
|
|
5348
|
+
const isForced = forced?.active === true;
|
|
5349
|
+
const hasRealValue = isForced && forced?.realValue !== void 0;
|
|
4874
5350
|
const showValue = display?.showValue ?? true;
|
|
4875
5351
|
const showStatus = display?.showStatus ?? true;
|
|
4876
5352
|
const showSparkline = display?.showSparkline ?? false;
|
|
@@ -4919,12 +5395,16 @@ function DataOverlayImpl({
|
|
|
4919
5395
|
const finalTextColor = textColor || colors.text;
|
|
4920
5396
|
const formattedValue = formatValue(value.value);
|
|
4921
5397
|
const displayText = unit ? `${formattedValue} ${unit}` : formattedValue;
|
|
5398
|
+
const realDisplayText = hasRealValue ? unit ? `REAL ${formatValue(forced.realValue)} ${unit}` : `REAL ${formatValue(forced.realValue)}` : void 0;
|
|
5399
|
+
const borderColor = isForced ? FORCED_MARK_COLOR.border : colors.border;
|
|
5400
|
+
const borderWidth = (isForced ? 2 : 1) * scale;
|
|
4922
5401
|
const hasSparkline = showSparkline && sparklinePath;
|
|
4923
|
-
const
|
|
5402
|
+
const extraMarkRows = realDisplayText ? 1 : 0;
|
|
5403
|
+
const overlayHeight = (label ? hasSparkline ? 55 : 30 : hasSparkline ? 47 : 22) * scale + extraMarkRows * 9 * scale;
|
|
4924
5404
|
const overlayWidth = 80 * scale;
|
|
4925
5405
|
const displayX = x + offsetX;
|
|
4926
5406
|
const displayY = y + offsetY;
|
|
4927
|
-
return /* @__PURE__ */ jsxs14("g", { "data-overlay-node": nodeId, "data-status": value.status, children: [
|
|
5407
|
+
return /* @__PURE__ */ jsxs14("g", { "data-overlay-node": nodeId, "data-status": value.status, "data-forced": isForced, children: [
|
|
4928
5408
|
/* @__PURE__ */ jsx18(
|
|
4929
5409
|
"rect",
|
|
4930
5410
|
{
|
|
@@ -4934,8 +5414,8 @@ function DataOverlayImpl({
|
|
|
4934
5414
|
height: overlayHeight,
|
|
4935
5415
|
rx: 4 * scale,
|
|
4936
5416
|
fill: colors.bg,
|
|
4937
|
-
stroke:
|
|
4938
|
-
strokeWidth:
|
|
5417
|
+
stroke: borderColor,
|
|
5418
|
+
strokeWidth: borderWidth,
|
|
4939
5419
|
opacity: "0.95",
|
|
4940
5420
|
filter: "drop-shadow(0 2px 4px rgba(0,0,0,0.2))"
|
|
4941
5421
|
}
|
|
@@ -4984,6 +5464,48 @@ function DataOverlayImpl({
|
|
|
4984
5464
|
]
|
|
4985
5465
|
}
|
|
4986
5466
|
),
|
|
5467
|
+
isForced && /* @__PURE__ */ jsxs14(
|
|
5468
|
+
"g",
|
|
5469
|
+
{
|
|
5470
|
+
transform: `translate(${displayX + overlayWidth / 2}, ${displayY - 25 * scale})`,
|
|
5471
|
+
"aria-label": "Forced",
|
|
5472
|
+
children: [
|
|
5473
|
+
/* @__PURE__ */ jsx18(
|
|
5474
|
+
"circle",
|
|
5475
|
+
{
|
|
5476
|
+
r: 7 * scale,
|
|
5477
|
+
fill: FORCED_MARK_COLOR.bg,
|
|
5478
|
+
stroke: FORCED_MARK_COLOR.border,
|
|
5479
|
+
strokeWidth: 1.5 * scale
|
|
5480
|
+
}
|
|
5481
|
+
),
|
|
5482
|
+
/* @__PURE__ */ jsx18(
|
|
5483
|
+
"text",
|
|
5484
|
+
{
|
|
5485
|
+
textAnchor: "middle",
|
|
5486
|
+
dominantBaseline: "central",
|
|
5487
|
+
fontSize: 8 * scale,
|
|
5488
|
+
fontWeight: "700",
|
|
5489
|
+
fill: FORCED_MARK_COLOR.text,
|
|
5490
|
+
children: "F"
|
|
5491
|
+
}
|
|
5492
|
+
)
|
|
5493
|
+
]
|
|
5494
|
+
}
|
|
5495
|
+
),
|
|
5496
|
+
realDisplayText && /* @__PURE__ */ jsx18(
|
|
5497
|
+
"text",
|
|
5498
|
+
{
|
|
5499
|
+
x: displayX,
|
|
5500
|
+
y: displayY + (value.quality !== void 0 && value.quality < 100 ? 14 : 5) * scale,
|
|
5501
|
+
textAnchor: "middle",
|
|
5502
|
+
fontSize: 7 * scale,
|
|
5503
|
+
fontWeight: "500",
|
|
5504
|
+
fill: finalTextColor,
|
|
5505
|
+
opacity: "0.85",
|
|
5506
|
+
children: realDisplayText
|
|
5507
|
+
}
|
|
5508
|
+
),
|
|
4987
5509
|
hasSparkline && /* @__PURE__ */ jsx18("g", { transform: `translate(${displayX - 35 * scale}, ${displayY + (label ? 5 : 0) * scale})`, children: /* @__PURE__ */ jsx18(
|
|
4988
5510
|
"path",
|
|
4989
5511
|
{
|
|
@@ -5751,8 +6273,49 @@ function useTelemetryStatus(telemetry, diagram, setDiagram, options = {}) {
|
|
|
5751
6273
|
}, [telemetry, diagram, setDiagram, enabled, mapStatus]);
|
|
5752
6274
|
}
|
|
5753
6275
|
|
|
6276
|
+
// src/diagram/hooks/useBooleanIndicators.ts
|
|
6277
|
+
import { useEffect as useEffect10 } from "react";
|
|
6278
|
+
function useBooleanIndicators(telemetry, diagram, setDiagram, options = {}) {
|
|
6279
|
+
const { enabled = true, symbolId = "status-indicator" } = options;
|
|
6280
|
+
useEffect10(() => {
|
|
6281
|
+
if (!enabled) return;
|
|
6282
|
+
const tagIndex = /* @__PURE__ */ new Map();
|
|
6283
|
+
telemetry.forEach((binding) => {
|
|
6284
|
+
if (binding.tag) tagIndex.set(binding.tag, binding.value.value);
|
|
6285
|
+
});
|
|
6286
|
+
let needsUpdate = false;
|
|
6287
|
+
const updatedNodes = diagram.nodes.map((node) => {
|
|
6288
|
+
if (node.symbolId !== symbolId) return node;
|
|
6289
|
+
const meta = node.metadata ?? {};
|
|
6290
|
+
const colorSource = typeof meta.colorSource === "string" ? meta.colorSource : "";
|
|
6291
|
+
const visibleSource = typeof meta.visibleSource === "string" ? meta.visibleSource : "";
|
|
6292
|
+
let next = node;
|
|
6293
|
+
if (colorSource) {
|
|
6294
|
+
const isTrue = Boolean(tagIndex.get(colorSource));
|
|
6295
|
+
const fill = resolvePresetColor(
|
|
6296
|
+
String(isTrue ? meta.onColor ?? "green" : meta.offColor ?? "red")
|
|
6297
|
+
);
|
|
6298
|
+
if (node.customColors?.fill !== fill) {
|
|
6299
|
+
next = { ...next, customColors: { ...next.customColors, fill } };
|
|
6300
|
+
}
|
|
6301
|
+
}
|
|
6302
|
+
if (visibleSource) {
|
|
6303
|
+
const vis = Boolean(tagIndex.get(visibleSource));
|
|
6304
|
+
if ((next.visible ?? true) !== vis) {
|
|
6305
|
+
next = { ...next, visible: vis };
|
|
6306
|
+
}
|
|
6307
|
+
}
|
|
6308
|
+
if (next !== node) needsUpdate = true;
|
|
6309
|
+
return next;
|
|
6310
|
+
});
|
|
6311
|
+
if (needsUpdate) {
|
|
6312
|
+
setDiagram({ ...diagram, nodes: updatedNodes });
|
|
6313
|
+
}
|
|
6314
|
+
}, [telemetry, diagram, setDiagram, enabled, symbolId]);
|
|
6315
|
+
}
|
|
6316
|
+
|
|
5754
6317
|
// src/diagram/hooks/useDrag.ts
|
|
5755
|
-
import { useState as useState13, useCallback as useCallback7, useRef as useRef5, useEffect as
|
|
6318
|
+
import { useState as useState13, useCallback as useCallback7, useRef as useRef5, useEffect as useEffect11 } from "react";
|
|
5756
6319
|
function useDrag(options = {}) {
|
|
5757
6320
|
const {
|
|
5758
6321
|
onDragStart,
|
|
@@ -5937,7 +6500,7 @@ function useDrag(options = {}) {
|
|
|
5937
6500
|
},
|
|
5938
6501
|
[screenToWorld, applySnap, onDragEnd]
|
|
5939
6502
|
);
|
|
5940
|
-
|
|
6503
|
+
useEffect11(() => {
|
|
5941
6504
|
if (!isListening) return;
|
|
5942
6505
|
document.addEventListener("mousemove", handleMouseMove);
|
|
5943
6506
|
document.addEventListener("mouseup", handleMouseUp);
|
|
@@ -6006,7 +6569,7 @@ function useDrag(options = {}) {
|
|
|
6006
6569
|
}
|
|
6007
6570
|
|
|
6008
6571
|
// src/diagram/hooks/useKeyboardShortcuts.ts
|
|
6009
|
-
import { useEffect as
|
|
6572
|
+
import { useEffect as useEffect12 } from "react";
|
|
6010
6573
|
function useKeyboardShortcuts(options) {
|
|
6011
6574
|
const {
|
|
6012
6575
|
onDelete,
|
|
@@ -6017,7 +6580,7 @@ function useKeyboardShortcuts(options) {
|
|
|
6017
6580
|
onSelectAll,
|
|
6018
6581
|
enabled = true
|
|
6019
6582
|
} = options;
|
|
6020
|
-
|
|
6583
|
+
useEffect12(() => {
|
|
6021
6584
|
if (!enabled) return;
|
|
6022
6585
|
const handleKeyDown = (event) => {
|
|
6023
6586
|
const target = event.target;
|
|
@@ -6169,7 +6732,7 @@ function PIDCanvasImpl({
|
|
|
6169
6732
|
const isUndoRedoAction = useRef6(false);
|
|
6170
6733
|
const isInternalChange = useRef6(false);
|
|
6171
6734
|
const lastInternalDiagram = useRef6(null);
|
|
6172
|
-
|
|
6735
|
+
useEffect13(() => {
|
|
6173
6736
|
const isExternal = !isInternalChange.current && diagram !== lastInternalDiagram.current;
|
|
6174
6737
|
if (isExternal) {
|
|
6175
6738
|
setLocalDiagram(diagram);
|
|
@@ -6214,7 +6777,7 @@ function PIDCanvasImpl({
|
|
|
6214
6777
|
});
|
|
6215
6778
|
return { minX, minY, maxX, maxY };
|
|
6216
6779
|
}, [localDiagram.nodes]);
|
|
6217
|
-
|
|
6780
|
+
useEffect13(() => {
|
|
6218
6781
|
if (onMounted) {
|
|
6219
6782
|
const controls = {
|
|
6220
6783
|
fitToContent: (padding = 50) => {
|
|
@@ -6293,7 +6856,7 @@ function PIDCanvasImpl({
|
|
|
6293
6856
|
isUndoRedoAction.current = false;
|
|
6294
6857
|
}, 0);
|
|
6295
6858
|
}, [localDiagram, onDiagramChange]);
|
|
6296
|
-
|
|
6859
|
+
useEffect13(() => {
|
|
6297
6860
|
const handleKeyDown = (e) => {
|
|
6298
6861
|
const isCtrlOrCmd = e.ctrlKey || e.metaKey;
|
|
6299
6862
|
if (isCtrlOrCmd && e.key === "z" && !e.shiftKey) {
|
|
@@ -6310,7 +6873,7 @@ function PIDCanvasImpl({
|
|
|
6310
6873
|
window.addEventListener("keydown", handleKeyDown);
|
|
6311
6874
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
6312
6875
|
}, [undo, redo]);
|
|
6313
|
-
|
|
6876
|
+
useEffect13(() => {
|
|
6314
6877
|
if (!features.dragNodes) return;
|
|
6315
6878
|
const handleKeyDown = (e) => {
|
|
6316
6879
|
if (selection.selectedNodeIds.size === 0 && !selectedWaypoint) return;
|
|
@@ -6847,6 +7410,7 @@ function PIDCanvasImpl({
|
|
|
6847
7410
|
}
|
|
6848
7411
|
),
|
|
6849
7412
|
telemetryEnabled && telemetry && /* @__PURE__ */ jsx20("g", { id: "layer-telemetry", children: displayDiagram.nodes.map((node) => {
|
|
7413
|
+
if (node.symbolId === "status-indicator") return null;
|
|
6850
7414
|
const binding = telemetry.get(node.id);
|
|
6851
7415
|
if (!binding) return null;
|
|
6852
7416
|
const symbol = getSymbolDefinition(node.symbolId);
|
|
@@ -7214,6 +7778,8 @@ function NodeConfigPanel({
|
|
|
7214
7778
|
onUpdateNode,
|
|
7215
7779
|
onUpdateTelemetry,
|
|
7216
7780
|
onAddTelemetry,
|
|
7781
|
+
onRemoveTelemetry,
|
|
7782
|
+
availableTags = [],
|
|
7217
7783
|
onRemove,
|
|
7218
7784
|
className = "",
|
|
7219
7785
|
style = {}
|
|
@@ -7226,6 +7792,8 @@ function NodeConfigPanel({
|
|
|
7226
7792
|
padding: "20px",
|
|
7227
7793
|
...style
|
|
7228
7794
|
};
|
|
7795
|
+
const appearanceFields = getAppearanceSchema(node.symbolId);
|
|
7796
|
+
const showGenericTelemetry = appearanceFields.length === 0;
|
|
7229
7797
|
return /* @__PURE__ */ jsxs18("div", { className, style: defaultStyle, children: [
|
|
7230
7798
|
/* @__PURE__ */ jsxs18("h2", { style: { margin: "0 0 16px 0", fontSize: "1rem", fontWeight: 600 }, children: [
|
|
7231
7799
|
"Configure: ",
|
|
@@ -7347,7 +7915,136 @@ function NodeConfigPanel({
|
|
|
7347
7915
|
)
|
|
7348
7916
|
] })
|
|
7349
7917
|
] }),
|
|
7350
|
-
/* @__PURE__ */ jsxs18("div", { style: { marginBottom: "20px" }, children: [
|
|
7918
|
+
appearanceFields.length > 0 && /* @__PURE__ */ jsxs18("div", { style: { marginBottom: "20px" }, children: [
|
|
7919
|
+
/* @__PURE__ */ jsx22("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Appearance" }),
|
|
7920
|
+
appearanceFields.map((field) => {
|
|
7921
|
+
const value = readAppearanceValue(node, field);
|
|
7922
|
+
const fieldLabel = field.label ?? field.key;
|
|
7923
|
+
const inputStyle = {
|
|
7924
|
+
width: "100%",
|
|
7925
|
+
padding: "6px 8px",
|
|
7926
|
+
borderRadius: "4px",
|
|
7927
|
+
border: "1px solid #cbd5e1",
|
|
7928
|
+
fontSize: "0.875rem"
|
|
7929
|
+
};
|
|
7930
|
+
let control;
|
|
7931
|
+
if (field.kind === "boolean") {
|
|
7932
|
+
control = /* @__PURE__ */ jsxs18("label", { style: { fontSize: "0.75rem", display: "block" }, children: [
|
|
7933
|
+
/* @__PURE__ */ jsx22(
|
|
7934
|
+
"input",
|
|
7935
|
+
{
|
|
7936
|
+
type: "checkbox",
|
|
7937
|
+
checked: Boolean(value),
|
|
7938
|
+
onChange: (e) => onUpdateNode(writeAppearanceValue(node, field, e.target.checked)),
|
|
7939
|
+
style: { marginRight: "6px" }
|
|
7940
|
+
}
|
|
7941
|
+
),
|
|
7942
|
+
fieldLabel
|
|
7943
|
+
] });
|
|
7944
|
+
} else if (field.kind === "select") {
|
|
7945
|
+
control = /* @__PURE__ */ jsxs18(Fragment8, { children: [
|
|
7946
|
+
/* @__PURE__ */ jsxs18("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
|
|
7947
|
+
fieldLabel,
|
|
7948
|
+
":"
|
|
7949
|
+
] }),
|
|
7950
|
+
/* @__PURE__ */ jsx22(
|
|
7951
|
+
"select",
|
|
7952
|
+
{
|
|
7953
|
+
value: String(value),
|
|
7954
|
+
onChange: (e) => onUpdateNode(writeAppearanceValue(node, field, e.target.value)),
|
|
7955
|
+
style: inputStyle,
|
|
7956
|
+
children: field.options?.map((opt) => /* @__PURE__ */ jsx22("option", { value: opt, children: opt }, opt))
|
|
7957
|
+
}
|
|
7958
|
+
)
|
|
7959
|
+
] });
|
|
7960
|
+
} else if (field.kind === "number") {
|
|
7961
|
+
control = /* @__PURE__ */ jsxs18(Fragment8, { children: [
|
|
7962
|
+
/* @__PURE__ */ jsxs18("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
|
|
7963
|
+
fieldLabel,
|
|
7964
|
+
":"
|
|
7965
|
+
] }),
|
|
7966
|
+
/* @__PURE__ */ jsx22(
|
|
7967
|
+
"input",
|
|
7968
|
+
{
|
|
7969
|
+
type: "number",
|
|
7970
|
+
value: Number(value),
|
|
7971
|
+
onChange: (e) => onUpdateNode(writeAppearanceValue(node, field, parseFloat(e.target.value) || 0)),
|
|
7972
|
+
style: inputStyle
|
|
7973
|
+
}
|
|
7974
|
+
)
|
|
7975
|
+
] });
|
|
7976
|
+
} else if (field.kind === "tag") {
|
|
7977
|
+
const tagValue = String(value);
|
|
7978
|
+
const listId = `tags-${node.id}-${field.key}`;
|
|
7979
|
+
const known = tagValue.length > 0 && availableTags.includes(tagValue);
|
|
7980
|
+
const unknown = tagValue.length > 0 && !known;
|
|
7981
|
+
control = /* @__PURE__ */ jsxs18(Fragment8, { children: [
|
|
7982
|
+
/* @__PURE__ */ jsxs18("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
|
|
7983
|
+
fieldLabel,
|
|
7984
|
+
":"
|
|
7985
|
+
] }),
|
|
7986
|
+
/* @__PURE__ */ jsx22(
|
|
7987
|
+
"input",
|
|
7988
|
+
{
|
|
7989
|
+
type: "text",
|
|
7990
|
+
value: tagValue,
|
|
7991
|
+
list: listId,
|
|
7992
|
+
onChange: (e) => onUpdateNode(writeAppearanceValue(node, field, e.target.value)),
|
|
7993
|
+
placeholder: "type or pick a signal\u2026",
|
|
7994
|
+
style: {
|
|
7995
|
+
...inputStyle,
|
|
7996
|
+
border: `1px solid ${unknown ? "#f59e0b" : known ? "#22c55e" : "#cbd5e1"}`
|
|
7997
|
+
}
|
|
7998
|
+
}
|
|
7999
|
+
),
|
|
8000
|
+
/* @__PURE__ */ jsx22("datalist", { id: listId, children: availableTags.map((t) => /* @__PURE__ */ jsx22("option", { value: t }, t)) }),
|
|
8001
|
+
tagValue.length > 0 && /* @__PURE__ */ jsx22(
|
|
8002
|
+
"div",
|
|
8003
|
+
{
|
|
8004
|
+
style: {
|
|
8005
|
+
fontSize: "0.7rem",
|
|
8006
|
+
marginTop: "3px",
|
|
8007
|
+
color: known ? "#16a34a" : "#b45309"
|
|
8008
|
+
},
|
|
8009
|
+
children: known ? "\u2713 matched signal" : "\u26A0 no matching signal (reads as false until published)"
|
|
8010
|
+
}
|
|
8011
|
+
)
|
|
8012
|
+
] });
|
|
8013
|
+
} else {
|
|
8014
|
+
control = /* @__PURE__ */ jsxs18(Fragment8, { children: [
|
|
8015
|
+
/* @__PURE__ */ jsxs18("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
|
|
8016
|
+
fieldLabel,
|
|
8017
|
+
":"
|
|
8018
|
+
] }),
|
|
8019
|
+
/* @__PURE__ */ jsx22(
|
|
8020
|
+
"input",
|
|
8021
|
+
{
|
|
8022
|
+
type: "text",
|
|
8023
|
+
value: String(value),
|
|
8024
|
+
onChange: (e) => onUpdateNode(writeAppearanceValue(node, field, e.target.value)),
|
|
8025
|
+
style: inputStyle
|
|
8026
|
+
}
|
|
8027
|
+
)
|
|
8028
|
+
] });
|
|
8029
|
+
}
|
|
8030
|
+
return /* @__PURE__ */ jsxs18("div", { style: { marginBottom: "10px" }, children: [
|
|
8031
|
+
control,
|
|
8032
|
+
field.help && /* @__PURE__ */ jsx22(
|
|
8033
|
+
"div",
|
|
8034
|
+
{
|
|
8035
|
+
style: {
|
|
8036
|
+
fontSize: "0.7rem",
|
|
8037
|
+
color: "#64748b",
|
|
8038
|
+
marginTop: "3px",
|
|
8039
|
+
lineHeight: 1.35
|
|
8040
|
+
},
|
|
8041
|
+
children: field.help
|
|
8042
|
+
}
|
|
8043
|
+
)
|
|
8044
|
+
] }, field.key);
|
|
8045
|
+
})
|
|
8046
|
+
] }),
|
|
8047
|
+
showGenericTelemetry && /* @__PURE__ */ jsxs18("div", { style: { marginBottom: "20px" }, children: [
|
|
7351
8048
|
/* @__PURE__ */ jsx22("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Telemetry Data" }),
|
|
7352
8049
|
!binding ? /* @__PURE__ */ jsx22(
|
|
7353
8050
|
"button",
|
|
@@ -7393,6 +8090,27 @@ function NodeConfigPanel({
|
|
|
7393
8090
|
children: "+ Add Telemetry"
|
|
7394
8091
|
}
|
|
7395
8092
|
) : /* @__PURE__ */ jsxs18(Fragment8, { children: [
|
|
8093
|
+
/* @__PURE__ */ jsx22("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Tag (attribute):" }),
|
|
8094
|
+
/* @__PURE__ */ jsx22(
|
|
8095
|
+
"input",
|
|
8096
|
+
{
|
|
8097
|
+
type: "text",
|
|
8098
|
+
value: binding.tag || "",
|
|
8099
|
+
onChange: (e) => onUpdateTelemetry({
|
|
8100
|
+
nodeId: node.id,
|
|
8101
|
+
tag: e.target.value
|
|
8102
|
+
}),
|
|
8103
|
+
placeholder: "e.g. pump.running",
|
|
8104
|
+
style: {
|
|
8105
|
+
width: "100%",
|
|
8106
|
+
padding: "6px 8px",
|
|
8107
|
+
borderRadius: "4px",
|
|
8108
|
+
border: "1px solid #cbd5e1",
|
|
8109
|
+
fontSize: "0.875rem",
|
|
8110
|
+
marginBottom: "8px"
|
|
8111
|
+
}
|
|
8112
|
+
}
|
|
8113
|
+
),
|
|
7396
8114
|
/* @__PURE__ */ jsx22("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Initial Value:" }),
|
|
7397
8115
|
/* @__PURE__ */ jsx22(
|
|
7398
8116
|
"input",
|
|
@@ -7700,10 +8418,28 @@ function NodeConfigPanel({
|
|
|
7700
8418
|
] })
|
|
7701
8419
|
] }),
|
|
7702
8420
|
" "
|
|
7703
|
-
] })
|
|
8421
|
+
] }),
|
|
8422
|
+
onRemoveTelemetry && /* @__PURE__ */ jsx22(
|
|
8423
|
+
"button",
|
|
8424
|
+
{
|
|
8425
|
+
onClick: onRemoveTelemetry,
|
|
8426
|
+
style: {
|
|
8427
|
+
width: "100%",
|
|
8428
|
+
padding: "6px 8px",
|
|
8429
|
+
marginTop: "8px",
|
|
8430
|
+
borderRadius: "4px",
|
|
8431
|
+
border: "1px solid #ef4444",
|
|
8432
|
+
background: "transparent",
|
|
8433
|
+
color: "#ef4444",
|
|
8434
|
+
fontSize: "0.8125rem",
|
|
8435
|
+
cursor: "pointer"
|
|
8436
|
+
},
|
|
8437
|
+
children: "Remove Telemetry"
|
|
8438
|
+
}
|
|
8439
|
+
)
|
|
7704
8440
|
] })
|
|
7705
8441
|
] }),
|
|
7706
|
-
binding && /* @__PURE__ */ jsxs18("div", { style: { marginBottom: "20px" }, children: [
|
|
8442
|
+
showGenericTelemetry && binding && /* @__PURE__ */ jsxs18("div", { style: { marginBottom: "20px" }, children: [
|
|
7707
8443
|
/* @__PURE__ */ jsx22("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Thresholds" }),
|
|
7708
8444
|
["highHigh", "high", "low", "lowLow"].map((key) => {
|
|
7709
8445
|
const label = key === "highHigh" ? "High-High (\u2265)" : key === "high" ? "High (\u2265)" : key === "low" ? "Low (\u2264)" : "Low-Low (\u2264)";
|
|
@@ -7733,7 +8469,7 @@ function NodeConfigPanel({
|
|
|
7733
8469
|
] }, key);
|
|
7734
8470
|
})
|
|
7735
8471
|
] }),
|
|
7736
|
-
binding && /* @__PURE__ */ jsxs18("div", { style: { marginBottom: "20px" }, children: [
|
|
8472
|
+
showGenericTelemetry && binding && /* @__PURE__ */ jsxs18("div", { style: { marginBottom: "20px" }, children: [
|
|
7737
8473
|
/* @__PURE__ */ jsx22("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Status Colors" }),
|
|
7738
8474
|
["normal", "warning", "alarm", "fault", "off"].map((status) => {
|
|
7739
8475
|
const defaultColors = {
|
|
@@ -8592,7 +9328,7 @@ function useDeviceConfigs(initialConfigs) {
|
|
|
8592
9328
|
}
|
|
8593
9329
|
|
|
8594
9330
|
// src/components/DeviceConfigPanel/DeviceConfigPanel.tsx
|
|
8595
|
-
import React15, { useState as useState18, useEffect as
|
|
9331
|
+
import React15, { useState as useState18, useEffect as useEffect14, useMemo, useRef as useRef8 } from "react";
|
|
8596
9332
|
import { Fragment as Fragment9, jsx as jsx23, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
8597
9333
|
function DeviceConfigPanelImpl({
|
|
8598
9334
|
binding,
|
|
@@ -8651,7 +9387,7 @@ function DeviceConfigPanelImpl({
|
|
|
8651
9387
|
setCollapsedSections(collapsed);
|
|
8652
9388
|
setBindingId(binding.nodeId);
|
|
8653
9389
|
}
|
|
8654
|
-
|
|
9390
|
+
useEffect14(() => {
|
|
8655
9391
|
const currentTimestamp = binding?.state.lastSaved || 0;
|
|
8656
9392
|
if (binding?.state.lastSaveResult && currentTimestamp !== lastResultTimestampRef.current) {
|
|
8657
9393
|
lastResultTimestampRef.current = currentTimestamp;
|
|
@@ -8786,7 +9522,49 @@ function DeviceConfigPanelImpl({
|
|
|
8786
9522
|
" (",
|
|
8787
9523
|
param.unit,
|
|
8788
9524
|
")"
|
|
8789
|
-
] })
|
|
9525
|
+
] }),
|
|
9526
|
+
param.forced?.active && /* @__PURE__ */ jsx23(
|
|
9527
|
+
"span",
|
|
9528
|
+
{
|
|
9529
|
+
"aria-label": "Forced",
|
|
9530
|
+
style: {
|
|
9531
|
+
display: "inline-flex",
|
|
9532
|
+
alignItems: "center",
|
|
9533
|
+
justifyContent: "center",
|
|
9534
|
+
width: "16px",
|
|
9535
|
+
height: "16px",
|
|
9536
|
+
marginLeft: "6px",
|
|
9537
|
+
fontSize: "10px",
|
|
9538
|
+
fontWeight: 700,
|
|
9539
|
+
textTransform: "none",
|
|
9540
|
+
letterSpacing: "normal",
|
|
9541
|
+
color: FORCED_MARK_COLOR.text,
|
|
9542
|
+
backgroundColor: FORCED_MARK_COLOR.bg,
|
|
9543
|
+
border: `1px solid ${FORCED_MARK_COLOR.border}`,
|
|
9544
|
+
borderRadius: "50%",
|
|
9545
|
+
verticalAlign: "middle"
|
|
9546
|
+
},
|
|
9547
|
+
children: "F"
|
|
9548
|
+
}
|
|
9549
|
+
)
|
|
9550
|
+
]
|
|
9551
|
+
}
|
|
9552
|
+
),
|
|
9553
|
+
param.forced?.active && param.forced.realValue !== void 0 && /* @__PURE__ */ jsxs19(
|
|
9554
|
+
"div",
|
|
9555
|
+
{
|
|
9556
|
+
style: {
|
|
9557
|
+
fontSize: `${fontSize.description}px`,
|
|
9558
|
+
color: mutedTextColor,
|
|
9559
|
+
marginTop: "-2px",
|
|
9560
|
+
marginBottom: "6px",
|
|
9561
|
+
fontFamily: "Arial, sans-serif"
|
|
9562
|
+
},
|
|
9563
|
+
children: [
|
|
9564
|
+
"REAL",
|
|
9565
|
+
" ",
|
|
9566
|
+
typeof param.forced.realValue === "boolean" ? param.forced.realValue ? "ON" : "OFF" : String(param.forced.realValue),
|
|
9567
|
+
param.unit ? ` ${param.unit}` : ""
|
|
8790
9568
|
]
|
|
8791
9569
|
}
|
|
8792
9570
|
),
|
|
@@ -9300,7 +10078,7 @@ function DeviceConfigPanelImpl({
|
|
|
9300
10078
|
var DeviceConfigPanel = React15.memo(DeviceConfigPanelImpl);
|
|
9301
10079
|
|
|
9302
10080
|
// src/diagram/hooks/useSimulation.ts
|
|
9303
|
-
import { useEffect as
|
|
10081
|
+
import { useEffect as useEffect15 } from "react";
|
|
9304
10082
|
function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
|
|
9305
10083
|
const {
|
|
9306
10084
|
interval = 2e3,
|
|
@@ -9311,7 +10089,7 @@ function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
|
|
|
9311
10089
|
historyLength = 10,
|
|
9312
10090
|
generateValue
|
|
9313
10091
|
} = options;
|
|
9314
|
-
|
|
10092
|
+
useEffect15(() => {
|
|
9315
10093
|
if (!enabled) return;
|
|
9316
10094
|
const intervalId = setInterval(() => {
|
|
9317
10095
|
const updates = [];
|
|
@@ -9361,6 +10139,7 @@ function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
|
|
|
9361
10139
|
}
|
|
9362
10140
|
export {
|
|
9363
10141
|
Button,
|
|
10142
|
+
COLOR_PRESETS,
|
|
9364
10143
|
CardHeader,
|
|
9365
10144
|
CardUnit,
|
|
9366
10145
|
CardValue,
|
|
@@ -9374,6 +10153,7 @@ export {
|
|
|
9374
10153
|
DisplayModeToggle,
|
|
9375
10154
|
EquipmentIndicator,
|
|
9376
10155
|
EquipmentIndicatorWithSparkline,
|
|
10156
|
+
FORCED_MARK_COLOR,
|
|
9377
10157
|
FixedSVGContainer,
|
|
9378
10158
|
FooterPanel,
|
|
9379
10159
|
FullscreenContainer,
|
|
@@ -9389,6 +10169,7 @@ export {
|
|
|
9389
10169
|
PanelTabs,
|
|
9390
10170
|
RightPanel,
|
|
9391
10171
|
RightToggleButton,
|
|
10172
|
+
STATUS_LED_APPEARANCE,
|
|
9392
10173
|
SVGArea,
|
|
9393
10174
|
SVGLockedOverlay,
|
|
9394
10175
|
ScrollableSVGWrapper,
|
|
@@ -9399,6 +10180,8 @@ export {
|
|
|
9399
10180
|
ThemeProvider,
|
|
9400
10181
|
ThemeToggle,
|
|
9401
10182
|
TrendLine,
|
|
10183
|
+
UNKNOWN_MARK_COLOR,
|
|
10184
|
+
UNKNOWN_MARK_COLOR_DARK,
|
|
9402
10185
|
ValueEntry,
|
|
9403
10186
|
ZoomButton,
|
|
9404
10187
|
ZoomControls,
|
|
@@ -9408,6 +10191,8 @@ export {
|
|
|
9408
10191
|
exampleDiagram,
|
|
9409
10192
|
exportDiagram,
|
|
9410
10193
|
generateRoutePoints,
|
|
10194
|
+
getAppearanceDefaults,
|
|
10195
|
+
getAppearanceSchema,
|
|
9411
10196
|
getAvailableSymbols,
|
|
9412
10197
|
getPortWorldPosition,
|
|
9413
10198
|
getSymbolDefinition,
|
|
@@ -9415,9 +10200,12 @@ export {
|
|
|
9415
10200
|
mockSymbolLibrary,
|
|
9416
10201
|
nodeHasPort,
|
|
9417
10202
|
overlayStyles,
|
|
10203
|
+
readAppearanceValue,
|
|
9418
10204
|
registerSymbol,
|
|
9419
10205
|
registerSymbols,
|
|
10206
|
+
resolvePresetColor,
|
|
9420
10207
|
resolveStatusColor,
|
|
10208
|
+
useBooleanIndicators,
|
|
9421
10209
|
useDeviceConfigs,
|
|
9422
10210
|
useDeviceControls,
|
|
9423
10211
|
useDrag,
|
|
@@ -9428,6 +10216,7 @@ export {
|
|
|
9428
10216
|
useTelemetryStatus,
|
|
9429
10217
|
useTheme,
|
|
9430
10218
|
useViewBox,
|
|
9431
|
-
validateDiagram
|
|
10219
|
+
validateDiagram,
|
|
10220
|
+
writeAppearanceValue
|
|
9432
10221
|
};
|
|
9433
10222
|
//# sourceMappingURL=index.js.map
|