@procaaso/alphinity-ui-components 1.0.5 → 1.0.7
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 +1428 -387
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +326 -3
- package/dist/index.d.ts +326 -3
- package/dist/index.js +1361 -326
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -707,14 +707,721 @@ var StatusIndicator = ({
|
|
|
707
707
|
] });
|
|
708
708
|
};
|
|
709
709
|
|
|
710
|
+
// src/components/NodeControlsPanel/NodeControlsPanel.tsx
|
|
711
|
+
import { Fragment, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
712
|
+
var NodeControlsPanel = ({
|
|
713
|
+
config,
|
|
714
|
+
onClose,
|
|
715
|
+
position = "bottom",
|
|
716
|
+
touchOptimized = true,
|
|
717
|
+
className = "",
|
|
718
|
+
style,
|
|
719
|
+
...props
|
|
720
|
+
}) => {
|
|
721
|
+
if (!config) return null;
|
|
722
|
+
const isBottom = position === "bottom";
|
|
723
|
+
const touchClass = touchOptimized ? "touch-optimized" : "";
|
|
724
|
+
const containerStyle = {
|
|
725
|
+
position: "fixed",
|
|
726
|
+
zIndex: 9999,
|
|
727
|
+
background: "white",
|
|
728
|
+
boxShadow: "0 -4px 16px rgba(0, 0, 0, 0.15)",
|
|
729
|
+
borderRadius: isBottom ? "16px 16px 0 0" : "0",
|
|
730
|
+
animation: isBottom ? "slideUp 0.3s ease-out" : "slideInRight 0.3s ease-out",
|
|
731
|
+
display: "flex",
|
|
732
|
+
flexDirection: "column",
|
|
733
|
+
...isBottom ? {
|
|
734
|
+
left: 0,
|
|
735
|
+
right: 0,
|
|
736
|
+
bottom: 0,
|
|
737
|
+
maxHeight: "70vh",
|
|
738
|
+
borderTop: "1px solid #e5e7eb"
|
|
739
|
+
} : {
|
|
740
|
+
right: 0,
|
|
741
|
+
top: 0,
|
|
742
|
+
bottom: 0,
|
|
743
|
+
width: touchOptimized ? "400px" : "320px",
|
|
744
|
+
borderLeft: "1px solid #e5e7eb"
|
|
745
|
+
},
|
|
746
|
+
...style
|
|
747
|
+
};
|
|
748
|
+
const headerStyle = {
|
|
749
|
+
display: "flex",
|
|
750
|
+
alignItems: "center",
|
|
751
|
+
justifyContent: "space-between",
|
|
752
|
+
padding: touchOptimized ? "1.25rem 1.5rem" : "1rem",
|
|
753
|
+
borderBottom: "2px solid #e5e7eb",
|
|
754
|
+
background: "#f9fafb",
|
|
755
|
+
flexShrink: 0
|
|
756
|
+
};
|
|
757
|
+
const titleStyle = {
|
|
758
|
+
margin: 0,
|
|
759
|
+
fontSize: touchOptimized ? "1.5rem" : "1.25rem",
|
|
760
|
+
fontWeight: 600,
|
|
761
|
+
color: "#111827"
|
|
762
|
+
};
|
|
763
|
+
const closeButtonStyle = {
|
|
764
|
+
background: "#ef4444",
|
|
765
|
+
color: "white",
|
|
766
|
+
border: "none",
|
|
767
|
+
borderRadius: "8px",
|
|
768
|
+
width: touchOptimized ? "56px" : "44px",
|
|
769
|
+
height: touchOptimized ? "56px" : "44px",
|
|
770
|
+
fontSize: touchOptimized ? "1.75rem" : "1.5rem",
|
|
771
|
+
fontWeight: "bold",
|
|
772
|
+
cursor: "pointer",
|
|
773
|
+
display: "flex",
|
|
774
|
+
alignItems: "center",
|
|
775
|
+
justifyContent: "center",
|
|
776
|
+
transition: "all 0.2s ease",
|
|
777
|
+
flexShrink: 0
|
|
778
|
+
};
|
|
779
|
+
const contentStyle = {
|
|
780
|
+
padding: touchOptimized ? "1.5rem" : "1rem",
|
|
781
|
+
overflowY: "auto",
|
|
782
|
+
flex: 1
|
|
783
|
+
};
|
|
784
|
+
return /* @__PURE__ */ jsxs6(Fragment, { children: [
|
|
785
|
+
/* @__PURE__ */ jsx7(
|
|
786
|
+
"div",
|
|
787
|
+
{
|
|
788
|
+
style: {
|
|
789
|
+
position: "fixed",
|
|
790
|
+
inset: 0,
|
|
791
|
+
background: "rgba(0, 0, 0, 0.3)",
|
|
792
|
+
zIndex: 9998,
|
|
793
|
+
animation: "fadeIn 0.3s ease-out"
|
|
794
|
+
},
|
|
795
|
+
onClick: onClose
|
|
796
|
+
}
|
|
797
|
+
),
|
|
798
|
+
/* @__PURE__ */ jsxs6(
|
|
799
|
+
"div",
|
|
800
|
+
{
|
|
801
|
+
className: `node-controls-panel ${touchClass} ${className}`.trim(),
|
|
802
|
+
style: containerStyle,
|
|
803
|
+
...props,
|
|
804
|
+
children: [
|
|
805
|
+
/* @__PURE__ */ jsxs6("div", { style: headerStyle, children: [
|
|
806
|
+
/* @__PURE__ */ jsx7("h2", { style: titleStyle, children: config.title }),
|
|
807
|
+
/* @__PURE__ */ jsx7(
|
|
808
|
+
"button",
|
|
809
|
+
{
|
|
810
|
+
style: closeButtonStyle,
|
|
811
|
+
onClick: onClose,
|
|
812
|
+
onMouseEnter: (e) => {
|
|
813
|
+
e.currentTarget.style.background = "#dc2626";
|
|
814
|
+
e.currentTarget.style.transform = "scale(1.05)";
|
|
815
|
+
},
|
|
816
|
+
onMouseLeave: (e) => {
|
|
817
|
+
e.currentTarget.style.background = "#ef4444";
|
|
818
|
+
e.currentTarget.style.transform = "scale(1)";
|
|
819
|
+
},
|
|
820
|
+
"aria-label": "Close",
|
|
821
|
+
children: "\u2715"
|
|
822
|
+
}
|
|
823
|
+
)
|
|
824
|
+
] }),
|
|
825
|
+
/* @__PURE__ */ jsx7("div", { style: contentStyle, children: /* @__PURE__ */ jsx7(
|
|
826
|
+
ControlPanel,
|
|
827
|
+
{
|
|
828
|
+
title: config.nodeId,
|
|
829
|
+
selectedMode: config.currentMode,
|
|
830
|
+
modeOptions: config.modes,
|
|
831
|
+
onModeChange: config.onModeChange,
|
|
832
|
+
setpointValue: config.setpoint,
|
|
833
|
+
onSetpointChange: config.onSetpointChange,
|
|
834
|
+
secondSetpointValue: config.secondSetpoint,
|
|
835
|
+
onSecondSetpointChange: config.onSecondSetpointChange,
|
|
836
|
+
modeConfigs: config.modeConfigs,
|
|
837
|
+
status: config.status,
|
|
838
|
+
setpointReadOnly: config.readOnly,
|
|
839
|
+
showStartStopButtons: !!(config.onStart || config.onStop),
|
|
840
|
+
isRunning: config.isRunning,
|
|
841
|
+
onStart: config.onStart,
|
|
842
|
+
onStop: config.onStop,
|
|
843
|
+
startButtonText: config.startButtonText,
|
|
844
|
+
stopButtonText: config.stopButtonText,
|
|
845
|
+
size: touchOptimized ? "large" : "medium"
|
|
846
|
+
}
|
|
847
|
+
) })
|
|
848
|
+
]
|
|
849
|
+
}
|
|
850
|
+
),
|
|
851
|
+
/* @__PURE__ */ jsx7("style", { children: `
|
|
852
|
+
@keyframes slideUp {
|
|
853
|
+
from {
|
|
854
|
+
transform: translateY(100%);
|
|
855
|
+
opacity: 0;
|
|
856
|
+
}
|
|
857
|
+
to {
|
|
858
|
+
transform: translateY(0);
|
|
859
|
+
opacity: 1;
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
@keyframes slideInRight {
|
|
864
|
+
from {
|
|
865
|
+
transform: translateX(100%);
|
|
866
|
+
opacity: 0;
|
|
867
|
+
}
|
|
868
|
+
to {
|
|
869
|
+
transform: translateX(0);
|
|
870
|
+
opacity: 1;
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
@keyframes fadeIn {
|
|
875
|
+
from {
|
|
876
|
+
opacity: 0;
|
|
877
|
+
}
|
|
878
|
+
to {
|
|
879
|
+
opacity: 1;
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
.node-controls-panel.touch-optimized button {
|
|
884
|
+
min-height: 56px;
|
|
885
|
+
font-size: 1.125rem;
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
.node-controls-panel.touch-optimized input {
|
|
889
|
+
min-height: 56px;
|
|
890
|
+
font-size: 1.125rem;
|
|
891
|
+
}
|
|
892
|
+
` })
|
|
893
|
+
] });
|
|
894
|
+
};
|
|
895
|
+
|
|
896
|
+
// src/components/DeviceControlPanel/DeviceControlPanel.tsx
|
|
897
|
+
import { useState as useState5, useEffect as useEffect2 } from "react";
|
|
898
|
+
import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
899
|
+
function DeviceControlPanel({
|
|
900
|
+
binding,
|
|
901
|
+
onClose,
|
|
902
|
+
position = "bottom",
|
|
903
|
+
touchOptimized = true,
|
|
904
|
+
onModeChange,
|
|
905
|
+
onParameterChange,
|
|
906
|
+
onStart,
|
|
907
|
+
onStop,
|
|
908
|
+
onCustomAction
|
|
909
|
+
}) {
|
|
910
|
+
const [localParameterValues, setLocalParameterValues] = useState5({});
|
|
911
|
+
useEffect2(() => {
|
|
912
|
+
if (binding) {
|
|
913
|
+
const currentParams2 = binding.parameters[binding.state.currentMode] || [];
|
|
914
|
+
const values = {};
|
|
915
|
+
currentParams2.forEach((param) => {
|
|
916
|
+
values[param.id] = param.value;
|
|
917
|
+
});
|
|
918
|
+
setLocalParameterValues(values);
|
|
919
|
+
}
|
|
920
|
+
}, [binding, binding?.state.currentMode]);
|
|
921
|
+
if (!binding) return null;
|
|
922
|
+
const currentMode = binding.state.currentMode;
|
|
923
|
+
const currentParams = binding.parameters[currentMode] || [];
|
|
924
|
+
const touchSize = touchOptimized ? 56 : 40;
|
|
925
|
+
const backgroundColor = binding.theme?.backgroundColor || "#edeeef";
|
|
926
|
+
const surfaceColor = "#f5f6f7";
|
|
927
|
+
const borderColor = "#d2d2d2";
|
|
928
|
+
const textColor = binding.theme?.textColor || "#000000";
|
|
929
|
+
const mutedTextColor = "#666666";
|
|
930
|
+
const selectedColor = "#b4d0fe";
|
|
931
|
+
const statusColors = {
|
|
932
|
+
normal: binding.theme?.statusColors?.normal || "#888888",
|
|
933
|
+
// Gray (no alarm)
|
|
934
|
+
warning: binding.theme?.statusColors?.warning || "#FFD700",
|
|
935
|
+
// Yellow
|
|
936
|
+
alarm: binding.theme?.statusColors?.alarm || "#FF0000",
|
|
937
|
+
// Red
|
|
938
|
+
fault: binding.theme?.statusColors?.fault || "#FF0000",
|
|
939
|
+
// Red
|
|
940
|
+
off: binding.theme?.statusColors?.off || "#666666",
|
|
941
|
+
// Dark gray
|
|
942
|
+
starting: binding.theme?.statusColors?.starting || "#90EE90",
|
|
943
|
+
// Light green
|
|
944
|
+
stopping: binding.theme?.statusColors?.stopping || "#FFD700"
|
|
945
|
+
// Yellow
|
|
946
|
+
};
|
|
947
|
+
const statusColor = statusColors[binding.state.status || "normal"];
|
|
948
|
+
const handleModeChange = (mode) => {
|
|
949
|
+
onModeChange?.(mode);
|
|
950
|
+
};
|
|
951
|
+
const handleParameterCommit = (parameterId, value) => {
|
|
952
|
+
onParameterChange?.(parameterId, value);
|
|
953
|
+
};
|
|
954
|
+
const handleParameterInput = (parameterId, value) => {
|
|
955
|
+
setLocalParameterValues((prev) => ({ ...prev, [parameterId]: value }));
|
|
956
|
+
};
|
|
957
|
+
const panelStyle = {
|
|
958
|
+
position: "fixed",
|
|
959
|
+
...position === "bottom" ? {
|
|
960
|
+
bottom: 0,
|
|
961
|
+
left: 0,
|
|
962
|
+
right: 0,
|
|
963
|
+
animation: "slideUp 0.3s ease-out"
|
|
964
|
+
} : {
|
|
965
|
+
right: 0,
|
|
966
|
+
top: 0,
|
|
967
|
+
bottom: 0,
|
|
968
|
+
width: "400px",
|
|
969
|
+
animation: "slideIn 0.3s ease-out"
|
|
970
|
+
},
|
|
971
|
+
backgroundColor,
|
|
972
|
+
color: textColor,
|
|
973
|
+
borderRadius: position === "bottom" ? "8px 8px 0 0" : "8px 0 0 8px",
|
|
974
|
+
boxShadow: "none",
|
|
975
|
+
border: `2px solid ${borderColor}`,
|
|
976
|
+
padding: "20px",
|
|
977
|
+
zIndex: 9999,
|
|
978
|
+
maxHeight: position === "bottom" ? "70vh" : "100vh",
|
|
979
|
+
overflowY: "auto",
|
|
980
|
+
...binding.display?.style
|
|
981
|
+
};
|
|
982
|
+
const titleText = binding.display?.title || binding.deviceName || binding.tag || binding.nodeId;
|
|
983
|
+
return /* @__PURE__ */ jsx8(Fragment2, { children: /* @__PURE__ */ jsxs7("div", { style: panelStyle, className: binding.display?.className, children: [
|
|
984
|
+
/* @__PURE__ */ jsxs7(
|
|
985
|
+
"div",
|
|
986
|
+
{
|
|
987
|
+
style: {
|
|
988
|
+
display: "flex",
|
|
989
|
+
justifyContent: "space-between",
|
|
990
|
+
alignItems: "center",
|
|
991
|
+
marginBottom: "16px",
|
|
992
|
+
paddingBottom: "12px",
|
|
993
|
+
borderBottom: `2px solid ${borderColor}`
|
|
994
|
+
},
|
|
995
|
+
children: [
|
|
996
|
+
/* @__PURE__ */ jsxs7("div", { children: [
|
|
997
|
+
/* @__PURE__ */ jsx8(
|
|
998
|
+
"h3",
|
|
999
|
+
{
|
|
1000
|
+
style: {
|
|
1001
|
+
margin: 0,
|
|
1002
|
+
fontSize: "14px",
|
|
1003
|
+
fontWeight: 600,
|
|
1004
|
+
fontFamily: "Arial, sans-serif",
|
|
1005
|
+
letterSpacing: "0.5px",
|
|
1006
|
+
textTransform: "uppercase",
|
|
1007
|
+
color: textColor
|
|
1008
|
+
},
|
|
1009
|
+
children: titleText
|
|
1010
|
+
}
|
|
1011
|
+
),
|
|
1012
|
+
binding.deviceType && /* @__PURE__ */ jsx8(
|
|
1013
|
+
"div",
|
|
1014
|
+
{
|
|
1015
|
+
style: {
|
|
1016
|
+
fontSize: "11px",
|
|
1017
|
+
color: mutedTextColor,
|
|
1018
|
+
marginTop: "4px",
|
|
1019
|
+
fontFamily: "Arial, sans-serif"
|
|
1020
|
+
},
|
|
1021
|
+
children: binding.deviceType
|
|
1022
|
+
}
|
|
1023
|
+
)
|
|
1024
|
+
] }),
|
|
1025
|
+
/* @__PURE__ */ jsx8(
|
|
1026
|
+
"button",
|
|
1027
|
+
{
|
|
1028
|
+
onClick: onClose,
|
|
1029
|
+
style: {
|
|
1030
|
+
width: touchSize * 0.7,
|
|
1031
|
+
height: touchSize * 0.7,
|
|
1032
|
+
backgroundColor: surfaceColor,
|
|
1033
|
+
color: textColor,
|
|
1034
|
+
border: `2px solid ${borderColor}`,
|
|
1035
|
+
borderRadius: "2px",
|
|
1036
|
+
fontSize: "18px",
|
|
1037
|
+
cursor: "pointer",
|
|
1038
|
+
fontWeight: "bold",
|
|
1039
|
+
fontFamily: "Arial, sans-serif"
|
|
1040
|
+
},
|
|
1041
|
+
children: "\xD7"
|
|
1042
|
+
}
|
|
1043
|
+
)
|
|
1044
|
+
]
|
|
1045
|
+
}
|
|
1046
|
+
),
|
|
1047
|
+
binding.state.status && /* @__PURE__ */ jsxs7(
|
|
1048
|
+
"div",
|
|
1049
|
+
{
|
|
1050
|
+
style: {
|
|
1051
|
+
display: "flex",
|
|
1052
|
+
alignItems: "center",
|
|
1053
|
+
gap: "12px",
|
|
1054
|
+
padding: "10px 12px",
|
|
1055
|
+
backgroundColor: surfaceColor,
|
|
1056
|
+
border: `1px solid ${borderColor}`,
|
|
1057
|
+
borderRadius: "6px",
|
|
1058
|
+
marginBottom: "16px"
|
|
1059
|
+
},
|
|
1060
|
+
children: [
|
|
1061
|
+
/* @__PURE__ */ jsx8(
|
|
1062
|
+
"div",
|
|
1063
|
+
{
|
|
1064
|
+
style: {
|
|
1065
|
+
width: "10px",
|
|
1066
|
+
height: "10px",
|
|
1067
|
+
borderRadius: "50%",
|
|
1068
|
+
backgroundColor: statusColor,
|
|
1069
|
+
border: "1px solid #333"
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
),
|
|
1073
|
+
/* @__PURE__ */ jsxs7("div", { style: { flex: 1 }, children: [
|
|
1074
|
+
/* @__PURE__ */ jsx8(
|
|
1075
|
+
"div",
|
|
1076
|
+
{
|
|
1077
|
+
style: {
|
|
1078
|
+
fontWeight: 600,
|
|
1079
|
+
textTransform: "uppercase",
|
|
1080
|
+
fontSize: "11px",
|
|
1081
|
+
fontFamily: "Arial, sans-serif",
|
|
1082
|
+
letterSpacing: "0.5px",
|
|
1083
|
+
color: textColor
|
|
1084
|
+
},
|
|
1085
|
+
children: binding.state.status
|
|
1086
|
+
}
|
|
1087
|
+
),
|
|
1088
|
+
binding.state.statusMessage && /* @__PURE__ */ jsx8(
|
|
1089
|
+
"div",
|
|
1090
|
+
{
|
|
1091
|
+
style: {
|
|
1092
|
+
fontSize: "10px",
|
|
1093
|
+
color: mutedTextColor,
|
|
1094
|
+
marginTop: "2px",
|
|
1095
|
+
fontFamily: "Arial, sans-serif"
|
|
1096
|
+
},
|
|
1097
|
+
children: binding.state.statusMessage
|
|
1098
|
+
}
|
|
1099
|
+
)
|
|
1100
|
+
] }),
|
|
1101
|
+
binding.state.isRunning !== void 0 && /* @__PURE__ */ jsx8(
|
|
1102
|
+
"div",
|
|
1103
|
+
{
|
|
1104
|
+
style: {
|
|
1105
|
+
padding: "4px 10px",
|
|
1106
|
+
backgroundColor: binding.state.isRunning ? selectedColor : surfaceColor,
|
|
1107
|
+
border: `1px solid ${borderColor}`,
|
|
1108
|
+
borderRadius: "2px",
|
|
1109
|
+
fontSize: "10px",
|
|
1110
|
+
fontWeight: 600,
|
|
1111
|
+
fontFamily: "Arial, sans-serif",
|
|
1112
|
+
letterSpacing: "0.5px",
|
|
1113
|
+
color: textColor
|
|
1114
|
+
},
|
|
1115
|
+
children: binding.state.isRunning ? "RUNNING" : "STOPPED"
|
|
1116
|
+
}
|
|
1117
|
+
)
|
|
1118
|
+
]
|
|
1119
|
+
}
|
|
1120
|
+
),
|
|
1121
|
+
binding.display?.showModeSelector !== false && binding.modes.length > 0 && /* @__PURE__ */ jsxs7("div", { style: { marginBottom: "16px" }, children: [
|
|
1122
|
+
/* @__PURE__ */ jsx8(
|
|
1123
|
+
"label",
|
|
1124
|
+
{
|
|
1125
|
+
style: {
|
|
1126
|
+
display: "block",
|
|
1127
|
+
marginBottom: "8px",
|
|
1128
|
+
fontSize: "11px",
|
|
1129
|
+
fontWeight: 600,
|
|
1130
|
+
textTransform: "uppercase",
|
|
1131
|
+
letterSpacing: "0.5px",
|
|
1132
|
+
fontFamily: "Arial, sans-serif",
|
|
1133
|
+
color: mutedTextColor
|
|
1134
|
+
},
|
|
1135
|
+
children: "Mode"
|
|
1136
|
+
}
|
|
1137
|
+
),
|
|
1138
|
+
/* @__PURE__ */ jsx8("div", { style: { display: "flex", gap: "6px", flexWrap: "wrap" }, children: binding.modes.map((mode) => {
|
|
1139
|
+
const isSelected = mode.value === currentMode;
|
|
1140
|
+
const isEnabled = mode.enabled !== false;
|
|
1141
|
+
return /* @__PURE__ */ jsx8(
|
|
1142
|
+
"button",
|
|
1143
|
+
{
|
|
1144
|
+
onClick: () => isEnabled && handleModeChange(mode.value),
|
|
1145
|
+
disabled: !isEnabled,
|
|
1146
|
+
style: {
|
|
1147
|
+
flex: 1,
|
|
1148
|
+
minWidth: "80px",
|
|
1149
|
+
height: touchSize,
|
|
1150
|
+
backgroundColor: isSelected ? selectedColor : surfaceColor,
|
|
1151
|
+
color: isSelected ? "#000000" : textColor,
|
|
1152
|
+
border: `1px solid ${isSelected ? "#b4d0fe" : borderColor}`,
|
|
1153
|
+
borderRadius: "6px",
|
|
1154
|
+
fontSize: "11px",
|
|
1155
|
+
fontWeight: 600,
|
|
1156
|
+
fontFamily: "Arial, sans-serif",
|
|
1157
|
+
letterSpacing: "0.5px",
|
|
1158
|
+
textTransform: "uppercase",
|
|
1159
|
+
cursor: isEnabled ? "pointer" : "not-allowed",
|
|
1160
|
+
opacity: isEnabled ? 1 : 0.4
|
|
1161
|
+
},
|
|
1162
|
+
children: mode.label
|
|
1163
|
+
},
|
|
1164
|
+
mode.value
|
|
1165
|
+
);
|
|
1166
|
+
}) })
|
|
1167
|
+
] }),
|
|
1168
|
+
currentParams.length > 0 && /* @__PURE__ */ jsxs7("div", { style: { marginBottom: "16px" }, children: [
|
|
1169
|
+
/* @__PURE__ */ jsx8(
|
|
1170
|
+
"label",
|
|
1171
|
+
{
|
|
1172
|
+
style: {
|
|
1173
|
+
display: "block",
|
|
1174
|
+
marginBottom: "8px",
|
|
1175
|
+
fontSize: "11px",
|
|
1176
|
+
fontWeight: 600,
|
|
1177
|
+
textTransform: "uppercase",
|
|
1178
|
+
letterSpacing: "0.5px",
|
|
1179
|
+
fontFamily: "Arial, sans-serif",
|
|
1180
|
+
color: mutedTextColor
|
|
1181
|
+
},
|
|
1182
|
+
children: "Parameters"
|
|
1183
|
+
}
|
|
1184
|
+
),
|
|
1185
|
+
currentParams.map((param) => /* @__PURE__ */ jsxs7(
|
|
1186
|
+
"div",
|
|
1187
|
+
{
|
|
1188
|
+
style: {
|
|
1189
|
+
marginBottom: "10px",
|
|
1190
|
+
padding: "10px",
|
|
1191
|
+
backgroundColor: surfaceColor,
|
|
1192
|
+
border: `1px solid ${borderColor}`,
|
|
1193
|
+
borderRadius: "6px"
|
|
1194
|
+
},
|
|
1195
|
+
children: [
|
|
1196
|
+
/* @__PURE__ */ jsxs7(
|
|
1197
|
+
"div",
|
|
1198
|
+
{
|
|
1199
|
+
style: { display: "flex", justifyContent: "space-between", marginBottom: "8px" },
|
|
1200
|
+
children: [
|
|
1201
|
+
/* @__PURE__ */ jsx8(
|
|
1202
|
+
"span",
|
|
1203
|
+
{
|
|
1204
|
+
style: {
|
|
1205
|
+
fontSize: "11px",
|
|
1206
|
+
fontWeight: 600,
|
|
1207
|
+
textTransform: "uppercase",
|
|
1208
|
+
letterSpacing: "0.5px",
|
|
1209
|
+
fontFamily: "Arial, sans-serif",
|
|
1210
|
+
color: mutedTextColor
|
|
1211
|
+
},
|
|
1212
|
+
children: param.label
|
|
1213
|
+
}
|
|
1214
|
+
),
|
|
1215
|
+
/* @__PURE__ */ jsxs7(
|
|
1216
|
+
"span",
|
|
1217
|
+
{
|
|
1218
|
+
style: {
|
|
1219
|
+
fontSize: "13px",
|
|
1220
|
+
fontWeight: 700,
|
|
1221
|
+
fontFamily: "Arial, sans-serif",
|
|
1222
|
+
color: textColor
|
|
1223
|
+
},
|
|
1224
|
+
children: [
|
|
1225
|
+
localParameterValues[param.id] ?? param.value,
|
|
1226
|
+
" ",
|
|
1227
|
+
param.unit && /* @__PURE__ */ jsx8("span", { style: { color: mutedTextColor, fontSize: "10px", fontWeight: 600 }, children: param.unit })
|
|
1228
|
+
]
|
|
1229
|
+
}
|
|
1230
|
+
)
|
|
1231
|
+
]
|
|
1232
|
+
}
|
|
1233
|
+
),
|
|
1234
|
+
param.type === "boolean" ? /* @__PURE__ */ jsx8(
|
|
1235
|
+
"button",
|
|
1236
|
+
{
|
|
1237
|
+
onClick: () => {
|
|
1238
|
+
const newValue = !localParameterValues[param.id];
|
|
1239
|
+
handleParameterInput(param.id, newValue);
|
|
1240
|
+
handleParameterCommit(param.id, newValue);
|
|
1241
|
+
},
|
|
1242
|
+
disabled: param.readOnly,
|
|
1243
|
+
style: {
|
|
1244
|
+
width: "100%",
|
|
1245
|
+
height: touchSize,
|
|
1246
|
+
backgroundColor: localParameterValues[param.id] ? "#3f3f46" : surfaceColor,
|
|
1247
|
+
color: localParameterValues[param.id] ? textColor : mutedTextColor,
|
|
1248
|
+
border: `1px solid ${localParameterValues[param.id] ? "#52525b" : borderColor}`,
|
|
1249
|
+
borderRadius: "4px",
|
|
1250
|
+
fontSize: "12px",
|
|
1251
|
+
fontWeight: 600,
|
|
1252
|
+
fontFamily: "monospace",
|
|
1253
|
+
letterSpacing: "0.5px",
|
|
1254
|
+
cursor: param.readOnly ? "not-allowed" : "pointer",
|
|
1255
|
+
transition: "all 0.15s"
|
|
1256
|
+
},
|
|
1257
|
+
children: localParameterValues[param.id] ? "ON" : "OFF"
|
|
1258
|
+
}
|
|
1259
|
+
) : param.type === "select" ? /* @__PURE__ */ jsx8(
|
|
1260
|
+
"select",
|
|
1261
|
+
{
|
|
1262
|
+
value: localParameterValues[param.id] || param.value,
|
|
1263
|
+
onChange: (e) => {
|
|
1264
|
+
handleParameterInput(param.id, e.target.value);
|
|
1265
|
+
handleParameterCommit(param.id, e.target.value);
|
|
1266
|
+
},
|
|
1267
|
+
disabled: param.readOnly,
|
|
1268
|
+
style: {
|
|
1269
|
+
width: "100%",
|
|
1270
|
+
height: touchSize,
|
|
1271
|
+
backgroundColor: surfaceColor,
|
|
1272
|
+
color: textColor,
|
|
1273
|
+
border: `1px solid ${borderColor}`,
|
|
1274
|
+
borderRadius: "4px",
|
|
1275
|
+
padding: "0 12px",
|
|
1276
|
+
fontSize: "12px",
|
|
1277
|
+
fontFamily: "monospace",
|
|
1278
|
+
cursor: "pointer"
|
|
1279
|
+
},
|
|
1280
|
+
children: param.options?.map((opt) => /* @__PURE__ */ jsx8("option", { value: opt.value, children: opt.label }, opt.value))
|
|
1281
|
+
}
|
|
1282
|
+
) : /* @__PURE__ */ jsx8(
|
|
1283
|
+
"input",
|
|
1284
|
+
{
|
|
1285
|
+
type: param.type === "number" ? "number" : "text",
|
|
1286
|
+
value: localParameterValues[param.id] ?? param.value,
|
|
1287
|
+
onChange: (e) => handleParameterInput(
|
|
1288
|
+
param.id,
|
|
1289
|
+
param.type === "number" ? +e.target.value : e.target.value
|
|
1290
|
+
),
|
|
1291
|
+
onBlur: () => handleParameterCommit(param.id, localParameterValues[param.id]),
|
|
1292
|
+
disabled: param.readOnly,
|
|
1293
|
+
min: param.min,
|
|
1294
|
+
max: param.max,
|
|
1295
|
+
step: param.step,
|
|
1296
|
+
style: {
|
|
1297
|
+
width: "100%",
|
|
1298
|
+
height: touchSize,
|
|
1299
|
+
backgroundColor: "#ffffff",
|
|
1300
|
+
color: textColor,
|
|
1301
|
+
border: `1px solid ${borderColor}`,
|
|
1302
|
+
borderRadius: "6px",
|
|
1303
|
+
padding: "0 12px",
|
|
1304
|
+
fontSize: "14px",
|
|
1305
|
+
fontFamily: "Arial, sans-serif",
|
|
1306
|
+
fontWeight: 600
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
)
|
|
1310
|
+
]
|
|
1311
|
+
},
|
|
1312
|
+
param.id
|
|
1313
|
+
))
|
|
1314
|
+
] }),
|
|
1315
|
+
binding.display?.showStartStop !== false && (binding.capabilities?.canStart || binding.capabilities?.canStop) && /* @__PURE__ */ jsxs7("div", { style: { display: "flex", gap: "8px", marginBottom: "16px" }, children: [
|
|
1316
|
+
binding.capabilities?.canStart && /* @__PURE__ */ jsx8(
|
|
1317
|
+
"button",
|
|
1318
|
+
{
|
|
1319
|
+
onClick: onStart,
|
|
1320
|
+
disabled: binding.state.isRunning,
|
|
1321
|
+
style: {
|
|
1322
|
+
flex: 1,
|
|
1323
|
+
height: touchSize,
|
|
1324
|
+
backgroundColor: binding.state.isRunning ? "#a3a3a3" : "#10b981",
|
|
1325
|
+
color: "#ffffff",
|
|
1326
|
+
border: "none",
|
|
1327
|
+
borderRadius: "6px",
|
|
1328
|
+
fontSize: "12px",
|
|
1329
|
+
fontWeight: 700,
|
|
1330
|
+
fontFamily: "Arial, sans-serif",
|
|
1331
|
+
letterSpacing: "0.5px",
|
|
1332
|
+
cursor: binding.state.isRunning ? "not-allowed" : "pointer",
|
|
1333
|
+
opacity: binding.state.isRunning ? 0.5 : 1
|
|
1334
|
+
},
|
|
1335
|
+
children: "START"
|
|
1336
|
+
}
|
|
1337
|
+
),
|
|
1338
|
+
binding.capabilities?.canStop && /* @__PURE__ */ jsx8(
|
|
1339
|
+
"button",
|
|
1340
|
+
{
|
|
1341
|
+
onClick: onStop,
|
|
1342
|
+
disabled: !binding.state.isRunning,
|
|
1343
|
+
style: {
|
|
1344
|
+
flex: 1,
|
|
1345
|
+
height: touchSize,
|
|
1346
|
+
backgroundColor: !binding.state.isRunning ? "#a3a3a3" : "#ef4444",
|
|
1347
|
+
color: "#ffffff",
|
|
1348
|
+
border: "none",
|
|
1349
|
+
borderRadius: "6px",
|
|
1350
|
+
fontSize: "12px",
|
|
1351
|
+
fontWeight: 700,
|
|
1352
|
+
fontFamily: "Arial, sans-serif",
|
|
1353
|
+
letterSpacing: "0.5px",
|
|
1354
|
+
cursor: !binding.state.isRunning ? "not-allowed" : "pointer",
|
|
1355
|
+
opacity: !binding.state.isRunning ? 0.5 : 1
|
|
1356
|
+
},
|
|
1357
|
+
children: "STOP"
|
|
1358
|
+
}
|
|
1359
|
+
)
|
|
1360
|
+
] }),
|
|
1361
|
+
binding.capabilities?.customActions && binding.capabilities.customActions.length > 0 && /* @__PURE__ */ jsx8("div", { style: { display: "flex", flexWrap: "wrap", gap: "8px" }, children: binding.capabilities.customActions.map((action) => /* @__PURE__ */ jsxs7(
|
|
1362
|
+
"button",
|
|
1363
|
+
{
|
|
1364
|
+
onClick: () => onCustomAction?.(action.id),
|
|
1365
|
+
style: {
|
|
1366
|
+
flex: 1,
|
|
1367
|
+
minWidth: "120px",
|
|
1368
|
+
height: touchSize,
|
|
1369
|
+
backgroundColor: surfaceColor,
|
|
1370
|
+
color: textColor,
|
|
1371
|
+
border: `1px solid ${borderColor}`,
|
|
1372
|
+
borderRadius: "6px",
|
|
1373
|
+
fontSize: "11px",
|
|
1374
|
+
fontWeight: 600,
|
|
1375
|
+
fontFamily: "monospace",
|
|
1376
|
+
letterSpacing: "0.5px",
|
|
1377
|
+
textTransform: "uppercase",
|
|
1378
|
+
cursor: "pointer",
|
|
1379
|
+
transition: "all 0.15s"
|
|
1380
|
+
},
|
|
1381
|
+
children: [
|
|
1382
|
+
action.icon && /* @__PURE__ */ jsx8("span", { style: { marginRight: "6px" }, children: action.icon }),
|
|
1383
|
+
action.label
|
|
1384
|
+
]
|
|
1385
|
+
},
|
|
1386
|
+
action.id
|
|
1387
|
+
)) }),
|
|
1388
|
+
binding.state.lastCommandResult && /* @__PURE__ */ jsx8(
|
|
1389
|
+
"div",
|
|
1390
|
+
{
|
|
1391
|
+
style: {
|
|
1392
|
+
marginTop: "16px",
|
|
1393
|
+
padding: "10px 12px",
|
|
1394
|
+
backgroundColor: surfaceColor,
|
|
1395
|
+
border: `1px solid ${binding.state.lastCommandResult.success ? "#52525b" : borderColor}`,
|
|
1396
|
+
borderRadius: "4px",
|
|
1397
|
+
fontSize: "11px",
|
|
1398
|
+
fontFamily: "monospace",
|
|
1399
|
+
color: binding.state.lastCommandResult.success ? textColor : mutedTextColor
|
|
1400
|
+
},
|
|
1401
|
+
children: binding.state.lastCommandResult.message
|
|
1402
|
+
}
|
|
1403
|
+
),
|
|
1404
|
+
/* @__PURE__ */ jsx8("style", { children: `
|
|
1405
|
+
@keyframes slideUp {
|
|
1406
|
+
from { transform: translateY(100%); }
|
|
1407
|
+
to { transform: translateY(0); }
|
|
1408
|
+
}
|
|
1409
|
+
@keyframes slideIn {
|
|
1410
|
+
from { transform: translateX(100%); }
|
|
1411
|
+
to { transform: translateX(0); }
|
|
1412
|
+
}
|
|
1413
|
+
` })
|
|
1414
|
+
] }) });
|
|
1415
|
+
}
|
|
1416
|
+
|
|
710
1417
|
// src/components/layout/FullscreenWorkspace/FullscreenWorkspace.tsx
|
|
711
|
-
import
|
|
1418
|
+
import React6 from "react";
|
|
712
1419
|
import { Tab } from "@mui/material";
|
|
713
1420
|
|
|
714
1421
|
// src/components/layout/FullscreenWorkspace/FullscreenWorkspace.styles.tsx
|
|
715
1422
|
import { Box, IconButton, Tabs } from "@mui/material";
|
|
716
1423
|
import styled from "@emotion/styled";
|
|
717
|
-
import { jsx as
|
|
1424
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
718
1425
|
var FullscreenContainer = styled(Box)(
|
|
719
1426
|
({ leftCollapsed, rightCollapsed }) => {
|
|
720
1427
|
const getGridTemplateAreas = () => {
|
|
@@ -839,7 +1546,7 @@ var DisplayModeToggle = styled(IconButton)(({ mode }) => ({
|
|
|
839
1546
|
transform: "translateX(-50%) scale(1.05)"
|
|
840
1547
|
}
|
|
841
1548
|
}));
|
|
842
|
-
var ChevronLeft = () => /* @__PURE__ */
|
|
1549
|
+
var ChevronLeft = () => /* @__PURE__ */ jsx9(
|
|
843
1550
|
"div",
|
|
844
1551
|
{
|
|
845
1552
|
style: {
|
|
@@ -851,7 +1558,7 @@ var ChevronLeft = () => /* @__PURE__ */ jsx7(
|
|
|
851
1558
|
}
|
|
852
1559
|
}
|
|
853
1560
|
);
|
|
854
|
-
var ChevronRight = () => /* @__PURE__ */
|
|
1561
|
+
var ChevronRight = () => /* @__PURE__ */ jsx9(
|
|
855
1562
|
"div",
|
|
856
1563
|
{
|
|
857
1564
|
style: {
|
|
@@ -962,10 +1669,10 @@ var ScrollableSVGWrapper = styled("div")({
|
|
|
962
1669
|
});
|
|
963
1670
|
|
|
964
1671
|
// src/components/layout/FullscreenWorkspace/FullscreenWorkspace.overlays.tsx
|
|
965
|
-
import { useEffect as
|
|
1672
|
+
import { useEffect as useEffect3, useState as useState6 } from "react";
|
|
966
1673
|
import { Box as Box2 } from "@mui/material";
|
|
967
1674
|
import styled2 from "@emotion/styled";
|
|
968
|
-
import { jsx as
|
|
1675
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
969
1676
|
var baseOverlayStyles = {
|
|
970
1677
|
tank: {
|
|
971
1678
|
background: "linear-gradient(135deg, rgba(69, 90, 120, 0.95) 0%, rgba(52, 73, 94, 0.95) 100%)",
|
|
@@ -1027,8 +1734,8 @@ var SVGLockedOverlay = ({
|
|
|
1027
1734
|
onClick,
|
|
1028
1735
|
containerSelector = ".tff-svg-container"
|
|
1029
1736
|
}) => {
|
|
1030
|
-
const [svgOffset, setSvgOffset] =
|
|
1031
|
-
|
|
1737
|
+
const [svgOffset, setSvgOffset] = useState6({ x: 0, y: 0 });
|
|
1738
|
+
useEffect3(() => {
|
|
1032
1739
|
const updateSvgOffset = () => {
|
|
1033
1740
|
const containerElement = document.querySelector(containerSelector);
|
|
1034
1741
|
const svgElement = containerElement?.querySelector("svg");
|
|
@@ -1048,7 +1755,7 @@ var SVGLockedOverlay = ({
|
|
|
1048
1755
|
const pixelX = svgX + svgOffset.x;
|
|
1049
1756
|
const pixelY = svgY + svgOffset.y;
|
|
1050
1757
|
const appliedStyle = theme ? { ...overlayStyles[theme], ...style } : style;
|
|
1051
|
-
return /* @__PURE__ */
|
|
1758
|
+
return /* @__PURE__ */ jsx10(
|
|
1052
1759
|
Box2,
|
|
1053
1760
|
{
|
|
1054
1761
|
className: `svg-locked-overlay ${className}`.trim(),
|
|
@@ -1112,7 +1819,7 @@ var CardUnit = styled2("div")({
|
|
|
1112
1819
|
});
|
|
1113
1820
|
|
|
1114
1821
|
// src/components/layout/FullscreenWorkspace/FullscreenWorkspace.visuals.tsx
|
|
1115
|
-
import { Fragment, jsx as
|
|
1822
|
+
import { Fragment as Fragment3, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1116
1823
|
var TrendLine = ({
|
|
1117
1824
|
values,
|
|
1118
1825
|
width = 60,
|
|
@@ -1122,7 +1829,7 @@ var TrendLine = ({
|
|
|
1122
1829
|
backgroundColor = "rgba(255, 255, 255, 0.1)"
|
|
1123
1830
|
}) => {
|
|
1124
1831
|
if (!values || values.length < 2) {
|
|
1125
|
-
return /* @__PURE__ */
|
|
1832
|
+
return /* @__PURE__ */ jsx11(
|
|
1126
1833
|
"div",
|
|
1127
1834
|
{
|
|
1128
1835
|
style: {
|
|
@@ -1134,7 +1841,7 @@ var TrendLine = ({
|
|
|
1134
1841
|
alignItems: "center",
|
|
1135
1842
|
justifyContent: "center"
|
|
1136
1843
|
},
|
|
1137
|
-
children: /* @__PURE__ */
|
|
1844
|
+
children: /* @__PURE__ */ jsx11("span", { style: { fontSize: "8px", color: "#ccc" }, children: "No data" })
|
|
1138
1845
|
}
|
|
1139
1846
|
);
|
|
1140
1847
|
}
|
|
@@ -1146,7 +1853,7 @@ var TrendLine = ({
|
|
|
1146
1853
|
const x = 4 + i / (values.length - 1) * (width - 8);
|
|
1147
1854
|
return i === 0 ? `M ${x} ${y}` : `L ${x} ${y}`;
|
|
1148
1855
|
}).join(" ");
|
|
1149
|
-
return /* @__PURE__ */
|
|
1856
|
+
return /* @__PURE__ */ jsx11(
|
|
1150
1857
|
"div",
|
|
1151
1858
|
{
|
|
1152
1859
|
style: {
|
|
@@ -1157,8 +1864,8 @@ var TrendLine = ({
|
|
|
1157
1864
|
position: "relative",
|
|
1158
1865
|
overflow: "hidden"
|
|
1159
1866
|
},
|
|
1160
|
-
children: /* @__PURE__ */
|
|
1161
|
-
/* @__PURE__ */
|
|
1867
|
+
children: /* @__PURE__ */ jsxs8("svg", { width, height, style: { position: "absolute", top: 0, left: 0 }, children: [
|
|
1868
|
+
/* @__PURE__ */ jsx11(
|
|
1162
1869
|
"path",
|
|
1163
1870
|
{
|
|
1164
1871
|
d: pathData,
|
|
@@ -1169,7 +1876,7 @@ var TrendLine = ({
|
|
|
1169
1876
|
strokeLinejoin: "round"
|
|
1170
1877
|
}
|
|
1171
1878
|
),
|
|
1172
|
-
/* @__PURE__ */
|
|
1879
|
+
/* @__PURE__ */ jsx11(
|
|
1173
1880
|
"circle",
|
|
1174
1881
|
{
|
|
1175
1882
|
cx: 4 + (width - 8),
|
|
@@ -1207,7 +1914,7 @@ var CircularGauge = ({
|
|
|
1207
1914
|
const borderColor = isHex ? hexToRgba(color, 0.9) : color;
|
|
1208
1915
|
const backgroundColor = isHex ? hexToRgba(color, 0.15) : color;
|
|
1209
1916
|
const borderStrokeColor = isHex ? hexToRgba(color, 0.4) : color;
|
|
1210
|
-
return /* @__PURE__ */
|
|
1917
|
+
return /* @__PURE__ */ jsxs8(
|
|
1211
1918
|
"div",
|
|
1212
1919
|
{
|
|
1213
1920
|
style: {
|
|
@@ -1216,7 +1923,7 @@ var CircularGauge = ({
|
|
|
1216
1923
|
alignItems: "center"
|
|
1217
1924
|
},
|
|
1218
1925
|
children: [
|
|
1219
|
-
/* @__PURE__ */
|
|
1926
|
+
/* @__PURE__ */ jsxs8(
|
|
1220
1927
|
"div",
|
|
1221
1928
|
{
|
|
1222
1929
|
style: {
|
|
@@ -1228,8 +1935,8 @@ var CircularGauge = ({
|
|
|
1228
1935
|
border: `1px solid ${borderStrokeColor}`
|
|
1229
1936
|
},
|
|
1230
1937
|
children: [
|
|
1231
|
-
/* @__PURE__ */
|
|
1232
|
-
/* @__PURE__ */
|
|
1938
|
+
/* @__PURE__ */ jsxs8("svg", { width: size, height: size, style: { transform: "rotate(-90deg)" }, children: [
|
|
1939
|
+
/* @__PURE__ */ jsx11(
|
|
1233
1940
|
"circle",
|
|
1234
1941
|
{
|
|
1235
1942
|
cx: size / 2,
|
|
@@ -1240,7 +1947,7 @@ var CircularGauge = ({
|
|
|
1240
1947
|
strokeWidth: 1
|
|
1241
1948
|
}
|
|
1242
1949
|
),
|
|
1243
|
-
/* @__PURE__ */
|
|
1950
|
+
/* @__PURE__ */ jsx11(
|
|
1244
1951
|
"circle",
|
|
1245
1952
|
{
|
|
1246
1953
|
cx: size / 2,
|
|
@@ -1251,7 +1958,7 @@ var CircularGauge = ({
|
|
|
1251
1958
|
fill: "transparent"
|
|
1252
1959
|
}
|
|
1253
1960
|
),
|
|
1254
|
-
/* @__PURE__ */
|
|
1961
|
+
/* @__PURE__ */ jsx11(
|
|
1255
1962
|
"circle",
|
|
1256
1963
|
{
|
|
1257
1964
|
cx: size / 2,
|
|
@@ -1267,7 +1974,7 @@ var CircularGauge = ({
|
|
|
1267
1974
|
}
|
|
1268
1975
|
)
|
|
1269
1976
|
] }),
|
|
1270
|
-
/* @__PURE__ */
|
|
1977
|
+
/* @__PURE__ */ jsxs8(
|
|
1271
1978
|
"div",
|
|
1272
1979
|
{
|
|
1273
1980
|
style: {
|
|
@@ -1283,14 +1990,14 @@ var CircularGauge = ({
|
|
|
1283
1990
|
},
|
|
1284
1991
|
children: [
|
|
1285
1992
|
value.toFixed(1),
|
|
1286
|
-
/* @__PURE__ */
|
|
1993
|
+
/* @__PURE__ */ jsx11("div", { style: { fontSize: "8px", opacity: 0.9, color: "white" }, children: unit })
|
|
1287
1994
|
]
|
|
1288
1995
|
}
|
|
1289
1996
|
)
|
|
1290
1997
|
]
|
|
1291
1998
|
}
|
|
1292
1999
|
),
|
|
1293
|
-
/* @__PURE__ */
|
|
2000
|
+
/* @__PURE__ */ jsx11(
|
|
1294
2001
|
"div",
|
|
1295
2002
|
{
|
|
1296
2003
|
style: {
|
|
@@ -1321,7 +2028,7 @@ var Sparkline = ({ data, width, height, color }) => {
|
|
|
1321
2028
|
const y = height - 8 - (value - min) / range * (height - 8);
|
|
1322
2029
|
return `${x + 4},${y + 4}`;
|
|
1323
2030
|
}).join(" ");
|
|
1324
|
-
return /* @__PURE__ */
|
|
2031
|
+
return /* @__PURE__ */ jsx11(
|
|
1325
2032
|
"div",
|
|
1326
2033
|
{
|
|
1327
2034
|
style: {
|
|
@@ -1335,7 +2042,7 @@ var Sparkline = ({ data, width, height, color }) => {
|
|
|
1335
2042
|
justifyContent: "center",
|
|
1336
2043
|
boxShadow: "0 1px 3px rgba(0, 0, 0, 0.2)"
|
|
1337
2044
|
},
|
|
1338
|
-
children: /* @__PURE__ */
|
|
2045
|
+
children: /* @__PURE__ */ jsx11("svg", { width, height, children: /* @__PURE__ */ jsx11("polyline", { points, fill: "none", stroke: color, strokeWidth: "1.5", opacity: "0.9" }) })
|
|
1339
2046
|
}
|
|
1340
2047
|
);
|
|
1341
2048
|
};
|
|
@@ -1349,8 +2056,8 @@ var EquipmentIndicatorWithSparkline = ({
|
|
|
1349
2056
|
sparklineOffset = { x: 40, y: 0 }
|
|
1350
2057
|
}) => {
|
|
1351
2058
|
const hasSparkline = sparklineData && sparklineData.length > 1 && Math.max(...sparklineData) !== Math.min(...sparklineData);
|
|
1352
|
-
return /* @__PURE__ */
|
|
1353
|
-
/* @__PURE__ */
|
|
2059
|
+
return /* @__PURE__ */ jsxs8(Fragment3, { children: [
|
|
2060
|
+
/* @__PURE__ */ jsx11(SVGLockedOverlay, { svgX, svgY, style: { transform: "translate(-50%, -50%)" }, children: /* @__PURE__ */ jsx11(
|
|
1354
2061
|
"div",
|
|
1355
2062
|
{
|
|
1356
2063
|
style: {
|
|
@@ -1371,7 +2078,7 @@ var EquipmentIndicatorWithSparkline = ({
|
|
|
1371
2078
|
children: label
|
|
1372
2079
|
}
|
|
1373
2080
|
) }),
|
|
1374
|
-
hasSparkline && /* @__PURE__ */
|
|
2081
|
+
hasSparkline && /* @__PURE__ */ jsx11(SVGLockedOverlay, { svgX: svgX + sparklineOffset.x, svgY: svgY + sparklineOffset.y, children: /* @__PURE__ */ jsx11(Sparkline, { data: sparklineData, width: 60, height: 20, color }) })
|
|
1375
2082
|
] });
|
|
1376
2083
|
};
|
|
1377
2084
|
var EquipmentIndicator = ({
|
|
@@ -1384,7 +2091,7 @@ var EquipmentIndicator = ({
|
|
|
1384
2091
|
className
|
|
1385
2092
|
}) => {
|
|
1386
2093
|
const overlayStyle = style !== void 0 ? { transform: "translate(-50%, -50%)", ...style } : { transform: "translate(-50%, -50%)" };
|
|
1387
|
-
return /* @__PURE__ */
|
|
2094
|
+
return /* @__PURE__ */ jsx11(SVGLockedOverlay, { svgX, svgY, style: overlayStyle, className, children: /* @__PURE__ */ jsx11(
|
|
1388
2095
|
"div",
|
|
1389
2096
|
{
|
|
1390
2097
|
style: {
|
|
@@ -1408,7 +2115,7 @@ var EquipmentIndicator = ({
|
|
|
1408
2115
|
};
|
|
1409
2116
|
|
|
1410
2117
|
// src/components/layout/FullscreenWorkspace/FullscreenWorkspace.tsx
|
|
1411
|
-
import { Fragment as
|
|
2118
|
+
import { Fragment as Fragment4, jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1412
2119
|
function FullscreenWorkspace({
|
|
1413
2120
|
svgContent,
|
|
1414
2121
|
overlays,
|
|
@@ -1436,10 +2143,10 @@ function FullscreenWorkspace({
|
|
|
1436
2143
|
className = "",
|
|
1437
2144
|
...rest
|
|
1438
2145
|
}) {
|
|
1439
|
-
const [leftCollapsedState, setLeftCollapsedState] =
|
|
1440
|
-
const [rightCollapsedState, setRightCollapsedState] =
|
|
1441
|
-
const [internalDisplayMode, setInternalDisplayMode] =
|
|
1442
|
-
const [internalTab, setInternalTab] =
|
|
2146
|
+
const [leftCollapsedState, setLeftCollapsedState] = React6.useState(defaultLeftCollapsed);
|
|
2147
|
+
const [rightCollapsedState, setRightCollapsedState] = React6.useState(defaultRightCollapsed);
|
|
2148
|
+
const [internalDisplayMode, setInternalDisplayMode] = React6.useState(displayMode ?? defaultDisplayMode);
|
|
2149
|
+
const [internalTab, setInternalTab] = React6.useState(
|
|
1443
2150
|
tabs && tabs.length > 0 ? tabs[0].value : ""
|
|
1444
2151
|
);
|
|
1445
2152
|
const leftCollapsed = leftCollapsedProp ?? leftCollapsedState;
|
|
@@ -1447,10 +2154,10 @@ function FullscreenWorkspace({
|
|
|
1447
2154
|
const isDisplayModeControlled = displayMode !== void 0;
|
|
1448
2155
|
const currentDisplayMode = isDisplayModeControlled ? displayMode : internalDisplayMode;
|
|
1449
2156
|
const isTabControlled = activeTab !== void 0 && activeTab !== null;
|
|
1450
|
-
const resolvedTabs =
|
|
2157
|
+
const resolvedTabs = React6.useMemo(() => tabs ?? [], [tabs]);
|
|
1451
2158
|
const defaultTabValue = resolvedTabs.length > 0 ? resolvedTabs[0].value : "";
|
|
1452
2159
|
const currentTab = isTabControlled ? activeTab : internalTab || defaultTabValue;
|
|
1453
|
-
|
|
2160
|
+
React6.useEffect(() => {
|
|
1454
2161
|
if (resolvedTabs.length > 0) {
|
|
1455
2162
|
const values = resolvedTabs.map((tab) => tab.value);
|
|
1456
2163
|
if (!values.includes(currentTab)) {
|
|
@@ -1459,7 +2166,7 @@ function FullscreenWorkspace({
|
|
|
1459
2166
|
}
|
|
1460
2167
|
}
|
|
1461
2168
|
}, [resolvedTabs, activeTab, currentTab, defaultTabValue]);
|
|
1462
|
-
|
|
2169
|
+
React6.useEffect(() => {
|
|
1463
2170
|
if (displayMode !== void 0) {
|
|
1464
2171
|
setInternalDisplayMode(displayMode);
|
|
1465
2172
|
}
|
|
@@ -1494,7 +2201,7 @@ function FullscreenWorkspace({
|
|
|
1494
2201
|
const currentTabContent = resolvedTabs.find((tab) => tab.value === currentTab)?.content ?? null;
|
|
1495
2202
|
const showLeftToggle = Boolean(leftPanel);
|
|
1496
2203
|
const showRightToggle = Boolean(rightPanel);
|
|
1497
|
-
return /* @__PURE__ */
|
|
2204
|
+
return /* @__PURE__ */ jsxs9(
|
|
1498
2205
|
FullscreenContainer,
|
|
1499
2206
|
{
|
|
1500
2207
|
leftCollapsed,
|
|
@@ -1502,25 +2209,25 @@ function FullscreenWorkspace({
|
|
|
1502
2209
|
className: `tff-svg-container ${className}`.trim(),
|
|
1503
2210
|
...rest,
|
|
1504
2211
|
children: [
|
|
1505
|
-
showLeftToggle && /* @__PURE__ */
|
|
2212
|
+
showLeftToggle && /* @__PURE__ */ jsx12(
|
|
1506
2213
|
LeftToggleButton,
|
|
1507
2214
|
{
|
|
1508
2215
|
collapsed: leftCollapsed,
|
|
1509
2216
|
onClick: handleLeftToggle,
|
|
1510
2217
|
"aria-label": leftCollapsed ? "Expand left panel" : "Collapse left panel",
|
|
1511
|
-
children: leftCollapsed ? /* @__PURE__ */
|
|
2218
|
+
children: leftCollapsed ? /* @__PURE__ */ jsx12(ChevronRight, {}) : /* @__PURE__ */ jsx12(ChevronLeft, {})
|
|
1512
2219
|
}
|
|
1513
2220
|
),
|
|
1514
|
-
showRightToggle && /* @__PURE__ */
|
|
2221
|
+
showRightToggle && /* @__PURE__ */ jsx12(
|
|
1515
2222
|
RightToggleButton,
|
|
1516
2223
|
{
|
|
1517
2224
|
collapsed: rightCollapsed,
|
|
1518
2225
|
onClick: handleRightToggle,
|
|
1519
2226
|
"aria-label": rightCollapsed ? "Expand right panel" : "Collapse right panel",
|
|
1520
|
-
children: rightCollapsed ? /* @__PURE__ */
|
|
2227
|
+
children: rightCollapsed ? /* @__PURE__ */ jsx12(ChevronLeft, {}) : /* @__PURE__ */ jsx12(ChevronRight, {})
|
|
1521
2228
|
}
|
|
1522
2229
|
),
|
|
1523
|
-
showDisplayModeToggle && /* @__PURE__ */
|
|
2230
|
+
showDisplayModeToggle && /* @__PURE__ */ jsx12(
|
|
1524
2231
|
DisplayModeToggle,
|
|
1525
2232
|
{
|
|
1526
2233
|
mode: currentDisplayMode,
|
|
@@ -1529,9 +2236,9 @@ function FullscreenWorkspace({
|
|
|
1529
2236
|
children: currentDisplayMode === "dashboard" ? "Dashboard Mode" : "Standard Mode"
|
|
1530
2237
|
}
|
|
1531
2238
|
),
|
|
1532
|
-
/* @__PURE__ */
|
|
1533
|
-
showZoomControls && /* @__PURE__ */
|
|
1534
|
-
/* @__PURE__ */
|
|
2239
|
+
/* @__PURE__ */ jsxs9(SVGArea, { children: [
|
|
2240
|
+
showZoomControls && /* @__PURE__ */ jsxs9(ZoomControls, { children: [
|
|
2241
|
+
/* @__PURE__ */ jsx12(
|
|
1535
2242
|
ZoomButton,
|
|
1536
2243
|
{
|
|
1537
2244
|
onClick: onZoomIn,
|
|
@@ -1541,7 +2248,7 @@ function FullscreenWorkspace({
|
|
|
1541
2248
|
children: "+"
|
|
1542
2249
|
}
|
|
1543
2250
|
),
|
|
1544
|
-
/* @__PURE__ */
|
|
2251
|
+
/* @__PURE__ */ jsx12(
|
|
1545
2252
|
ZoomButton,
|
|
1546
2253
|
{
|
|
1547
2254
|
onClick: onZoomOut,
|
|
@@ -1551,7 +2258,7 @@ function FullscreenWorkspace({
|
|
|
1551
2258
|
children: "-"
|
|
1552
2259
|
}
|
|
1553
2260
|
),
|
|
1554
|
-
onResetZoom && /* @__PURE__ */
|
|
2261
|
+
onResetZoom && /* @__PURE__ */ jsx12(
|
|
1555
2262
|
ZoomButton,
|
|
1556
2263
|
{
|
|
1557
2264
|
onClick: onResetZoom,
|
|
@@ -1562,33 +2269,33 @@ function FullscreenWorkspace({
|
|
|
1562
2269
|
}
|
|
1563
2270
|
)
|
|
1564
2271
|
] }),
|
|
1565
|
-
/* @__PURE__ */
|
|
2272
|
+
/* @__PURE__ */ jsx12(ScrollableSVGWrapper, { className: "svg-scroll-wrapper", children: /* @__PURE__ */ jsxs9(FixedSVGContainer, { className: "svg-container", children: [
|
|
1566
2273
|
svgContent,
|
|
1567
2274
|
overlays
|
|
1568
2275
|
] }) })
|
|
1569
2276
|
] }),
|
|
1570
|
-
/* @__PURE__ */
|
|
1571
|
-
/* @__PURE__ */
|
|
2277
|
+
/* @__PURE__ */ jsx12(LeftPanel, { collapsed: leftCollapsed, children: resolvedTabs.length > 0 ? /* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
2278
|
+
/* @__PURE__ */ jsx12(
|
|
1572
2279
|
PanelTabs,
|
|
1573
2280
|
{
|
|
1574
2281
|
value: currentTab,
|
|
1575
2282
|
onChange: handleTabChangeInternal,
|
|
1576
2283
|
"aria-label": "Left panel tabs",
|
|
1577
|
-
children: resolvedTabs.map((tab) => /* @__PURE__ */
|
|
2284
|
+
children: resolvedTabs.map((tab) => /* @__PURE__ */ jsx12(Tab, { label: tab.label, value: tab.value }, tab.value))
|
|
1578
2285
|
}
|
|
1579
2286
|
),
|
|
1580
|
-
/* @__PURE__ */
|
|
2287
|
+
/* @__PURE__ */ jsx12(PanelContent, { children: currentTabContent })
|
|
1581
2288
|
] }) : leftPanel }),
|
|
1582
|
-
/* @__PURE__ */
|
|
1583
|
-
/* @__PURE__ */
|
|
2289
|
+
/* @__PURE__ */ jsx12(RightPanel, { collapsed: rightCollapsed, children: rightPanel }),
|
|
2290
|
+
/* @__PURE__ */ jsx12(FooterPanel, { children: footer })
|
|
1584
2291
|
]
|
|
1585
2292
|
}
|
|
1586
2293
|
);
|
|
1587
2294
|
}
|
|
1588
2295
|
|
|
1589
2296
|
// src/theme/ThemeContext.tsx
|
|
1590
|
-
import { createContext, useContext, useState as
|
|
1591
|
-
import { jsx as
|
|
2297
|
+
import { createContext, useContext, useState as useState7, useEffect as useEffect4 } from "react";
|
|
2298
|
+
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
1592
2299
|
var ThemeContext = createContext(void 0);
|
|
1593
2300
|
var useTheme = () => {
|
|
1594
2301
|
const context = useContext(ThemeContext);
|
|
@@ -1598,8 +2305,8 @@ var useTheme = () => {
|
|
|
1598
2305
|
return context;
|
|
1599
2306
|
};
|
|
1600
2307
|
var ThemeProvider = ({ children }) => {
|
|
1601
|
-
const [theme, setThemeState] =
|
|
1602
|
-
|
|
2308
|
+
const [theme, setThemeState] = useState7("modern");
|
|
2309
|
+
useEffect4(() => {
|
|
1603
2310
|
document.body.className = "";
|
|
1604
2311
|
document.body.classList.add(`theme-${theme}`);
|
|
1605
2312
|
document.documentElement.className = "";
|
|
@@ -1611,11 +2318,11 @@ var ThemeProvider = ({ children }) => {
|
|
|
1611
2318
|
const setTheme = (newTheme) => {
|
|
1612
2319
|
setThemeState(newTheme);
|
|
1613
2320
|
};
|
|
1614
|
-
return /* @__PURE__ */
|
|
2321
|
+
return /* @__PURE__ */ jsx13(ThemeContext.Provider, { value: { theme, toggleTheme, setTheme }, children });
|
|
1615
2322
|
};
|
|
1616
2323
|
|
|
1617
2324
|
// src/theme/ThemeToggle.tsx
|
|
1618
|
-
import { jsx as
|
|
2325
|
+
import { jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1619
2326
|
var ThemeToggle = ({
|
|
1620
2327
|
size = "medium",
|
|
1621
2328
|
position = "top-right",
|
|
@@ -1686,15 +2393,15 @@ var ThemeToggle = ({
|
|
|
1686
2393
|
transition: "all 0.2s ease",
|
|
1687
2394
|
boxShadow: "0 2px 4px rgba(0, 0, 0, 0.2)"
|
|
1688
2395
|
};
|
|
1689
|
-
return /* @__PURE__ */
|
|
1690
|
-
/* @__PURE__ */
|
|
1691
|
-
/* @__PURE__ */
|
|
1692
|
-
/* @__PURE__ */
|
|
2396
|
+
return /* @__PURE__ */ jsxs10("div", { style: currentStyle, onClick: toggleTheme, className, ...props, children: [
|
|
2397
|
+
/* @__PURE__ */ jsx14("span", { children: theme === "modern" ? "\u{1F3A8} Modern" : "\u{1F3ED} HMI" }),
|
|
2398
|
+
/* @__PURE__ */ jsx14("div", { style: toggleStyle, children: /* @__PURE__ */ jsx14("div", { style: thumbStyle }) }),
|
|
2399
|
+
/* @__PURE__ */ jsx14("span", { style: { fontSize: "0.75rem", opacity: 0.8 }, children: theme === "modern" ? "Industrial Design" : "High Performance" })
|
|
1693
2400
|
] });
|
|
1694
2401
|
};
|
|
1695
2402
|
|
|
1696
2403
|
// src/components/PIDCanvas/PIDCanvas.tsx
|
|
1697
|
-
import { useCallback as useCallback7, useState as
|
|
2404
|
+
import { useCallback as useCallback7, useState as useState13, useEffect as useEffect11, useRef as useRef5 } from "react";
|
|
1698
2405
|
|
|
1699
2406
|
// src/diagram/symbols/mockSymbolLibrary.ts
|
|
1700
2407
|
var mockSymbolLibrary = {
|
|
@@ -1702,13 +2409,13 @@ var mockSymbolLibrary = {
|
|
|
1702
2409
|
id: "valve-gate",
|
|
1703
2410
|
name: "Gate Valve (Powered)",
|
|
1704
2411
|
category: "valve",
|
|
1705
|
-
viewBox: { x: 0, y: 0, width:
|
|
2412
|
+
viewBox: { x: 0, y: 0, width: 26, height: 26 },
|
|
1706
2413
|
ports: [
|
|
1707
|
-
{ id: "inlet", x: 0, y:
|
|
1708
|
-
{ id: "outlet", x:
|
|
2414
|
+
{ id: "inlet", x: 0, y: 18, type: "inlet", direction: "in" },
|
|
2415
|
+
{ id: "outlet", x: 26, y: 18, type: "outlet", direction: "out" }
|
|
1709
2416
|
],
|
|
1710
2417
|
svgContent: `
|
|
1711
|
-
<g>
|
|
2418
|
+
<g transform="scale(0.5)">
|
|
1712
2419
|
<!-- Actuator box -->
|
|
1713
2420
|
<rect x="16.74" y="0" width="18.02" height="18.02" fill="var(--symbol-fill, #edeeef)" stroke="var(--symbol-stroke, #666666)" pointer-events="all"/>
|
|
1714
2421
|
<!-- Actuator stem -->
|
|
@@ -1726,13 +2433,13 @@ var mockSymbolLibrary = {
|
|
|
1726
2433
|
id: "pump-positive-displacement",
|
|
1727
2434
|
name: "Positive Displacement Pump",
|
|
1728
2435
|
category: "pump",
|
|
1729
|
-
viewBox: { x: 0, y: 0, width:
|
|
2436
|
+
viewBox: { x: 0, y: 0, width: 28.125, height: 28.125 },
|
|
1730
2437
|
ports: [
|
|
1731
|
-
{ id: "inlet", x: 0, y:
|
|
1732
|
-
{ id: "outlet", x:
|
|
2438
|
+
{ id: "inlet", x: 0, y: 14.0625, type: "inlet", direction: "in" },
|
|
2439
|
+
{ id: "outlet", x: 28.125, y: 14.0625, type: "outlet", direction: "out" }
|
|
1733
2440
|
],
|
|
1734
2441
|
svgContent: `
|
|
1735
|
-
<g transform="scale(0.
|
|
2442
|
+
<g transform="scale(0.28125)">
|
|
1736
2443
|
<!-- Outer circle -->
|
|
1737
2444
|
<ellipse
|
|
1738
2445
|
cx="50"
|
|
@@ -1774,13 +2481,13 @@ var mockSymbolLibrary = {
|
|
|
1774
2481
|
id: "vannefold-bottom",
|
|
1775
2482
|
name: "Vannefold Block (Bottom)",
|
|
1776
2483
|
category: "valve",
|
|
1777
|
-
viewBox: { x: -0.
|
|
2484
|
+
viewBox: { x: -0.25, y: -0.25, width: 44, height: 33.892578 },
|
|
1778
2485
|
ports: [
|
|
1779
|
-
{ id: "bottom-inlet", x: 0, y:
|
|
1780
|
-
{ id: "top-outlet", x:
|
|
2486
|
+
{ id: "bottom-inlet", x: 0, y: 12.5, type: "control", direction: "in" },
|
|
2487
|
+
{ id: "top-outlet", x: 24, y: 32.5, type: "control", direction: "out" }
|
|
1781
2488
|
],
|
|
1782
2489
|
svgContent: `
|
|
1783
|
-
<g>
|
|
2490
|
+
<g transform="scale(0.5)">
|
|
1784
2491
|
<!-- Bottom inlet pipe -->
|
|
1785
2492
|
<path
|
|
1786
2493
|
d="M 3,29.785156 H 0 v -10 h 3 m 14,10 h 3 v -10 h -3 m -15,8 h 16 m -16,-6 h 16"
|
|
@@ -1838,13 +2545,13 @@ var mockSymbolLibrary = {
|
|
|
1838
2545
|
id: "vannefold-middle",
|
|
1839
2546
|
name: "Vannefold Block (Middle)",
|
|
1840
2547
|
category: "valve",
|
|
1841
|
-
viewBox: { x: -0.
|
|
2548
|
+
viewBox: { x: -0.25, y: -0.25, width: 47.5, height: 26.548828 },
|
|
1842
2549
|
ports: [
|
|
1843
|
-
{ id: "left-inlet", x: 0, y:
|
|
1844
|
-
{ id: "right-outlet", x:
|
|
2550
|
+
{ id: "left-inlet", x: 0, y: 13.65625, type: "control", direction: "in" },
|
|
2551
|
+
{ id: "right-outlet", x: 47.5, y: 13.65625, type: "control", direction: "out" }
|
|
1845
2552
|
],
|
|
1846
2553
|
svgContent: `
|
|
1847
|
-
<g>
|
|
2554
|
+
<g transform="scale(0.5)">
|
|
1848
2555
|
<!-- Left inlet pipe -->
|
|
1849
2556
|
<path
|
|
1850
2557
|
d="M 3,22.3125 H 0 v 10 H 3 m 14,-10 h 3 v 10 h -3 m -15,-8 h 16 m -16,6 h 16"
|
|
@@ -1893,13 +2600,13 @@ var mockSymbolLibrary = {
|
|
|
1893
2600
|
id: "vannefold-top",
|
|
1894
2601
|
name: "Vannefold Block (Top)",
|
|
1895
2602
|
category: "valve",
|
|
1896
|
-
viewBox: { x: -0.
|
|
2603
|
+
viewBox: { x: -0.25, y: -0.25, width: 47.5, height: 30.392578 },
|
|
1897
2604
|
ports: [
|
|
1898
|
-
{ id: "bottom-inlet", x: 0, y:
|
|
1899
|
-
{ id: "top-outlet", x:
|
|
2605
|
+
{ id: "bottom-inlet", x: 0, y: 17.5, type: "control", direction: "in" },
|
|
2606
|
+
{ id: "top-outlet", x: 24, y: 0, type: "control", direction: "out" }
|
|
1900
2607
|
],
|
|
1901
2608
|
svgContent: `
|
|
1902
|
-
<g>
|
|
2609
|
+
<g transform="scale(0.5)">
|
|
1903
2610
|
<!-- Bottom inlet pipe -->
|
|
1904
2611
|
<path
|
|
1905
2612
|
d="M 3,30 H 0 V 40 H 3 M 17,30 h 3 V 40 H 17 M 2,32 H 18 M 2,38 H 18"
|
|
@@ -1949,13 +2656,13 @@ var mockSymbolLibrary = {
|
|
|
1949
2656
|
id: "vannefold-top-top-inlet",
|
|
1950
2657
|
name: "Vannefold Block (Top, Top Inlet)",
|
|
1951
2658
|
category: "valve",
|
|
1952
|
-
viewBox: { x: 0, y: 0, width:
|
|
2659
|
+
viewBox: { x: 0, y: 0, width: 44, height: 33.788002 },
|
|
1953
2660
|
ports: [
|
|
1954
|
-
{ id: "top-inlet", x:
|
|
1955
|
-
{ id: "bottom-outlet", x: 0, y:
|
|
2661
|
+
{ id: "top-inlet", x: 23.5, y: 0, type: "control", direction: "in" },
|
|
2662
|
+
{ id: "bottom-outlet", x: 0, y: 21, type: "control", direction: "out" }
|
|
1956
2663
|
],
|
|
1957
2664
|
svgContent: `
|
|
1958
|
-
<g>
|
|
2665
|
+
<g transform="scale(0.5)">
|
|
1959
2666
|
<!-- Top inlet pipe flange -->
|
|
1960
2667
|
<path
|
|
1961
2668
|
d="M 52,3 V 1.3598666e-8 H 42 V 3 m 10,14 v 3 H 42 V 17 M 50,2 V 18 M 44,2 v 16"
|
|
@@ -2013,13 +2720,13 @@ var mockSymbolLibrary = {
|
|
|
2013
2720
|
id: "vannefold-left",
|
|
2014
2721
|
name: "Vannefold Block (Left)",
|
|
2015
2722
|
category: "valve",
|
|
2016
|
-
viewBox: { x: 0, y: 0, width:
|
|
2723
|
+
viewBox: { x: 0, y: 0, width: 33.892578, height: 44.25 },
|
|
2017
2724
|
ports: [
|
|
2018
|
-
{ id: "left-inlet", x: 0, y:
|
|
2019
|
-
{ id: "right-outlet", x:
|
|
2725
|
+
{ id: "left-inlet", x: 0, y: 20.75, type: "control", direction: "in" },
|
|
2726
|
+
{ id: "right-outlet", x: 21, y: 43.5, type: "control", direction: "out" }
|
|
2020
2727
|
],
|
|
2021
2728
|
svgContent: `
|
|
2022
|
-
<g>
|
|
2729
|
+
<g transform="scale(0.5)">
|
|
2023
2730
|
<!-- Left inlet pipe flange -->
|
|
2024
2731
|
<path
|
|
2025
2732
|
d="M 3,46.5 H 2.8789924e-8 v -10 H 3 m 14,10 h 3 v -10 h -3 m -15,8 h 16 m -16,-6 h 16"
|
|
@@ -2076,13 +2783,13 @@ var mockSymbolLibrary = {
|
|
|
2076
2783
|
id: "vannefold-right",
|
|
2077
2784
|
name: "Vannefold Block (Right)",
|
|
2078
2785
|
category: "valve",
|
|
2079
|
-
viewBox: { x: 0, y: 0, width:
|
|
2786
|
+
viewBox: { x: 0, y: 0, width: 33.892578, height: 44.25 },
|
|
2080
2787
|
ports: [
|
|
2081
|
-
{ id: "right-inlet", x:
|
|
2082
|
-
{ id: "left-outlet", x:
|
|
2788
|
+
{ id: "right-inlet", x: 33.892578, y: 20.75, type: "control", direction: "in" },
|
|
2789
|
+
{ id: "left-outlet", x: 12.392578, y: 43.75, type: "control", direction: "out" }
|
|
2083
2790
|
],
|
|
2084
2791
|
svgContent: `
|
|
2085
|
-
<g>
|
|
2792
|
+
<g transform="scale(0.5)">
|
|
2086
2793
|
<!-- Right inlet pipe flange -->
|
|
2087
2794
|
<path
|
|
2088
2795
|
d="m 63.785156,46.5 h 3 v -10 h -3 m -14,10 h -3 v -10 h 3 m 15,8 h -16 m 16,-6 h -16"
|
|
@@ -2139,16 +2846,16 @@ var mockSymbolLibrary = {
|
|
|
2139
2846
|
id: "pixer",
|
|
2140
2847
|
name: "Pixer",
|
|
2141
2848
|
category: "pump",
|
|
2142
|
-
viewBox: { x: 0, y: 0, width:
|
|
2849
|
+
viewBox: { x: 0, y: 0, width: 25.3125, height: 23.34375 },
|
|
2143
2850
|
ports: [
|
|
2144
|
-
{ id: "right-outlet", x:
|
|
2145
|
-
{ id: "left-outlet", x: 0, y:
|
|
2146
|
-
{ id: "left-inlet", x:
|
|
2147
|
-
{ id: "right-inlet", x: 0, y:
|
|
2148
|
-
{ id: "top-inlet", x:
|
|
2851
|
+
{ id: "right-outlet", x: 25.3125, y: 15.46875, type: "control", direction: "out" },
|
|
2852
|
+
{ id: "left-outlet", x: 0, y: 15.46875, type: "control", direction: "out" },
|
|
2853
|
+
{ id: "left-inlet", x: 25.3125, y: 9.84375, type: "control", direction: "in" },
|
|
2854
|
+
{ id: "right-inlet", x: 0, y: 9.84375, type: "control", direction: "in" },
|
|
2855
|
+
{ id: "top-inlet", x: 12.65625, y: 0, type: "control", direction: "in" }
|
|
2149
2856
|
],
|
|
2150
2857
|
svgContent: `
|
|
2151
|
-
<g transform="scale(0.
|
|
2858
|
+
<g transform="scale(0.0984375) translate(-195, -186)">
|
|
2152
2859
|
<!-- Top mounting flange -->
|
|
2153
2860
|
<rect
|
|
2154
2861
|
width="141.313"
|
|
@@ -2413,16 +3120,16 @@ var mockSymbolLibrary = {
|
|
|
2413
3120
|
id: "pixer-barb",
|
|
2414
3121
|
name: "Pixer (Hose Barb)",
|
|
2415
3122
|
category: "pump",
|
|
2416
|
-
viewBox: { x: 0, y: 0, width:
|
|
3123
|
+
viewBox: { x: 0, y: 0, width: 25.3125, height: 23.34375 },
|
|
2417
3124
|
ports: [
|
|
2418
|
-
{ id: "right-outlet", x:
|
|
2419
|
-
{ id: "left-outlet", x: 0, y:
|
|
2420
|
-
{ id: "left-inlet", x:
|
|
2421
|
-
{ id: "right-inlet", x: 0, y:
|
|
2422
|
-
{ id: "top-inlet", x:
|
|
3125
|
+
{ id: "right-outlet", x: 25.3125, y: 15.46875, type: "control", direction: "out" },
|
|
3126
|
+
{ id: "left-outlet", x: 0, y: 15.46875, type: "control", direction: "out" },
|
|
3127
|
+
{ id: "left-inlet", x: 25.3125, y: 9.84375, type: "control", direction: "in" },
|
|
3128
|
+
{ id: "right-inlet", x: 0, y: 9.84375, type: "control", direction: "in" },
|
|
3129
|
+
{ id: "top-inlet", x: 12.65625, y: 0, type: "control", direction: "in" }
|
|
2423
3130
|
],
|
|
2424
3131
|
svgContent: `
|
|
2425
|
-
<g transform="scale(0.
|
|
3132
|
+
<g transform="scale(0.0984375) translate(-195, -186)">
|
|
2426
3133
|
<!-- Hose barb ridges at top -->
|
|
2427
3134
|
<rect
|
|
2428
3135
|
width="20"
|
|
@@ -2704,15 +3411,15 @@ var mockSymbolLibrary = {
|
|
|
2704
3411
|
id: "vessel-balloon",
|
|
2705
3412
|
name: "Vessel",
|
|
2706
3413
|
category: "vessel",
|
|
2707
|
-
viewBox: { x: 0, y: 0, width:
|
|
3414
|
+
viewBox: { x: 0, y: 0, width: 25.3125, height: 45.5 },
|
|
2708
3415
|
ports: [
|
|
2709
|
-
{ id: "top", type: "inlet", x:
|
|
2710
|
-
{ id: "left", type: "inlet", x: 5, y:
|
|
2711
|
-
{ id: "right", type: "outlet", x:
|
|
2712
|
-
{ id: "bottom", type: "outlet", x:
|
|
3416
|
+
{ id: "top", type: "inlet", x: 12.65625, y: 0 },
|
|
3417
|
+
{ id: "left", type: "inlet", x: 2.5, y: 19.5 },
|
|
3418
|
+
{ id: "right", type: "outlet", x: 22.8125, y: 19.5 },
|
|
3419
|
+
{ id: "bottom", type: "outlet", x: 12.65625, y: 45.5 }
|
|
2713
3420
|
],
|
|
2714
3421
|
svgContent: `
|
|
2715
|
-
<g transform="scale(0.
|
|
3422
|
+
<g transform="scale(0.0984375) translate(-195, -100)">
|
|
2716
3423
|
<!-- Top opening nozzle -->
|
|
2717
3424
|
<rect
|
|
2718
3425
|
width="65"
|
|
@@ -2777,19 +3484,53 @@ var mockSymbolLibrary = {
|
|
|
2777
3484
|
tags: ["vessel", "storage", "tank", "balloon"]
|
|
2778
3485
|
}
|
|
2779
3486
|
},
|
|
3487
|
+
"hollow-fiber": {
|
|
3488
|
+
id: "hollow-fiber",
|
|
3489
|
+
name: "Hollow Fiber",
|
|
3490
|
+
category: "other",
|
|
3491
|
+
viewBox: { x: 0, y: 0, width: 30, height: 109 },
|
|
3492
|
+
ports: [
|
|
3493
|
+
{ id: "top-left", type: "outlet", x: 10, y: 2.75 },
|
|
3494
|
+
{ id: "top-right", type: "outlet", x: 24.5, y: 22.25 },
|
|
3495
|
+
{ id: "bottom-left", type: "inlet", x: 10, y: 106.25 },
|
|
3496
|
+
{ id: "bottom-right", type: "inlet", x: 24.5, y: 87.25 }
|
|
3497
|
+
],
|
|
3498
|
+
svgContent: `
|
|
3499
|
+
<g transform="scale(0.5)">
|
|
3500
|
+
<!-- Top left flange -->
|
|
3501
|
+
<rect x="10.5" y="0.5" width="20" height="10" rx="1.5" ry="1.5" fill="var(--symbol-fill, #eaeaea)" stroke="var(--symbol-stroke, #000000)" />
|
|
3502
|
+
|
|
3503
|
+
<!-- Top right flange -->
|
|
3504
|
+
<rect x="39.5" y="39.5" width="20" height="10" rx="1.5" ry="1.5" fill="var(--symbol-fill, #eaeaea)" stroke="var(--symbol-stroke, #000000)" />
|
|
3505
|
+
|
|
3506
|
+
<!-- Bottom left flange -->
|
|
3507
|
+
<rect x="10.5" y="207.5" width="20" height="10" rx="1.5" ry="1.5" fill="var(--symbol-fill, #eaeaea)" stroke="var(--symbol-stroke, #000000)" />
|
|
3508
|
+
|
|
3509
|
+
<!-- Bottom right flange -->
|
|
3510
|
+
<rect x="39.5" y="169.5" width="20" height="10" rx="1.5" ry="1.5" fill="var(--symbol-fill, #eaeaea)" stroke="var(--symbol-stroke, #000000)" />
|
|
3511
|
+
|
|
3512
|
+
<!-- Main vessel body -->
|
|
3513
|
+
<rect x="0.5" y="9.5" width="40" height="199.5" rx="6" ry="6" fill="var(--symbol-fill, #eaeaea)" stroke="var(--symbol-stroke, #000000)" />
|
|
3514
|
+
</g>
|
|
3515
|
+
`,
|
|
3516
|
+
metadata: {
|
|
3517
|
+
description: "Hollow fiber filter module with multiple inlet/outlet connections",
|
|
3518
|
+
tags: ["filter", "hollow-fiber", "filtration", "separation", "membrane"]
|
|
3519
|
+
}
|
|
3520
|
+
},
|
|
2780
3521
|
"psr-f": {
|
|
2781
3522
|
id: "psr-f",
|
|
2782
3523
|
name: "PSR F",
|
|
2783
3524
|
category: "instrument",
|
|
2784
|
-
viewBox: { x: 0, y: 0, width:
|
|
3525
|
+
viewBox: { x: 0, y: 0, width: 28.5, height: 28.5 },
|
|
2785
3526
|
ports: [
|
|
2786
|
-
{ id: "top", type: "signal", x:
|
|
2787
|
-
{ id: "right", type: "signal", x:
|
|
2788
|
-
{ id: "bottom", type: "signal", x:
|
|
2789
|
-
{ id: "left", type: "signal", x:
|
|
3527
|
+
{ id: "top", type: "signal", x: 14.25, y: 7.125 },
|
|
3528
|
+
{ id: "right", type: "signal", x: 21.375, y: 14.25 },
|
|
3529
|
+
{ id: "bottom", type: "signal", x: 14.25, y: 21.375 },
|
|
3530
|
+
{ id: "left", type: "signal", x: 7.125, y: 14.25 }
|
|
2790
3531
|
],
|
|
2791
3532
|
svgContent: `
|
|
2792
|
-
<g transform="scale(0.
|
|
3533
|
+
<g transform="scale(0.25) translate(28.5, 28.5)">
|
|
2793
3534
|
<!-- Circle background -->
|
|
2794
3535
|
<ellipse
|
|
2795
3536
|
cx="28.5"
|
|
@@ -2823,15 +3564,15 @@ var mockSymbolLibrary = {
|
|
|
2823
3564
|
id: "psr-p",
|
|
2824
3565
|
name: "PSR P",
|
|
2825
3566
|
category: "instrument",
|
|
2826
|
-
viewBox: { x: 0, y: 0, width:
|
|
3567
|
+
viewBox: { x: 0, y: 0, width: 28.5, height: 28.5 },
|
|
2827
3568
|
ports: [
|
|
2828
|
-
{ id: "top", type: "signal", x:
|
|
2829
|
-
{ id: "right", type: "signal", x:
|
|
2830
|
-
{ id: "bottom", type: "signal", x:
|
|
2831
|
-
{ id: "left", type: "signal", x:
|
|
3569
|
+
{ id: "top", type: "signal", x: 14.25, y: 7.125 },
|
|
3570
|
+
{ id: "right", type: "signal", x: 21.375, y: 14.25 },
|
|
3571
|
+
{ id: "bottom", type: "signal", x: 14.25, y: 21.375 },
|
|
3572
|
+
{ id: "left", type: "signal", x: 7.125, y: 14.25 }
|
|
2832
3573
|
],
|
|
2833
3574
|
svgContent: `
|
|
2834
|
-
<g transform="scale(0.
|
|
3575
|
+
<g transform="scale(0.25) translate(28.5, 28.5)">
|
|
2835
3576
|
<!-- Circle background -->
|
|
2836
3577
|
<ellipse
|
|
2837
3578
|
cx="28.5"
|
|
@@ -2862,15 +3603,26 @@ var mockSymbolLibrary = {
|
|
|
2862
3603
|
}
|
|
2863
3604
|
}
|
|
2864
3605
|
};
|
|
3606
|
+
var customSymbols = {};
|
|
3607
|
+
function registerSymbol(symbol) {
|
|
3608
|
+
customSymbols[symbol.id] = symbol;
|
|
3609
|
+
}
|
|
3610
|
+
function registerSymbols(symbols) {
|
|
3611
|
+
if (Array.isArray(symbols)) {
|
|
3612
|
+
symbols.forEach((symbol) => registerSymbol(symbol));
|
|
3613
|
+
} else {
|
|
3614
|
+
Object.values(symbols).forEach((symbol) => registerSymbol(symbol));
|
|
3615
|
+
}
|
|
3616
|
+
}
|
|
2865
3617
|
function getSymbolDefinition(symbolId) {
|
|
2866
|
-
return mockSymbolLibrary[symbolId];
|
|
3618
|
+
return customSymbols[symbolId] ?? mockSymbolLibrary[symbolId];
|
|
2867
3619
|
}
|
|
2868
3620
|
function getAvailableSymbols() {
|
|
2869
|
-
return Object.keys(mockSymbolLibrary);
|
|
3621
|
+
return [...Object.keys(customSymbols), ...Object.keys(mockSymbolLibrary)];
|
|
2870
3622
|
}
|
|
2871
3623
|
|
|
2872
3624
|
// src/components/PIDCanvas/NodeRenderer.tsx
|
|
2873
|
-
import { jsx as
|
|
3625
|
+
import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2874
3626
|
function NodeRenderer({
|
|
2875
3627
|
nodes: nodes2,
|
|
2876
3628
|
selectedNodeIds,
|
|
@@ -2881,13 +3633,13 @@ function NodeRenderer({
|
|
|
2881
3633
|
dragOffset = { x: 0, y: 0 },
|
|
2882
3634
|
enableDrag = false
|
|
2883
3635
|
}) {
|
|
2884
|
-
return /* @__PURE__ */
|
|
3636
|
+
return /* @__PURE__ */ jsx15("g", { id: "layer-nodes", children: nodes2.filter((node) => node.visible !== false).map((node) => {
|
|
2885
3637
|
const symbol = getSymbolDefinition(node.symbolId);
|
|
2886
3638
|
const isSelected = selectedNodeIds?.has(node.id) ?? false;
|
|
2887
3639
|
const isDragging = draggingNodeId === node.id;
|
|
2888
3640
|
if (!symbol) {
|
|
2889
|
-
return /* @__PURE__ */
|
|
2890
|
-
/* @__PURE__ */
|
|
3641
|
+
return /* @__PURE__ */ jsxs11("g", { children: [
|
|
3642
|
+
/* @__PURE__ */ jsx15(
|
|
2891
3643
|
"circle",
|
|
2892
3644
|
{
|
|
2893
3645
|
cx: node.transform.x,
|
|
@@ -2899,7 +3651,7 @@ function NodeRenderer({
|
|
|
2899
3651
|
strokeWidth: "2"
|
|
2900
3652
|
}
|
|
2901
3653
|
),
|
|
2902
|
-
/* @__PURE__ */
|
|
3654
|
+
/* @__PURE__ */ jsx15(
|
|
2903
3655
|
"text",
|
|
2904
3656
|
{
|
|
2905
3657
|
x: node.transform.x,
|
|
@@ -2956,7 +3708,7 @@ function NodeRenderer({
|
|
|
2956
3708
|
};
|
|
2957
3709
|
const fillColor = node.customColors?.fill ?? getStatusColor(node.status);
|
|
2958
3710
|
const strokeColor = node.customColors?.stroke ?? "rgb(0, 0, 0)";
|
|
2959
|
-
return /* @__PURE__ */
|
|
3711
|
+
return /* @__PURE__ */ jsxs11(
|
|
2960
3712
|
"g",
|
|
2961
3713
|
{
|
|
2962
3714
|
"data-node-id": node.id,
|
|
@@ -2989,7 +3741,7 @@ function NodeRenderer({
|
|
|
2989
3741
|
}
|
|
2990
3742
|
},
|
|
2991
3743
|
children: [
|
|
2992
|
-
isSelected && /* @__PURE__ */
|
|
3744
|
+
isSelected && /* @__PURE__ */ jsx15(
|
|
2993
3745
|
"rect",
|
|
2994
3746
|
{
|
|
2995
3747
|
x: "-5",
|
|
@@ -3004,7 +3756,7 @@ function NodeRenderer({
|
|
|
3004
3756
|
pointerEvents: "none"
|
|
3005
3757
|
}
|
|
3006
3758
|
),
|
|
3007
|
-
/* @__PURE__ */
|
|
3759
|
+
/* @__PURE__ */ jsx15(
|
|
3008
3760
|
"g",
|
|
3009
3761
|
{
|
|
3010
3762
|
dangerouslySetInnerHTML: { __html: symbol.svgContent },
|
|
@@ -3012,7 +3764,7 @@ function NodeRenderer({
|
|
|
3012
3764
|
style: { pointerEvents: "auto" }
|
|
3013
3765
|
}
|
|
3014
3766
|
),
|
|
3015
|
-
/* @__PURE__ */
|
|
3767
|
+
/* @__PURE__ */ jsx15(
|
|
3016
3768
|
"text",
|
|
3017
3769
|
{
|
|
3018
3770
|
x: symbol.viewBox.width / 2 + (node.labelOffset?.x ?? 0),
|
|
@@ -3033,7 +3785,7 @@ function NodeRenderer({
|
|
|
3033
3785
|
}
|
|
3034
3786
|
|
|
3035
3787
|
// src/components/PIDCanvas/PipeRenderer.tsx
|
|
3036
|
-
import { Fragment as
|
|
3788
|
+
import { Fragment as Fragment5, jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
3037
3789
|
function PipeRenderer({
|
|
3038
3790
|
pipes,
|
|
3039
3791
|
selectedPipeIds,
|
|
@@ -3048,7 +3800,7 @@ function PipeRenderer({
|
|
|
3048
3800
|
waypointDragOffset,
|
|
3049
3801
|
onPipeSegmentClick
|
|
3050
3802
|
}) {
|
|
3051
|
-
return /* @__PURE__ */
|
|
3803
|
+
return /* @__PURE__ */ jsx16("g", { id: "layer-pipes", children: pipes.filter((pipe) => pipe.visible !== false).map((pipe) => {
|
|
3052
3804
|
const isSelected = selectedPipeIds?.has(pipe.id) ?? false;
|
|
3053
3805
|
const isEditing = enableWaypointEditing && editingPipeId === pipe.id;
|
|
3054
3806
|
const showEditingControls = enableWaypointEditing && isSelected;
|
|
@@ -3067,7 +3819,7 @@ function PipeRenderer({
|
|
|
3067
3819
|
const strokeWidth = isSelected ? (pipeStyle.strokeWidth || 3) + 2 : pipeStyle.strokeWidth || 3;
|
|
3068
3820
|
const strokeDasharray = pipeStyle.strokeDasharray;
|
|
3069
3821
|
const opacity = pipeStyle.opacity !== void 0 ? pipeStyle.opacity : 1;
|
|
3070
|
-
return /* @__PURE__ */
|
|
3822
|
+
return /* @__PURE__ */ jsxs12(
|
|
3071
3823
|
"g",
|
|
3072
3824
|
{
|
|
3073
3825
|
"data-pipe-id": pipe.id,
|
|
@@ -3080,8 +3832,8 @@ function PipeRenderer({
|
|
|
3080
3832
|
cursor: onPipeClick ? "pointer" : "default"
|
|
3081
3833
|
},
|
|
3082
3834
|
children: [
|
|
3083
|
-
!enableWaypointEditing && /* @__PURE__ */
|
|
3084
|
-
onPipeClick && /* @__PURE__ */
|
|
3835
|
+
!enableWaypointEditing && /* @__PURE__ */ jsxs12(Fragment5, { children: [
|
|
3836
|
+
onPipeClick && /* @__PURE__ */ jsx16(
|
|
3085
3837
|
"polyline",
|
|
3086
3838
|
{
|
|
3087
3839
|
points: pointsString,
|
|
@@ -3093,7 +3845,7 @@ function PipeRenderer({
|
|
|
3093
3845
|
pointerEvents: "stroke"
|
|
3094
3846
|
}
|
|
3095
3847
|
),
|
|
3096
|
-
/* @__PURE__ */
|
|
3848
|
+
/* @__PURE__ */ jsx16(
|
|
3097
3849
|
"polyline",
|
|
3098
3850
|
{
|
|
3099
3851
|
points: pointsString,
|
|
@@ -3117,7 +3869,7 @@ function PipeRenderer({
|
|
|
3117
3869
|
const waypointSize = isSelectedWaypoint ? 8 : isDragging ? 8 : showEditingControls ? 6 : isSelected ? 3 : 2;
|
|
3118
3870
|
const waypointOpacity = isSelectedWaypoint ? 1 : isDragging ? 1 : showEditingControls ? 0.9 : isSelected ? 0.8 : 0.5;
|
|
3119
3871
|
const waypointColor = isSelectedWaypoint ? "#3b82f6" : isEndpoint && showEditingControls ? "#f59e0b" : isDragging ? "#10b981" : stroke;
|
|
3120
|
-
return /* @__PURE__ */
|
|
3872
|
+
return /* @__PURE__ */ jsx16(
|
|
3121
3873
|
"circle",
|
|
3122
3874
|
{
|
|
3123
3875
|
cx: point.x,
|
|
@@ -3154,12 +3906,12 @@ function PipeRenderer({
|
|
|
3154
3906
|
`${pipe.id}-point-${idx}`
|
|
3155
3907
|
);
|
|
3156
3908
|
}),
|
|
3157
|
-
showEditingControls && onPipeSegmentClick && displayPoints.length >= 2 && /* @__PURE__ */
|
|
3909
|
+
showEditingControls && onPipeSegmentClick && displayPoints.length >= 2 && /* @__PURE__ */ jsx16(Fragment5, { children: displayPoints.slice(0, -1).map((point, idx) => {
|
|
3158
3910
|
const nextPoint = displayPoints[idx + 1];
|
|
3159
3911
|
const midX = (point.x + nextPoint.x) / 2;
|
|
3160
3912
|
const midY = (point.y + nextPoint.y) / 2;
|
|
3161
|
-
return /* @__PURE__ */
|
|
3162
|
-
/* @__PURE__ */
|
|
3913
|
+
return /* @__PURE__ */ jsxs12("g", { children: [
|
|
3914
|
+
/* @__PURE__ */ jsx16(
|
|
3163
3915
|
"circle",
|
|
3164
3916
|
{
|
|
3165
3917
|
cx: midX,
|
|
@@ -3175,7 +3927,7 @@ function PipeRenderer({
|
|
|
3175
3927
|
}
|
|
3176
3928
|
}
|
|
3177
3929
|
),
|
|
3178
|
-
/* @__PURE__ */
|
|
3930
|
+
/* @__PURE__ */ jsx16(
|
|
3179
3931
|
"circle",
|
|
3180
3932
|
{
|
|
3181
3933
|
cx: midX,
|
|
@@ -3191,7 +3943,7 @@ function PipeRenderer({
|
|
|
3191
3943
|
)
|
|
3192
3944
|
] }, `${pipe.id}-segment-${idx}`);
|
|
3193
3945
|
}) }),
|
|
3194
|
-
pipe.showLabel !== false && pipe.label && pipe.routePoints.length >= 2 && /* @__PURE__ */
|
|
3946
|
+
pipe.showLabel !== false && pipe.label && pipe.routePoints.length >= 2 && /* @__PURE__ */ jsx16(
|
|
3195
3947
|
"text",
|
|
3196
3948
|
{
|
|
3197
3949
|
x: pipe.routePoints[Math.floor(pipe.routePoints.length / 2)].x + (pipe.labelOffset?.x ?? 0),
|
|
@@ -3213,7 +3965,7 @@ function PipeRenderer({
|
|
|
3213
3965
|
}
|
|
3214
3966
|
|
|
3215
3967
|
// src/components/PIDCanvas/DataOverlay.tsx
|
|
3216
|
-
import { Fragment as
|
|
3968
|
+
import { Fragment as Fragment6, jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
3217
3969
|
function DataOverlay({
|
|
3218
3970
|
nodeId,
|
|
3219
3971
|
x,
|
|
@@ -3233,7 +3985,7 @@ function DataOverlay({
|
|
|
3233
3985
|
const offsetX = display?.offsetX ?? 0;
|
|
3234
3986
|
const offsetY = display?.offsetY ?? 0;
|
|
3235
3987
|
if (!showValue) {
|
|
3236
|
-
return /* @__PURE__ */
|
|
3988
|
+
return /* @__PURE__ */ jsx17(Fragment6, {});
|
|
3237
3989
|
}
|
|
3238
3990
|
const formatValue = (val) => {
|
|
3239
3991
|
if (typeof val === "number") {
|
|
@@ -3251,9 +4003,14 @@ function DataOverlay({
|
|
|
3251
4003
|
fault: { bg: "#dc2626", text: "#ffffff", border: "#b91c1c" },
|
|
3252
4004
|
off: { bg: "#6b7280", text: "#ffffff", border: "#4b5563" }
|
|
3253
4005
|
};
|
|
3254
|
-
const
|
|
3255
|
-
|
|
3256
|
-
|
|
4006
|
+
const getStatusColors = () => {
|
|
4007
|
+
const customColor = telemetry.statusColors?.[value.status];
|
|
4008
|
+
if (customColor) {
|
|
4009
|
+
return { bg: customColor, text: "#ffffff", border: customColor };
|
|
4010
|
+
}
|
|
4011
|
+
return defaultStatusColors[value.status] || defaultStatusColors.normal;
|
|
4012
|
+
};
|
|
4013
|
+
const statusColors = getStatusColors();
|
|
3257
4014
|
const colors = backgroundColor && backgroundColor !== "status" ? { bg: backgroundColor, text: textColor || "#ffffff", border: backgroundColor } : statusColors;
|
|
3258
4015
|
const finalTextColor = textColor || colors.text;
|
|
3259
4016
|
const formattedValue = formatValue(value.value);
|
|
@@ -3280,8 +4037,8 @@ function DataOverlay({
|
|
|
3280
4037
|
const overlayWidth = 80 * scale;
|
|
3281
4038
|
const displayX = x + offsetX;
|
|
3282
4039
|
const displayY = y + offsetY;
|
|
3283
|
-
return /* @__PURE__ */
|
|
3284
|
-
/* @__PURE__ */
|
|
4040
|
+
return /* @__PURE__ */ jsxs13("g", { "data-overlay-node": nodeId, "data-status": value.status, children: [
|
|
4041
|
+
/* @__PURE__ */ jsx17(
|
|
3285
4042
|
"rect",
|
|
3286
4043
|
{
|
|
3287
4044
|
x: displayX - overlayWidth / 2,
|
|
@@ -3296,7 +4053,7 @@ function DataOverlay({
|
|
|
3296
4053
|
filter: "drop-shadow(0 2px 4px rgba(0,0,0,0.2))"
|
|
3297
4054
|
}
|
|
3298
4055
|
),
|
|
3299
|
-
label && /* @__PURE__ */
|
|
4056
|
+
label && /* @__PURE__ */ jsx17(
|
|
3300
4057
|
"text",
|
|
3301
4058
|
{
|
|
3302
4059
|
x: displayX,
|
|
@@ -3309,7 +4066,7 @@ function DataOverlay({
|
|
|
3309
4066
|
children: label
|
|
3310
4067
|
}
|
|
3311
4068
|
),
|
|
3312
|
-
/* @__PURE__ */
|
|
4069
|
+
/* @__PURE__ */ jsx17(
|
|
3313
4070
|
"text",
|
|
3314
4071
|
{
|
|
3315
4072
|
x: displayX,
|
|
@@ -3322,7 +4079,7 @@ function DataOverlay({
|
|
|
3322
4079
|
children: displayText
|
|
3323
4080
|
}
|
|
3324
4081
|
),
|
|
3325
|
-
showStatus && value.status !== "normal" && /* @__PURE__ */
|
|
4082
|
+
showStatus && value.status !== "normal" && /* @__PURE__ */ jsx17(
|
|
3326
4083
|
"circle",
|
|
3327
4084
|
{
|
|
3328
4085
|
cx: displayX + 35 * scale,
|
|
@@ -3330,7 +4087,7 @@ function DataOverlay({
|
|
|
3330
4087
|
r: 3 * scale,
|
|
3331
4088
|
fill: finalTextColor,
|
|
3332
4089
|
opacity: "0.9",
|
|
3333
|
-
children: /* @__PURE__ */
|
|
4090
|
+
children: /* @__PURE__ */ jsx17(
|
|
3334
4091
|
"animate",
|
|
3335
4092
|
{
|
|
3336
4093
|
attributeName: "opacity",
|
|
@@ -3341,7 +4098,7 @@ function DataOverlay({
|
|
|
3341
4098
|
)
|
|
3342
4099
|
}
|
|
3343
4100
|
),
|
|
3344
|
-
value.quality !== void 0 && value.quality < 100 && /* @__PURE__ */
|
|
4101
|
+
value.quality !== void 0 && value.quality < 100 && /* @__PURE__ */ jsxs13(
|
|
3345
4102
|
"text",
|
|
3346
4103
|
{
|
|
3347
4104
|
x: displayX,
|
|
@@ -3358,7 +4115,7 @@ function DataOverlay({
|
|
|
3358
4115
|
]
|
|
3359
4116
|
}
|
|
3360
4117
|
),
|
|
3361
|
-
hasSparkline && /* @__PURE__ */
|
|
4118
|
+
hasSparkline && /* @__PURE__ */ jsx17("g", { transform: `translate(${displayX - 35 * scale}, ${displayY + (label ? 5 : 0) * scale})`, children: /* @__PURE__ */ jsx17(
|
|
3362
4119
|
"path",
|
|
3363
4120
|
{
|
|
3364
4121
|
d: sparklinePath,
|
|
@@ -3374,8 +4131,8 @@ function DataOverlay({
|
|
|
3374
4131
|
}
|
|
3375
4132
|
|
|
3376
4133
|
// src/components/PIDCanvas/PositionPanel.tsx
|
|
3377
|
-
import { useState as
|
|
3378
|
-
import { jsx as
|
|
4134
|
+
import { useState as useState8, useEffect as useEffect5 } from "react";
|
|
4135
|
+
import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
3379
4136
|
function PositionPanel({
|
|
3380
4137
|
selectedNode,
|
|
3381
4138
|
selectedWaypoint,
|
|
@@ -3383,9 +4140,9 @@ function PositionPanel({
|
|
|
3383
4140
|
onWaypointPositionChange,
|
|
3384
4141
|
position = "top-right"
|
|
3385
4142
|
}) {
|
|
3386
|
-
const [x, setX] =
|
|
3387
|
-
const [y, setY] =
|
|
3388
|
-
|
|
4143
|
+
const [x, setX] = useState8("");
|
|
4144
|
+
const [y, setY] = useState8("");
|
|
4145
|
+
useEffect5(() => {
|
|
3389
4146
|
if (selectedNode) {
|
|
3390
4147
|
setX(selectedNode.transform.x.toFixed(2));
|
|
3391
4148
|
setY(selectedNode.transform.y.toFixed(2));
|
|
@@ -3444,7 +4201,7 @@ function PositionPanel({
|
|
|
3444
4201
|
"bottom-left": { bottom: 10, left: 10 },
|
|
3445
4202
|
"bottom-right": { bottom: 10, right: 10 }
|
|
3446
4203
|
};
|
|
3447
|
-
return /* @__PURE__ */
|
|
4204
|
+
return /* @__PURE__ */ jsxs14(
|
|
3448
4205
|
"div",
|
|
3449
4206
|
{
|
|
3450
4207
|
style: {
|
|
@@ -3461,11 +4218,11 @@ function PositionPanel({
|
|
|
3461
4218
|
fontSize: "13px"
|
|
3462
4219
|
},
|
|
3463
4220
|
children: [
|
|
3464
|
-
/* @__PURE__ */
|
|
3465
|
-
/* @__PURE__ */
|
|
3466
|
-
/* @__PURE__ */
|
|
3467
|
-
/* @__PURE__ */
|
|
3468
|
-
/* @__PURE__ */
|
|
4221
|
+
/* @__PURE__ */ jsx18("div", { style: { marginBottom: "8px", fontWeight: 600, color: "#333" }, children: "Position" }),
|
|
4222
|
+
/* @__PURE__ */ jsxs14("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: [
|
|
4223
|
+
/* @__PURE__ */ jsxs14("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
|
|
4224
|
+
/* @__PURE__ */ jsx18("label", { style: { width: "16px", color: "#666" }, children: "X:" }),
|
|
4225
|
+
/* @__PURE__ */ jsx18(
|
|
3469
4226
|
"input",
|
|
3470
4227
|
{
|
|
3471
4228
|
type: "number",
|
|
@@ -3483,9 +4240,9 @@ function PositionPanel({
|
|
|
3483
4240
|
}
|
|
3484
4241
|
)
|
|
3485
4242
|
] }),
|
|
3486
|
-
/* @__PURE__ */
|
|
3487
|
-
/* @__PURE__ */
|
|
3488
|
-
/* @__PURE__ */
|
|
4243
|
+
/* @__PURE__ */ jsxs14("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
|
|
4244
|
+
/* @__PURE__ */ jsx18("label", { style: { width: "16px", color: "#666" }, children: "Y:" }),
|
|
4245
|
+
/* @__PURE__ */ jsx18(
|
|
3489
4246
|
"input",
|
|
3490
4247
|
{
|
|
3491
4248
|
type: "number",
|
|
@@ -3504,14 +4261,14 @@ function PositionPanel({
|
|
|
3504
4261
|
)
|
|
3505
4262
|
] })
|
|
3506
4263
|
] }),
|
|
3507
|
-
/* @__PURE__ */
|
|
4264
|
+
/* @__PURE__ */ jsx18("div", { style: { marginTop: "8px", fontSize: "11px", color: "#888" }, children: "Use arrow keys to nudge (\xB11px)" })
|
|
3508
4265
|
]
|
|
3509
4266
|
}
|
|
3510
4267
|
);
|
|
3511
4268
|
}
|
|
3512
4269
|
|
|
3513
4270
|
// src/diagram/hooks/useViewBox.ts
|
|
3514
|
-
import { useState as
|
|
4271
|
+
import { useState as useState9, useCallback as useCallback3, useRef as useRef2, useEffect as useEffect6 } from "react";
|
|
3515
4272
|
function useViewBox(options) {
|
|
3516
4273
|
const {
|
|
3517
4274
|
initialViewBox,
|
|
@@ -3522,7 +4279,7 @@ function useViewBox(options) {
|
|
|
3522
4279
|
zoomSensitivity = 1e-3,
|
|
3523
4280
|
allowLeftClickPan = true
|
|
3524
4281
|
} = options;
|
|
3525
|
-
const [viewBox, setViewBox] =
|
|
4282
|
+
const [viewBox, setViewBox] = useState9(initialViewBox);
|
|
3526
4283
|
const svgRef = useRef2(null);
|
|
3527
4284
|
const isPanningRef = useRef2(false);
|
|
3528
4285
|
const lastMousePosRef = useRef2({ x: 0, y: 0 });
|
|
@@ -3593,7 +4350,7 @@ function useViewBox(options) {
|
|
|
3593
4350
|
height: newHeight
|
|
3594
4351
|
});
|
|
3595
4352
|
}, [initialViewBox]);
|
|
3596
|
-
|
|
4353
|
+
useEffect6(() => {
|
|
3597
4354
|
if (!enableZoom || !svgRef.current) return;
|
|
3598
4355
|
const svg = svgRef.current;
|
|
3599
4356
|
const handleWheel = (e) => {
|
|
@@ -3626,7 +4383,7 @@ function useViewBox(options) {
|
|
|
3626
4383
|
svg.addEventListener("wheel", handleWheel, { passive: false });
|
|
3627
4384
|
return () => svg.removeEventListener("wheel", handleWheel);
|
|
3628
4385
|
}, [enableZoom, zoomSensitivity, minZoom, initialViewBox]);
|
|
3629
|
-
|
|
4386
|
+
useEffect6(() => {
|
|
3630
4387
|
if (!enablePan || !svgRef.current) return;
|
|
3631
4388
|
const svg = svgRef.current;
|
|
3632
4389
|
const handleMouseDown = (e) => {
|
|
@@ -3702,7 +4459,7 @@ function useViewBox(options) {
|
|
|
3702
4459
|
window.removeEventListener("keyup", handleKeyUp);
|
|
3703
4460
|
};
|
|
3704
4461
|
}, [enablePan, allowLeftClickPan]);
|
|
3705
|
-
|
|
4462
|
+
useEffect6(() => {
|
|
3706
4463
|
if (!svgRef.current) return;
|
|
3707
4464
|
if (!enablePan && !enableZoom) return;
|
|
3708
4465
|
const svg = svgRef.current;
|
|
@@ -3832,14 +4589,14 @@ function useViewBox(options) {
|
|
|
3832
4589
|
}
|
|
3833
4590
|
|
|
3834
4591
|
// src/diagram/hooks/useSelection.ts
|
|
3835
|
-
import { useState as
|
|
4592
|
+
import { useState as useState10, useCallback as useCallback4 } from "react";
|
|
3836
4593
|
function useSelection(options = {}) {
|
|
3837
4594
|
const {
|
|
3838
4595
|
multiSelect = true,
|
|
3839
4596
|
initialSelection = { selectedNodeIds: /* @__PURE__ */ new Set(), selectedPipeIds: /* @__PURE__ */ new Set() },
|
|
3840
4597
|
onSelectionChange
|
|
3841
4598
|
} = options;
|
|
3842
|
-
const [selection, setSelection] =
|
|
4599
|
+
const [selection, setSelection] = useState10(initialSelection);
|
|
3843
4600
|
const notifyChange = useCallback4(
|
|
3844
4601
|
(newSelection) => {
|
|
3845
4602
|
if (onSelectionChange) {
|
|
@@ -3937,14 +4694,14 @@ function useSelection(options = {}) {
|
|
|
3937
4694
|
}
|
|
3938
4695
|
|
|
3939
4696
|
// src/diagram/hooks/useTelemetry.ts
|
|
3940
|
-
import { useState as
|
|
4697
|
+
import { useState as useState11, useCallback as useCallback5, useEffect as useEffect7, useRef as useRef3 } from "react";
|
|
3941
4698
|
function useTelemetry(options = {}) {
|
|
3942
4699
|
const {
|
|
3943
4700
|
initialBindings = [],
|
|
3944
4701
|
onTelemetryChange,
|
|
3945
4702
|
refreshInterval = 0
|
|
3946
4703
|
} = options;
|
|
3947
|
-
const [telemetry, setTelemetry] =
|
|
4704
|
+
const [telemetry, setTelemetry] = useState11(() => {
|
|
3948
4705
|
const map = /* @__PURE__ */ new Map();
|
|
3949
4706
|
initialBindings.forEach((binding) => {
|
|
3950
4707
|
map.set(binding.nodeId, binding);
|
|
@@ -4065,7 +4822,7 @@ function useTelemetry(options = {}) {
|
|
|
4065
4822
|
},
|
|
4066
4823
|
[notifyChange]
|
|
4067
4824
|
);
|
|
4068
|
-
|
|
4825
|
+
useEffect7(() => {
|
|
4069
4826
|
if (refreshInterval <= 0) return;
|
|
4070
4827
|
const intervalId = setInterval(() => {
|
|
4071
4828
|
notifyChange(telemetryRef.current);
|
|
@@ -4083,10 +4840,10 @@ function useTelemetry(options = {}) {
|
|
|
4083
4840
|
}
|
|
4084
4841
|
|
|
4085
4842
|
// src/diagram/hooks/useTelemetryStatus.ts
|
|
4086
|
-
import { useEffect as
|
|
4843
|
+
import { useEffect as useEffect8 } from "react";
|
|
4087
4844
|
function useTelemetryStatus(telemetry, diagram, setDiagram, options = {}) {
|
|
4088
4845
|
const { enabled = true, mapStatus } = options;
|
|
4089
|
-
|
|
4846
|
+
useEffect8(() => {
|
|
4090
4847
|
if (!enabled) return;
|
|
4091
4848
|
const defaultMapStatus = (telemetryStatus) => {
|
|
4092
4849
|
switch (telemetryStatus) {
|
|
@@ -4125,7 +4882,7 @@ function useTelemetryStatus(telemetry, diagram, setDiagram, options = {}) {
|
|
|
4125
4882
|
}
|
|
4126
4883
|
|
|
4127
4884
|
// src/diagram/hooks/useDrag.ts
|
|
4128
|
-
import { useState as
|
|
4885
|
+
import { useState as useState12, useCallback as useCallback6, useRef as useRef4, useEffect as useEffect9 } from "react";
|
|
4129
4886
|
function useDrag(options = {}) {
|
|
4130
4887
|
const {
|
|
4131
4888
|
onDragStart,
|
|
@@ -4135,13 +4892,13 @@ function useDrag(options = {}) {
|
|
|
4135
4892
|
dragThreshold = 3,
|
|
4136
4893
|
screenToWorld = (x, y) => ({ x, y })
|
|
4137
4894
|
} = options;
|
|
4138
|
-
const [dragState, setDragState] =
|
|
4895
|
+
const [dragState, setDragState] = useState12({
|
|
4139
4896
|
isDragging: false,
|
|
4140
4897
|
startPosition: null,
|
|
4141
4898
|
offset: { x: 0, y: 0 },
|
|
4142
4899
|
draggedId: null
|
|
4143
4900
|
});
|
|
4144
|
-
const [isListening, setIsListening] =
|
|
4901
|
+
const [isListening, setIsListening] = useState12(false);
|
|
4145
4902
|
const dragStartRef = useRef4(null);
|
|
4146
4903
|
const hasMovedRef = useRef4(false);
|
|
4147
4904
|
const applySnap = useCallback6(
|
|
@@ -4310,7 +5067,7 @@ function useDrag(options = {}) {
|
|
|
4310
5067
|
},
|
|
4311
5068
|
[screenToWorld, applySnap, onDragEnd]
|
|
4312
5069
|
);
|
|
4313
|
-
|
|
5070
|
+
useEffect9(() => {
|
|
4314
5071
|
if (!isListening) return;
|
|
4315
5072
|
document.addEventListener("mousemove", handleMouseMove);
|
|
4316
5073
|
document.addEventListener("mouseup", handleMouseUp);
|
|
@@ -4379,7 +5136,7 @@ function useDrag(options = {}) {
|
|
|
4379
5136
|
}
|
|
4380
5137
|
|
|
4381
5138
|
// src/diagram/hooks/useKeyboardShortcuts.ts
|
|
4382
|
-
import { useEffect as
|
|
5139
|
+
import { useEffect as useEffect10 } from "react";
|
|
4383
5140
|
function useKeyboardShortcuts(options) {
|
|
4384
5141
|
const {
|
|
4385
5142
|
onDelete,
|
|
@@ -4390,7 +5147,7 @@ function useKeyboardShortcuts(options) {
|
|
|
4390
5147
|
onSelectAll,
|
|
4391
5148
|
enabled = true
|
|
4392
5149
|
} = options;
|
|
4393
|
-
|
|
5150
|
+
useEffect10(() => {
|
|
4394
5151
|
if (!enabled) return;
|
|
4395
5152
|
const handleKeyDown = (event) => {
|
|
4396
5153
|
const target = event.target;
|
|
@@ -4499,7 +5256,7 @@ function nodeHasPort(node, portId) {
|
|
|
4499
5256
|
}
|
|
4500
5257
|
|
|
4501
5258
|
// src/components/PIDCanvas/PIDCanvas.tsx
|
|
4502
|
-
import { Fragment as
|
|
5259
|
+
import { Fragment as Fragment7, jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
4503
5260
|
function PIDCanvas({
|
|
4504
5261
|
diagram,
|
|
4505
5262
|
className = "",
|
|
@@ -4526,21 +5283,21 @@ function PIDCanvas({
|
|
|
4526
5283
|
telemetry,
|
|
4527
5284
|
...props
|
|
4528
5285
|
}) {
|
|
4529
|
-
const [localDiagram, setLocalDiagram] =
|
|
4530
|
-
const [dragOverPosition, setDragOverPosition] =
|
|
4531
|
-
const [isConnecting, setIsConnecting] =
|
|
4532
|
-
const [connectionSource, setConnectionSource] =
|
|
4533
|
-
const [connectionSourcePort, setConnectionSourcePort] =
|
|
4534
|
-
const [connectionCursor, setConnectionCursor] =
|
|
4535
|
-
const [hoveredNode, setHoveredNode] =
|
|
4536
|
-
const [hoveredPort, setHoveredPort] =
|
|
4537
|
-
const [selectedWaypoint, setSelectedWaypoint] =
|
|
5286
|
+
const [localDiagram, setLocalDiagram] = useState13(diagram);
|
|
5287
|
+
const [dragOverPosition, setDragOverPosition] = useState13(null);
|
|
5288
|
+
const [isConnecting, setIsConnecting] = useState13(false);
|
|
5289
|
+
const [connectionSource, setConnectionSource] = useState13(null);
|
|
5290
|
+
const [connectionSourcePort, setConnectionSourcePort] = useState13(null);
|
|
5291
|
+
const [connectionCursor, setConnectionCursor] = useState13(null);
|
|
5292
|
+
const [hoveredNode, setHoveredNode] = useState13(null);
|
|
5293
|
+
const [hoveredPort, setHoveredPort] = useState13(null);
|
|
5294
|
+
const [selectedWaypoint, setSelectedWaypoint] = useState13(null);
|
|
4538
5295
|
const historyStack = useRef5([]);
|
|
4539
5296
|
const redoStack = useRef5([]);
|
|
4540
5297
|
const isUndoRedoAction = useRef5(false);
|
|
4541
5298
|
const isInternalChange = useRef5(false);
|
|
4542
5299
|
const lastInternalDiagram = useRef5(null);
|
|
4543
|
-
|
|
5300
|
+
useEffect11(() => {
|
|
4544
5301
|
const isExternal = !isInternalChange.current && diagram !== lastInternalDiagram.current;
|
|
4545
5302
|
if (isExternal) {
|
|
4546
5303
|
setLocalDiagram(diagram);
|
|
@@ -4585,7 +5342,7 @@ function PIDCanvas({
|
|
|
4585
5342
|
});
|
|
4586
5343
|
return { minX, minY, maxX, maxY };
|
|
4587
5344
|
}, [localDiagram.nodes]);
|
|
4588
|
-
|
|
5345
|
+
useEffect11(() => {
|
|
4589
5346
|
if (onMounted) {
|
|
4590
5347
|
const controls = {
|
|
4591
5348
|
fitToContent: (padding = 50) => {
|
|
@@ -4664,7 +5421,7 @@ function PIDCanvas({
|
|
|
4664
5421
|
isUndoRedoAction.current = false;
|
|
4665
5422
|
}, 0);
|
|
4666
5423
|
}, [localDiagram, onDiagramChange]);
|
|
4667
|
-
|
|
5424
|
+
useEffect11(() => {
|
|
4668
5425
|
const handleKeyDown = (e) => {
|
|
4669
5426
|
const isCtrlOrCmd = e.ctrlKey || e.metaKey;
|
|
4670
5427
|
if (isCtrlOrCmd && e.key === "z" && !e.shiftKey) {
|
|
@@ -4681,7 +5438,7 @@ function PIDCanvas({
|
|
|
4681
5438
|
window.addEventListener("keydown", handleKeyDown);
|
|
4682
5439
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
4683
5440
|
}, [undo, redo]);
|
|
4684
|
-
|
|
5441
|
+
useEffect11(() => {
|
|
4685
5442
|
if (!features.dragNodes) return;
|
|
4686
5443
|
const handleKeyDown = (e) => {
|
|
4687
5444
|
if (selection.selectedNodeIds.size === 0 && !selectedWaypoint) return;
|
|
@@ -5091,7 +5848,7 @@ function PIDCanvas({
|
|
|
5091
5848
|
const viewBox = controlledViewBox;
|
|
5092
5849
|
const displayDiagram = localDiagram;
|
|
5093
5850
|
const selectedNode = selectionEnabled && selection.selectedNodeIds.size === 1 ? localDiagram.nodes.find((n) => selection.selectedNodeIds.has(n.id)) || null : null;
|
|
5094
|
-
return /* @__PURE__ */
|
|
5851
|
+
return /* @__PURE__ */ jsxs15(
|
|
5095
5852
|
"div",
|
|
5096
5853
|
{
|
|
5097
5854
|
ref: containerRef,
|
|
@@ -5106,7 +5863,7 @@ function PIDCanvas({
|
|
|
5106
5863
|
},
|
|
5107
5864
|
...props,
|
|
5108
5865
|
children: [
|
|
5109
|
-
/* @__PURE__ */
|
|
5866
|
+
/* @__PURE__ */ jsxs15(
|
|
5110
5867
|
"svg",
|
|
5111
5868
|
{
|
|
5112
5869
|
ref: svgRef,
|
|
@@ -5125,15 +5882,15 @@ function PIDCanvas({
|
|
|
5125
5882
|
onDrop: handleDrop,
|
|
5126
5883
|
onDragLeave: handleDragLeave,
|
|
5127
5884
|
children: [
|
|
5128
|
-
features.showGrid !== false ? /* @__PURE__ */
|
|
5129
|
-
/* @__PURE__ */
|
|
5130
|
-
/* @__PURE__ */
|
|
5131
|
-
/* @__PURE__ */
|
|
5132
|
-
/* @__PURE__ */
|
|
5133
|
-
/* @__PURE__ */
|
|
5885
|
+
features.showGrid !== false ? /* @__PURE__ */ jsxs15(Fragment7, { children: [
|
|
5886
|
+
/* @__PURE__ */ jsxs15("defs", { children: [
|
|
5887
|
+
/* @__PURE__ */ jsx19("pattern", { id: "grid-minor", width: "5", height: "5", patternUnits: "userSpaceOnUse", children: /* @__PURE__ */ jsx19("path", { d: "M 5 0 L 0 0 0 5", fill: "none", stroke: "#e5e7eb", strokeWidth: "0.5" }) }),
|
|
5888
|
+
/* @__PURE__ */ jsxs15("pattern", { id: "grid-major", width: "25", height: "25", patternUnits: "userSpaceOnUse", children: [
|
|
5889
|
+
/* @__PURE__ */ jsx19("rect", { width: "25", height: "25", fill: "url(#grid-minor)" }),
|
|
5890
|
+
/* @__PURE__ */ jsx19("path", { d: "M 25 0 L 0 0 0 25", fill: "none", stroke: "#d1d5db", strokeWidth: "1" })
|
|
5134
5891
|
] })
|
|
5135
5892
|
] }),
|
|
5136
|
-
/* @__PURE__ */
|
|
5893
|
+
/* @__PURE__ */ jsx19(
|
|
5137
5894
|
"rect",
|
|
5138
5895
|
{
|
|
5139
5896
|
x: Math.floor(viewBox.x / 25) * 25 - viewBox.width,
|
|
@@ -5143,7 +5900,7 @@ function PIDCanvas({
|
|
|
5143
5900
|
fill: "url(#grid-major)"
|
|
5144
5901
|
}
|
|
5145
5902
|
)
|
|
5146
|
-
] }) : /* @__PURE__ */
|
|
5903
|
+
] }) : /* @__PURE__ */ jsx19(
|
|
5147
5904
|
"rect",
|
|
5148
5905
|
{
|
|
5149
5906
|
x: Math.floor(viewBox.x / 25) * 25 - viewBox.width,
|
|
@@ -5153,7 +5910,7 @@ function PIDCanvas({
|
|
|
5153
5910
|
fill: features.backgroundColor ?? "#ffffff"
|
|
5154
5911
|
}
|
|
5155
5912
|
),
|
|
5156
|
-
/* @__PURE__ */
|
|
5913
|
+
/* @__PURE__ */ jsx19(
|
|
5157
5914
|
PipeRenderer,
|
|
5158
5915
|
{
|
|
5159
5916
|
pipes: displayDiagram.pipes,
|
|
@@ -5167,12 +5924,12 @@ function PIDCanvas({
|
|
|
5167
5924
|
onPipeSegmentClick: void 0
|
|
5168
5925
|
}
|
|
5169
5926
|
),
|
|
5170
|
-
/* @__PURE__ */
|
|
5927
|
+
/* @__PURE__ */ jsx19(
|
|
5171
5928
|
NodeRenderer,
|
|
5172
5929
|
{
|
|
5173
5930
|
nodes: displayDiagram.nodes,
|
|
5174
5931
|
selectedNodeIds: selectionEnabled ? selection.selectedNodeIds : void 0,
|
|
5175
|
-
onNodeClick: selectionEnabled || features.connectionMode ? handleNodeClick : void 0,
|
|
5932
|
+
onNodeClick: onNodeClick ? handleNodeClick : selectionEnabled || features.connectionMode ? handleNodeClick : void 0,
|
|
5176
5933
|
onNodeDoubleClick: selectionEnabled ? handleNodeDoubleClick : void 0,
|
|
5177
5934
|
enableDrag: dragEnabled && !isConnecting,
|
|
5178
5935
|
onNodeDragStart: dragEnabled && !isConnecting ? handleNodeDragStart : void 0,
|
|
@@ -5180,7 +5937,7 @@ function PIDCanvas({
|
|
|
5180
5937
|
dragOffset: dragState.offset
|
|
5181
5938
|
}
|
|
5182
5939
|
),
|
|
5183
|
-
(features.editPipeRoutes ?? false) && /* @__PURE__ */
|
|
5940
|
+
(features.editPipeRoutes ?? false) && /* @__PURE__ */ jsx19(
|
|
5184
5941
|
PipeRenderer,
|
|
5185
5942
|
{
|
|
5186
5943
|
pipes: displayDiagram.pipes,
|
|
@@ -5197,14 +5954,14 @@ function PIDCanvas({
|
|
|
5197
5954
|
onPipeSegmentClick: handlePipeSegmentClick
|
|
5198
5955
|
}
|
|
5199
5956
|
),
|
|
5200
|
-
telemetryEnabled && telemetry && /* @__PURE__ */
|
|
5957
|
+
telemetryEnabled && telemetry && /* @__PURE__ */ jsx19("g", { id: "layer-telemetry", children: displayDiagram.nodes.map((node) => {
|
|
5201
5958
|
const binding = telemetry.get(node.id);
|
|
5202
5959
|
if (!binding) return null;
|
|
5203
5960
|
const symbol = getSymbolDefinition(node.symbolId);
|
|
5204
5961
|
if (!symbol) return null;
|
|
5205
5962
|
const overlayX = node.transform.x + symbol.viewBox.width / 2;
|
|
5206
5963
|
const overlayY = node.transform.y + symbol.viewBox.height + 50;
|
|
5207
|
-
return /* @__PURE__ */
|
|
5964
|
+
return /* @__PURE__ */ jsx19(
|
|
5208
5965
|
DataOverlay,
|
|
5209
5966
|
{
|
|
5210
5967
|
nodeId: node.id,
|
|
@@ -5216,7 +5973,7 @@ function PIDCanvas({
|
|
|
5216
5973
|
`telemetry-${node.id}`
|
|
5217
5974
|
);
|
|
5218
5975
|
}) }),
|
|
5219
|
-
dragOverPosition && /* @__PURE__ */
|
|
5976
|
+
dragOverPosition && /* @__PURE__ */ jsx19(
|
|
5220
5977
|
"circle",
|
|
5221
5978
|
{
|
|
5222
5979
|
cx: dragOverPosition.x,
|
|
@@ -5229,7 +5986,7 @@ function PIDCanvas({
|
|
|
5229
5986
|
pointerEvents: "none"
|
|
5230
5987
|
}
|
|
5231
5988
|
),
|
|
5232
|
-
isConnecting && connectionSource && connectionCursor && /* @__PURE__ */
|
|
5989
|
+
isConnecting && connectionSource && connectionCursor && /* @__PURE__ */ jsx19("g", { id: "connection-preview", pointerEvents: "none", children: (() => {
|
|
5233
5990
|
const sourceNode = displayDiagram.nodes.find((n) => n.id === connectionSource);
|
|
5234
5991
|
if (!sourceNode) return null;
|
|
5235
5992
|
const symbol = getSymbolDefinition(sourceNode.symbolId);
|
|
@@ -5245,8 +6002,8 @@ function PIDCanvas({
|
|
|
5245
6002
|
}
|
|
5246
6003
|
}
|
|
5247
6004
|
}
|
|
5248
|
-
return /* @__PURE__ */
|
|
5249
|
-
/* @__PURE__ */
|
|
6005
|
+
return /* @__PURE__ */ jsxs15(Fragment7, { children: [
|
|
6006
|
+
/* @__PURE__ */ jsx19(
|
|
5250
6007
|
"circle",
|
|
5251
6008
|
{
|
|
5252
6009
|
cx: lineStartX,
|
|
@@ -5258,7 +6015,7 @@ function PIDCanvas({
|
|
|
5258
6015
|
opacity: 0.6
|
|
5259
6016
|
}
|
|
5260
6017
|
),
|
|
5261
|
-
/* @__PURE__ */
|
|
6018
|
+
/* @__PURE__ */ jsx19(
|
|
5262
6019
|
"line",
|
|
5263
6020
|
{
|
|
5264
6021
|
x1: lineStartX,
|
|
@@ -5271,7 +6028,7 @@ function PIDCanvas({
|
|
|
5271
6028
|
opacity: 0.8
|
|
5272
6029
|
}
|
|
5273
6030
|
),
|
|
5274
|
-
/* @__PURE__ */
|
|
6031
|
+
/* @__PURE__ */ jsx19(
|
|
5275
6032
|
"circle",
|
|
5276
6033
|
{
|
|
5277
6034
|
cx: connectionCursor.x,
|
|
@@ -5283,7 +6040,7 @@ function PIDCanvas({
|
|
|
5283
6040
|
)
|
|
5284
6041
|
] });
|
|
5285
6042
|
})() }),
|
|
5286
|
-
features.connectionMode && /* @__PURE__ */
|
|
6043
|
+
features.connectionMode && /* @__PURE__ */ jsx19("g", { id: "port-indicators", children: displayDiagram.nodes.map((node) => {
|
|
5287
6044
|
const symbol = getSymbolDefinition(node.symbolId);
|
|
5288
6045
|
if (!symbol?.ports) return null;
|
|
5289
6046
|
return symbol.ports.map((port) => {
|
|
@@ -5291,8 +6048,8 @@ function PIDCanvas({
|
|
|
5291
6048
|
if (!portPos) return null;
|
|
5292
6049
|
const isHovered = hoveredPort === port.id && hoveredNode === node.id;
|
|
5293
6050
|
const isSourcePort = node.id === connectionSource && port.id === connectionSourcePort;
|
|
5294
|
-
return /* @__PURE__ */
|
|
5295
|
-
/* @__PURE__ */
|
|
6051
|
+
return /* @__PURE__ */ jsxs15("g", { children: [
|
|
6052
|
+
/* @__PURE__ */ jsx19(
|
|
5296
6053
|
"circle",
|
|
5297
6054
|
{
|
|
5298
6055
|
cx: portPos.x,
|
|
@@ -5325,7 +6082,7 @@ function PIDCanvas({
|
|
|
5325
6082
|
}
|
|
5326
6083
|
}
|
|
5327
6084
|
),
|
|
5328
|
-
/* @__PURE__ */
|
|
6085
|
+
/* @__PURE__ */ jsx19(
|
|
5329
6086
|
"circle",
|
|
5330
6087
|
{
|
|
5331
6088
|
cx: portPos.x,
|
|
@@ -5344,7 +6101,7 @@ function PIDCanvas({
|
|
|
5344
6101
|
]
|
|
5345
6102
|
}
|
|
5346
6103
|
),
|
|
5347
|
-
features.dragNodes && /* @__PURE__ */
|
|
6104
|
+
features.dragNodes && /* @__PURE__ */ jsx19(
|
|
5348
6105
|
PositionPanel,
|
|
5349
6106
|
{
|
|
5350
6107
|
selectedNode,
|
|
@@ -5364,16 +6121,16 @@ function PIDCanvas({
|
|
|
5364
6121
|
}
|
|
5365
6122
|
|
|
5366
6123
|
// src/components/SymbolLibrary/SymbolLibrary.tsx
|
|
5367
|
-
import { useState as
|
|
5368
|
-
import { jsx as
|
|
6124
|
+
import { useState as useState14 } from "react";
|
|
6125
|
+
import { jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
5369
6126
|
function SymbolLibrary({
|
|
5370
6127
|
className = "",
|
|
5371
6128
|
onSymbolDragStart,
|
|
5372
6129
|
showCategories = true,
|
|
5373
6130
|
categories = ["Valves", "Pumps", "Tanks", "Instruments", "Displays"]
|
|
5374
6131
|
}) {
|
|
5375
|
-
const [selectedCategory, setSelectedCategory] =
|
|
5376
|
-
const [searchQuery, setSearchQuery] =
|
|
6132
|
+
const [selectedCategory, setSelectedCategory] = useState14("all");
|
|
6133
|
+
const [searchQuery, setSearchQuery] = useState14("");
|
|
5377
6134
|
const symbolIds = getAvailableSymbols();
|
|
5378
6135
|
const allSymbols = symbolIds.map((id) => getSymbolDefinition(id)).filter((symbol) => symbol !== void 0);
|
|
5379
6136
|
const categoryMap = {
|
|
@@ -5394,9 +6151,9 @@ function SymbolLibrary({
|
|
|
5394
6151
|
event.dataTransfer.effectAllowed = "copy";
|
|
5395
6152
|
onSymbolDragStart?.(symbol.id, event);
|
|
5396
6153
|
};
|
|
5397
|
-
return /* @__PURE__ */
|
|
5398
|
-
/* @__PURE__ */
|
|
5399
|
-
/* @__PURE__ */
|
|
6154
|
+
return /* @__PURE__ */ jsxs16("div", { className: `symbol-library ${className}`.trim(), style: styles.container, children: [
|
|
6155
|
+
/* @__PURE__ */ jsx20("div", { style: styles.header, children: /* @__PURE__ */ jsx20("h3", { style: styles.title, children: "Symbol Library" }) }),
|
|
6156
|
+
/* @__PURE__ */ jsx20("div", { style: styles.searchContainer, children: /* @__PURE__ */ jsx20(
|
|
5400
6157
|
"input",
|
|
5401
6158
|
{
|
|
5402
6159
|
type: "text",
|
|
@@ -5406,8 +6163,8 @@ function SymbolLibrary({
|
|
|
5406
6163
|
style: styles.searchInput
|
|
5407
6164
|
}
|
|
5408
6165
|
) }),
|
|
5409
|
-
showCategories && /* @__PURE__ */
|
|
5410
|
-
/* @__PURE__ */
|
|
6166
|
+
showCategories && /* @__PURE__ */ jsxs16("div", { style: styles.categories, children: [
|
|
6167
|
+
/* @__PURE__ */ jsx20(
|
|
5411
6168
|
"button",
|
|
5412
6169
|
{
|
|
5413
6170
|
onClick: () => setSelectedCategory("all"),
|
|
@@ -5418,7 +6175,7 @@ function SymbolLibrary({
|
|
|
5418
6175
|
children: "All"
|
|
5419
6176
|
}
|
|
5420
6177
|
),
|
|
5421
|
-
categories.map((category) => /* @__PURE__ */
|
|
6178
|
+
categories.map((category) => /* @__PURE__ */ jsx20(
|
|
5422
6179
|
"button",
|
|
5423
6180
|
{
|
|
5424
6181
|
onClick: () => setSelectedCategory(category),
|
|
@@ -5431,7 +6188,7 @@ function SymbolLibrary({
|
|
|
5431
6188
|
category
|
|
5432
6189
|
))
|
|
5433
6190
|
] }),
|
|
5434
|
-
/* @__PURE__ */
|
|
6191
|
+
/* @__PURE__ */ jsx20("div", { style: styles.symbolGrid, children: filteredSymbols.length === 0 ? /* @__PURE__ */ jsx20("div", { style: styles.emptyState, children: "No symbols found" }) : filteredSymbols.map((symbol) => /* @__PURE__ */ jsxs16(
|
|
5435
6192
|
"div",
|
|
5436
6193
|
{
|
|
5437
6194
|
draggable: true,
|
|
@@ -5439,15 +6196,15 @@ function SymbolLibrary({
|
|
|
5439
6196
|
style: styles.symbolCard,
|
|
5440
6197
|
title: symbol.metadata?.description || symbol.name,
|
|
5441
6198
|
children: [
|
|
5442
|
-
/* @__PURE__ */
|
|
6199
|
+
/* @__PURE__ */ jsx20("div", { style: styles.symbolPreview, children: /* @__PURE__ */ jsx20(
|
|
5443
6200
|
"svg",
|
|
5444
6201
|
{
|
|
5445
6202
|
viewBox: `${symbol.viewBox.x} ${symbol.viewBox.y} ${symbol.viewBox.width} ${symbol.viewBox.height}`,
|
|
5446
6203
|
style: styles.symbolSvg,
|
|
5447
|
-
children: /* @__PURE__ */
|
|
6204
|
+
children: /* @__PURE__ */ jsx20("g", { dangerouslySetInnerHTML: { __html: symbol.svgContent } })
|
|
5448
6205
|
}
|
|
5449
6206
|
) }),
|
|
5450
|
-
/* @__PURE__ */
|
|
6207
|
+
/* @__PURE__ */ jsx20("div", { style: styles.symbolName, children: symbol.name })
|
|
5451
6208
|
]
|
|
5452
6209
|
},
|
|
5453
6210
|
symbol.id
|
|
@@ -5556,7 +6313,7 @@ var styles = {
|
|
|
5556
6313
|
};
|
|
5557
6314
|
|
|
5558
6315
|
// src/components/NodeConfigPanel/NodeConfigPanel.tsx
|
|
5559
|
-
import { Fragment as
|
|
6316
|
+
import { Fragment as Fragment8, jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
5560
6317
|
function NodeConfigPanel({
|
|
5561
6318
|
node,
|
|
5562
6319
|
binding,
|
|
@@ -5575,15 +6332,15 @@ function NodeConfigPanel({
|
|
|
5575
6332
|
padding: "20px",
|
|
5576
6333
|
...style
|
|
5577
6334
|
};
|
|
5578
|
-
return /* @__PURE__ */
|
|
5579
|
-
/* @__PURE__ */
|
|
6335
|
+
return /* @__PURE__ */ jsxs17("div", { className, style: defaultStyle, children: [
|
|
6336
|
+
/* @__PURE__ */ jsxs17("h2", { style: { margin: "0 0 16px 0", fontSize: "1rem", fontWeight: 600 }, children: [
|
|
5580
6337
|
"Configure: ",
|
|
5581
6338
|
node.id
|
|
5582
6339
|
] }),
|
|
5583
|
-
/* @__PURE__ */
|
|
5584
|
-
/* @__PURE__ */
|
|
5585
|
-
/* @__PURE__ */
|
|
5586
|
-
/* @__PURE__ */
|
|
6340
|
+
/* @__PURE__ */ jsxs17("div", { style: { marginBottom: "20px" }, children: [
|
|
6341
|
+
/* @__PURE__ */ jsx21("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Node Settings" }),
|
|
6342
|
+
/* @__PURE__ */ jsx21("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label:" }),
|
|
6343
|
+
/* @__PURE__ */ jsx21(
|
|
5587
6344
|
"input",
|
|
5588
6345
|
{
|
|
5589
6346
|
type: "text",
|
|
@@ -5599,10 +6356,10 @@ function NodeConfigPanel({
|
|
|
5599
6356
|
}
|
|
5600
6357
|
}
|
|
5601
6358
|
),
|
|
5602
|
-
/* @__PURE__ */
|
|
5603
|
-
/* @__PURE__ */
|
|
5604
|
-
/* @__PURE__ */
|
|
5605
|
-
/* @__PURE__ */
|
|
6359
|
+
/* @__PURE__ */ jsxs17("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "8px" }, children: [
|
|
6360
|
+
/* @__PURE__ */ jsxs17("div", { children: [
|
|
6361
|
+
/* @__PURE__ */ jsx21("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label Offset X:" }),
|
|
6362
|
+
/* @__PURE__ */ jsx21(
|
|
5606
6363
|
"input",
|
|
5607
6364
|
{
|
|
5608
6365
|
type: "number",
|
|
@@ -5623,9 +6380,9 @@ function NodeConfigPanel({
|
|
|
5623
6380
|
}
|
|
5624
6381
|
)
|
|
5625
6382
|
] }),
|
|
5626
|
-
/* @__PURE__ */
|
|
5627
|
-
/* @__PURE__ */
|
|
5628
|
-
/* @__PURE__ */
|
|
6383
|
+
/* @__PURE__ */ jsxs17("div", { children: [
|
|
6384
|
+
/* @__PURE__ */ jsx21("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label Offset Y:" }),
|
|
6385
|
+
/* @__PURE__ */ jsx21(
|
|
5629
6386
|
"input",
|
|
5630
6387
|
{
|
|
5631
6388
|
type: "number",
|
|
@@ -5647,9 +6404,9 @@ function NodeConfigPanel({
|
|
|
5647
6404
|
)
|
|
5648
6405
|
] })
|
|
5649
6406
|
] }),
|
|
5650
|
-
/* @__PURE__ */
|
|
5651
|
-
/* @__PURE__ */
|
|
5652
|
-
/* @__PURE__ */
|
|
6407
|
+
/* @__PURE__ */ jsxs17("div", { children: [
|
|
6408
|
+
/* @__PURE__ */ jsx21("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Label Font Size:" }),
|
|
6409
|
+
/* @__PURE__ */ jsx21(
|
|
5653
6410
|
"input",
|
|
5654
6411
|
{
|
|
5655
6412
|
type: "number",
|
|
@@ -5669,9 +6426,9 @@ function NodeConfigPanel({
|
|
|
5669
6426
|
}
|
|
5670
6427
|
)
|
|
5671
6428
|
] }),
|
|
5672
|
-
/* @__PURE__ */
|
|
5673
|
-
/* @__PURE__ */
|
|
5674
|
-
/* @__PURE__ */
|
|
6429
|
+
/* @__PURE__ */ jsxs17("div", { children: [
|
|
6430
|
+
/* @__PURE__ */ jsx21("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Rotation (degrees):" }),
|
|
6431
|
+
/* @__PURE__ */ jsx21(
|
|
5675
6432
|
"input",
|
|
5676
6433
|
{
|
|
5677
6434
|
type: "number",
|
|
@@ -5696,9 +6453,9 @@ function NodeConfigPanel({
|
|
|
5696
6453
|
)
|
|
5697
6454
|
] })
|
|
5698
6455
|
] }),
|
|
5699
|
-
/* @__PURE__ */
|
|
5700
|
-
/* @__PURE__ */
|
|
5701
|
-
!binding ? /* @__PURE__ */
|
|
6456
|
+
/* @__PURE__ */ jsxs17("div", { style: { marginBottom: "20px" }, children: [
|
|
6457
|
+
/* @__PURE__ */ jsx21("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Telemetry Data" }),
|
|
6458
|
+
!binding ? /* @__PURE__ */ jsx21(
|
|
5702
6459
|
"button",
|
|
5703
6460
|
{
|
|
5704
6461
|
onClick: () => {
|
|
@@ -5741,9 +6498,9 @@ function NodeConfigPanel({
|
|
|
5741
6498
|
},
|
|
5742
6499
|
children: "+ Add Telemetry"
|
|
5743
6500
|
}
|
|
5744
|
-
) : /* @__PURE__ */
|
|
5745
|
-
/* @__PURE__ */
|
|
5746
|
-
/* @__PURE__ */
|
|
6501
|
+
) : /* @__PURE__ */ jsxs17(Fragment8, { children: [
|
|
6502
|
+
/* @__PURE__ */ jsx21("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Initial Value:" }),
|
|
6503
|
+
/* @__PURE__ */ jsx21(
|
|
5747
6504
|
"input",
|
|
5748
6505
|
{
|
|
5749
6506
|
type: "number",
|
|
@@ -5765,8 +6522,8 @@ function NodeConfigPanel({
|
|
|
5765
6522
|
}
|
|
5766
6523
|
}
|
|
5767
6524
|
),
|
|
5768
|
-
/* @__PURE__ */
|
|
5769
|
-
/* @__PURE__ */
|
|
6525
|
+
/* @__PURE__ */ jsx21("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: "Unit:" }),
|
|
6526
|
+
/* @__PURE__ */ jsx21(
|
|
5770
6527
|
"input",
|
|
5771
6528
|
{
|
|
5772
6529
|
type: "text",
|
|
@@ -5788,8 +6545,8 @@ function NodeConfigPanel({
|
|
|
5788
6545
|
}
|
|
5789
6546
|
}
|
|
5790
6547
|
),
|
|
5791
|
-
/* @__PURE__ */
|
|
5792
|
-
/* @__PURE__ */
|
|
6548
|
+
/* @__PURE__ */ jsxs17("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
|
|
6549
|
+
/* @__PURE__ */ jsx21(
|
|
5793
6550
|
"input",
|
|
5794
6551
|
{
|
|
5795
6552
|
type: "checkbox",
|
|
@@ -5811,8 +6568,8 @@ function NodeConfigPanel({
|
|
|
5811
6568
|
),
|
|
5812
6569
|
"Show Sparkline"
|
|
5813
6570
|
] }),
|
|
5814
|
-
/* @__PURE__ */
|
|
5815
|
-
/* @__PURE__ */
|
|
6571
|
+
/* @__PURE__ */ jsxs17("div", { style: { marginTop: "12px" }, children: [
|
|
6572
|
+
/* @__PURE__ */ jsx21(
|
|
5816
6573
|
"label",
|
|
5817
6574
|
{
|
|
5818
6575
|
style: {
|
|
@@ -5824,10 +6581,10 @@ function NodeConfigPanel({
|
|
|
5824
6581
|
children: "Telemetry Position Offset:"
|
|
5825
6582
|
}
|
|
5826
6583
|
),
|
|
5827
|
-
/* @__PURE__ */
|
|
5828
|
-
/* @__PURE__ */
|
|
5829
|
-
/* @__PURE__ */
|
|
5830
|
-
/* @__PURE__ */
|
|
6584
|
+
/* @__PURE__ */ jsxs17("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "8px" }, children: [
|
|
6585
|
+
/* @__PURE__ */ jsxs17("div", { children: [
|
|
6586
|
+
/* @__PURE__ */ jsx21("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "X Offset:" }),
|
|
6587
|
+
/* @__PURE__ */ jsx21(
|
|
5831
6588
|
"input",
|
|
5832
6589
|
{
|
|
5833
6590
|
type: "number",
|
|
@@ -5854,9 +6611,9 @@ function NodeConfigPanel({
|
|
|
5854
6611
|
}
|
|
5855
6612
|
)
|
|
5856
6613
|
] }),
|
|
5857
|
-
/* @__PURE__ */
|
|
5858
|
-
/* @__PURE__ */
|
|
5859
|
-
/* @__PURE__ */
|
|
6614
|
+
/* @__PURE__ */ jsxs17("div", { children: [
|
|
6615
|
+
/* @__PURE__ */ jsx21("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Y Offset:" }),
|
|
6616
|
+
/* @__PURE__ */ jsx21(
|
|
5860
6617
|
"input",
|
|
5861
6618
|
{
|
|
5862
6619
|
type: "number",
|
|
@@ -5884,8 +6641,8 @@ function NodeConfigPanel({
|
|
|
5884
6641
|
)
|
|
5885
6642
|
] })
|
|
5886
6643
|
] }),
|
|
5887
|
-
/* @__PURE__ */
|
|
5888
|
-
/* @__PURE__ */
|
|
6644
|
+
/* @__PURE__ */ jsxs17("div", { style: { marginTop: "16px" }, children: [
|
|
6645
|
+
/* @__PURE__ */ jsx21(
|
|
5889
6646
|
"label",
|
|
5890
6647
|
{
|
|
5891
6648
|
style: {
|
|
@@ -5897,10 +6654,10 @@ function NodeConfigPanel({
|
|
|
5897
6654
|
children: "Display Colors:"
|
|
5898
6655
|
}
|
|
5899
6656
|
),
|
|
5900
|
-
/* @__PURE__ */
|
|
5901
|
-
/* @__PURE__ */
|
|
5902
|
-
/* @__PURE__ */
|
|
5903
|
-
/* @__PURE__ */
|
|
6657
|
+
/* @__PURE__ */ jsxs17("div", { style: { marginBottom: "8px" }, children: [
|
|
6658
|
+
/* @__PURE__ */ jsx21("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Text Color:" }),
|
|
6659
|
+
/* @__PURE__ */ jsxs17("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
|
|
6660
|
+
/* @__PURE__ */ jsx21(
|
|
5904
6661
|
"input",
|
|
5905
6662
|
{
|
|
5906
6663
|
type: "color",
|
|
@@ -5926,7 +6683,7 @@ function NodeConfigPanel({
|
|
|
5926
6683
|
}
|
|
5927
6684
|
}
|
|
5928
6685
|
),
|
|
5929
|
-
/* @__PURE__ */
|
|
6686
|
+
/* @__PURE__ */ jsx21(
|
|
5930
6687
|
"input",
|
|
5931
6688
|
{
|
|
5932
6689
|
type: "text",
|
|
@@ -5956,10 +6713,10 @@ function NodeConfigPanel({
|
|
|
5956
6713
|
)
|
|
5957
6714
|
] })
|
|
5958
6715
|
] }),
|
|
5959
|
-
binding.display?.showSparkline && /* @__PURE__ */
|
|
5960
|
-
/* @__PURE__ */
|
|
5961
|
-
/* @__PURE__ */
|
|
5962
|
-
/* @__PURE__ */
|
|
6716
|
+
binding.display?.showSparkline && /* @__PURE__ */ jsxs17("div", { style: { marginBottom: "8px" }, children: [
|
|
6717
|
+
/* @__PURE__ */ jsx21("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Sparkline Color:" }),
|
|
6718
|
+
/* @__PURE__ */ jsxs17("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
|
|
6719
|
+
/* @__PURE__ */ jsx21(
|
|
5963
6720
|
"input",
|
|
5964
6721
|
{
|
|
5965
6722
|
type: "color",
|
|
@@ -5985,7 +6742,7 @@ function NodeConfigPanel({
|
|
|
5985
6742
|
}
|
|
5986
6743
|
}
|
|
5987
6744
|
),
|
|
5988
|
-
/* @__PURE__ */
|
|
6745
|
+
/* @__PURE__ */ jsx21(
|
|
5989
6746
|
"input",
|
|
5990
6747
|
{
|
|
5991
6748
|
type: "text",
|
|
@@ -6015,9 +6772,9 @@ function NodeConfigPanel({
|
|
|
6015
6772
|
)
|
|
6016
6773
|
] })
|
|
6017
6774
|
] }),
|
|
6018
|
-
/* @__PURE__ */
|
|
6019
|
-
/* @__PURE__ */
|
|
6020
|
-
/* @__PURE__ */
|
|
6775
|
+
/* @__PURE__ */ jsxs17("div", { style: { marginBottom: "8px" }, children: [
|
|
6776
|
+
/* @__PURE__ */ jsx21("label", { style: { fontSize: "0.7rem", display: "block", marginBottom: "4px" }, children: "Background:" }),
|
|
6777
|
+
/* @__PURE__ */ jsx21(
|
|
6021
6778
|
"input",
|
|
6022
6779
|
{
|
|
6023
6780
|
type: "text",
|
|
@@ -6045,20 +6802,20 @@ function NodeConfigPanel({
|
|
|
6045
6802
|
}
|
|
6046
6803
|
}
|
|
6047
6804
|
),
|
|
6048
|
-
/* @__PURE__ */
|
|
6805
|
+
/* @__PURE__ */ jsx21("div", { style: { fontSize: "0.65rem", color: "#6b7280", marginTop: "2px" }, children: "Use 'status' for status-based color or hex code" })
|
|
6049
6806
|
] })
|
|
6050
6807
|
] }),
|
|
6051
6808
|
" "
|
|
6052
6809
|
] })
|
|
6053
6810
|
] })
|
|
6054
6811
|
] }),
|
|
6055
|
-
binding && /* @__PURE__ */
|
|
6056
|
-
/* @__PURE__ */
|
|
6812
|
+
binding && /* @__PURE__ */ jsxs17("div", { style: { marginBottom: "20px" }, children: [
|
|
6813
|
+
/* @__PURE__ */ jsx21("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Thresholds" }),
|
|
6057
6814
|
["highHigh", "high", "low", "lowLow"].map((key) => {
|
|
6058
6815
|
const label = key === "highHigh" ? "High-High (\u2265)" : key === "high" ? "High (\u2265)" : key === "low" ? "Low (\u2264)" : "Low-Low (\u2264)";
|
|
6059
|
-
return /* @__PURE__ */
|
|
6060
|
-
/* @__PURE__ */
|
|
6061
|
-
/* @__PURE__ */
|
|
6816
|
+
return /* @__PURE__ */ jsxs17("div", { style: { marginBottom: "8px" }, children: [
|
|
6817
|
+
/* @__PURE__ */ jsx21("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: label }),
|
|
6818
|
+
/* @__PURE__ */ jsx21(
|
|
6062
6819
|
"input",
|
|
6063
6820
|
{
|
|
6064
6821
|
type: "number",
|
|
@@ -6082,8 +6839,8 @@ function NodeConfigPanel({
|
|
|
6082
6839
|
] }, key);
|
|
6083
6840
|
})
|
|
6084
6841
|
] }),
|
|
6085
|
-
binding && /* @__PURE__ */
|
|
6086
|
-
/* @__PURE__ */
|
|
6842
|
+
binding && /* @__PURE__ */ jsxs17("div", { style: { marginBottom: "20px" }, children: [
|
|
6843
|
+
/* @__PURE__ */ jsx21("h3", { style: { fontSize: "0.875rem", fontWeight: 600, marginBottom: "8px" }, children: "Status Colors" }),
|
|
6087
6844
|
["normal", "warning", "alarm", "fault", "off"].map((status) => {
|
|
6088
6845
|
const defaultColors = {
|
|
6089
6846
|
normal: "#10b981",
|
|
@@ -6093,13 +6850,13 @@ function NodeConfigPanel({
|
|
|
6093
6850
|
off: "#6b7280"
|
|
6094
6851
|
};
|
|
6095
6852
|
const label = status === "normal" ? "Normal" : status === "warning" ? "Warning" : status === "alarm" ? "Alarm" : status === "fault" ? "Fault" : "Off";
|
|
6096
|
-
return /* @__PURE__ */
|
|
6097
|
-
/* @__PURE__ */
|
|
6853
|
+
return /* @__PURE__ */ jsxs17("div", { style: { marginBottom: "8px" }, children: [
|
|
6854
|
+
/* @__PURE__ */ jsxs17("label", { style: { fontSize: "0.75rem", display: "block", marginBottom: "4px" }, children: [
|
|
6098
6855
|
label,
|
|
6099
6856
|
":"
|
|
6100
6857
|
] }),
|
|
6101
|
-
/* @__PURE__ */
|
|
6102
|
-
/* @__PURE__ */
|
|
6858
|
+
/* @__PURE__ */ jsxs17("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
|
|
6859
|
+
/* @__PURE__ */ jsx21(
|
|
6103
6860
|
"input",
|
|
6104
6861
|
{
|
|
6105
6862
|
type: "color",
|
|
@@ -6120,7 +6877,7 @@ function NodeConfigPanel({
|
|
|
6120
6877
|
}
|
|
6121
6878
|
}
|
|
6122
6879
|
),
|
|
6123
|
-
/* @__PURE__ */
|
|
6880
|
+
/* @__PURE__ */ jsx21(
|
|
6124
6881
|
"input",
|
|
6125
6882
|
{
|
|
6126
6883
|
type: "text",
|
|
@@ -6147,7 +6904,7 @@ function NodeConfigPanel({
|
|
|
6147
6904
|
] }, status);
|
|
6148
6905
|
})
|
|
6149
6906
|
] }),
|
|
6150
|
-
/* @__PURE__ */
|
|
6907
|
+
/* @__PURE__ */ jsx21("div", { style: { marginTop: "20px", paddingTop: "20px", borderTop: "1px solid #cbd5e1" }, children: /* @__PURE__ */ jsx21(
|
|
6151
6908
|
"button",
|
|
6152
6909
|
{
|
|
6153
6910
|
onClick: onRemove,
|
|
@@ -6386,8 +7143,280 @@ var DEFAULT_THRESHOLDS = {
|
|
|
6386
7143
|
lowLow: 15
|
|
6387
7144
|
};
|
|
6388
7145
|
|
|
7146
|
+
// src/diagram/schema/DeviceControlBinding.ts
|
|
7147
|
+
function createControlBinding(nodeId, deviceConfig, actions) {
|
|
7148
|
+
const parametersByMode = {};
|
|
7149
|
+
deviceConfig.parameters.forEach((param) => {
|
|
7150
|
+
const modes = param.modes || deviceConfig.modes.map((m) => m.value);
|
|
7151
|
+
modes.forEach((mode) => {
|
|
7152
|
+
if (!parametersByMode[mode]) {
|
|
7153
|
+
parametersByMode[mode] = [];
|
|
7154
|
+
}
|
|
7155
|
+
parametersByMode[mode].push({
|
|
7156
|
+
id: param.id,
|
|
7157
|
+
label: param.label,
|
|
7158
|
+
unit: param.unit,
|
|
7159
|
+
min: param.min,
|
|
7160
|
+
max: param.max,
|
|
7161
|
+
value: param.value,
|
|
7162
|
+
type: typeof param.value === "number" ? "number" : "string"
|
|
7163
|
+
});
|
|
7164
|
+
});
|
|
7165
|
+
});
|
|
7166
|
+
return {
|
|
7167
|
+
nodeId,
|
|
7168
|
+
tag: deviceConfig.tag,
|
|
7169
|
+
deviceName: deviceConfig.name,
|
|
7170
|
+
deviceType: deviceConfig.type,
|
|
7171
|
+
modes: deviceConfig.modes,
|
|
7172
|
+
state: {
|
|
7173
|
+
currentMode: deviceConfig.currentMode,
|
|
7174
|
+
isRunning: deviceConfig.isRunning,
|
|
7175
|
+
status: deviceConfig.status
|
|
7176
|
+
},
|
|
7177
|
+
parameters: parametersByMode,
|
|
7178
|
+
capabilities: deviceConfig.capabilities,
|
|
7179
|
+
actions
|
|
7180
|
+
};
|
|
7181
|
+
}
|
|
7182
|
+
|
|
7183
|
+
// src/hooks/useDeviceControls.ts
|
|
7184
|
+
import { useState as useState15, useCallback as useCallback8 } from "react";
|
|
7185
|
+
function useDeviceControls(initialBindings) {
|
|
7186
|
+
const [controls, setControls] = useState15(() => {
|
|
7187
|
+
const map = /* @__PURE__ */ new Map();
|
|
7188
|
+
if (initialBindings) {
|
|
7189
|
+
initialBindings.forEach((binding) => {
|
|
7190
|
+
map.set(binding.nodeId, binding);
|
|
7191
|
+
});
|
|
7192
|
+
}
|
|
7193
|
+
return map;
|
|
7194
|
+
});
|
|
7195
|
+
const updateControl = useCallback8((nodeId, updates) => {
|
|
7196
|
+
setControls((prev) => {
|
|
7197
|
+
const newMap = new Map(prev);
|
|
7198
|
+
const existing = newMap.get(nodeId);
|
|
7199
|
+
if (existing) {
|
|
7200
|
+
newMap.set(nodeId, { ...existing, ...updates });
|
|
7201
|
+
} else {
|
|
7202
|
+
if ("tag" in updates && "modes" in updates && "state" in updates && "parameters" in updates && "actions" in updates) {
|
|
7203
|
+
newMap.set(nodeId, { nodeId, ...updates });
|
|
7204
|
+
}
|
|
7205
|
+
}
|
|
7206
|
+
return newMap;
|
|
7207
|
+
});
|
|
7208
|
+
}, []);
|
|
7209
|
+
const updateControlBatch = useCallback8((updates) => {
|
|
7210
|
+
setControls((prev) => {
|
|
7211
|
+
const newMap = new Map(prev);
|
|
7212
|
+
Object.entries(updates).forEach(([nodeId, update]) => {
|
|
7213
|
+
const existing = newMap.get(nodeId);
|
|
7214
|
+
if (existing) {
|
|
7215
|
+
newMap.set(nodeId, { ...existing, ...update });
|
|
7216
|
+
}
|
|
7217
|
+
});
|
|
7218
|
+
return newMap;
|
|
7219
|
+
});
|
|
7220
|
+
}, []);
|
|
7221
|
+
const updateDeviceState = useCallback8(
|
|
7222
|
+
(nodeId, stateUpdates) => {
|
|
7223
|
+
setControls((prev) => {
|
|
7224
|
+
const newMap = new Map(prev);
|
|
7225
|
+
const existing = newMap.get(nodeId);
|
|
7226
|
+
if (existing) {
|
|
7227
|
+
newMap.set(nodeId, {
|
|
7228
|
+
...existing,
|
|
7229
|
+
state: { ...existing.state, ...stateUpdates }
|
|
7230
|
+
});
|
|
7231
|
+
}
|
|
7232
|
+
return newMap;
|
|
7233
|
+
});
|
|
7234
|
+
},
|
|
7235
|
+
[]
|
|
7236
|
+
);
|
|
7237
|
+
const updateParameter = useCallback8(
|
|
7238
|
+
(nodeId, parameterId, value) => {
|
|
7239
|
+
setControls((prev) => {
|
|
7240
|
+
const newMap = new Map(prev);
|
|
7241
|
+
const existing = newMap.get(nodeId);
|
|
7242
|
+
if (existing) {
|
|
7243
|
+
const updatedParameters = { ...existing.parameters };
|
|
7244
|
+
Object.keys(updatedParameters).forEach((mode) => {
|
|
7245
|
+
const paramIndex = updatedParameters[mode].findIndex((p) => p.id === parameterId);
|
|
7246
|
+
if (paramIndex !== -1) {
|
|
7247
|
+
updatedParameters[mode] = [...updatedParameters[mode]];
|
|
7248
|
+
updatedParameters[mode][paramIndex] = {
|
|
7249
|
+
...updatedParameters[mode][paramIndex],
|
|
7250
|
+
value
|
|
7251
|
+
};
|
|
7252
|
+
}
|
|
7253
|
+
});
|
|
7254
|
+
newMap.set(nodeId, {
|
|
7255
|
+
...existing,
|
|
7256
|
+
parameters: updatedParameters
|
|
7257
|
+
});
|
|
7258
|
+
}
|
|
7259
|
+
return newMap;
|
|
7260
|
+
});
|
|
7261
|
+
},
|
|
7262
|
+
[]
|
|
7263
|
+
);
|
|
7264
|
+
const setControlBinding = useCallback8((binding) => {
|
|
7265
|
+
setControls((prev) => {
|
|
7266
|
+
const newMap = new Map(prev);
|
|
7267
|
+
newMap.set(binding.nodeId, binding);
|
|
7268
|
+
return newMap;
|
|
7269
|
+
});
|
|
7270
|
+
}, []);
|
|
7271
|
+
const removeControlBinding = useCallback8((nodeId) => {
|
|
7272
|
+
setControls((prev) => {
|
|
7273
|
+
const newMap = new Map(prev);
|
|
7274
|
+
newMap.delete(nodeId);
|
|
7275
|
+
return newMap;
|
|
7276
|
+
});
|
|
7277
|
+
}, []);
|
|
7278
|
+
const getControlBinding = useCallback8(
|
|
7279
|
+
(nodeId) => {
|
|
7280
|
+
return controls.get(nodeId);
|
|
7281
|
+
},
|
|
7282
|
+
[controls]
|
|
7283
|
+
);
|
|
7284
|
+
const sendModeChange = useCallback8(
|
|
7285
|
+
async (nodeId, mode) => {
|
|
7286
|
+
const binding = controls.get(nodeId);
|
|
7287
|
+
if (!binding) return;
|
|
7288
|
+
updateDeviceState(nodeId, { currentMode: mode });
|
|
7289
|
+
try {
|
|
7290
|
+
await binding.actions.onModeChange?.(mode);
|
|
7291
|
+
updateDeviceState(nodeId, {
|
|
7292
|
+
lastCommandTime: Date.now(),
|
|
7293
|
+
lastCommandResult: { success: true, message: `Mode changed to ${mode}` }
|
|
7294
|
+
});
|
|
7295
|
+
} catch (error) {
|
|
7296
|
+
updateDeviceState(nodeId, {
|
|
7297
|
+
currentMode: binding.state.currentMode,
|
|
7298
|
+
lastCommandResult: {
|
|
7299
|
+
success: false,
|
|
7300
|
+
message: error instanceof Error ? error.message : "Mode change failed"
|
|
7301
|
+
}
|
|
7302
|
+
});
|
|
7303
|
+
}
|
|
7304
|
+
},
|
|
7305
|
+
[controls, updateDeviceState]
|
|
7306
|
+
);
|
|
7307
|
+
const sendParameterChange = useCallback8(
|
|
7308
|
+
async (nodeId, parameterId, value) => {
|
|
7309
|
+
const binding = controls.get(nodeId);
|
|
7310
|
+
if (!binding) return;
|
|
7311
|
+
updateParameter(nodeId, parameterId, value);
|
|
7312
|
+
try {
|
|
7313
|
+
await binding.actions.onParameterChange?.(parameterId, value);
|
|
7314
|
+
updateDeviceState(nodeId, {
|
|
7315
|
+
lastCommandTime: Date.now(),
|
|
7316
|
+
lastCommandResult: { success: true, message: `Parameter ${parameterId} updated` }
|
|
7317
|
+
});
|
|
7318
|
+
} catch (error) {
|
|
7319
|
+
updateDeviceState(nodeId, {
|
|
7320
|
+
lastCommandResult: {
|
|
7321
|
+
success: false,
|
|
7322
|
+
message: error instanceof Error ? error.message : "Parameter change failed"
|
|
7323
|
+
}
|
|
7324
|
+
});
|
|
7325
|
+
}
|
|
7326
|
+
},
|
|
7327
|
+
[controls, updateParameter, updateDeviceState]
|
|
7328
|
+
);
|
|
7329
|
+
const sendStartCommand = useCallback8(
|
|
7330
|
+
async (nodeId) => {
|
|
7331
|
+
const binding = controls.get(nodeId);
|
|
7332
|
+
if (!binding) return;
|
|
7333
|
+
updateDeviceState(nodeId, { isRunning: true, status: "starting" });
|
|
7334
|
+
try {
|
|
7335
|
+
await binding.actions.onStart?.();
|
|
7336
|
+
updateDeviceState(nodeId, {
|
|
7337
|
+
status: "normal",
|
|
7338
|
+
lastCommandTime: Date.now(),
|
|
7339
|
+
lastCommandResult: { success: true, message: "Device started" }
|
|
7340
|
+
});
|
|
7341
|
+
} catch (error) {
|
|
7342
|
+
updateDeviceState(nodeId, {
|
|
7343
|
+
isRunning: false,
|
|
7344
|
+
status: "fault",
|
|
7345
|
+
lastCommandResult: {
|
|
7346
|
+
success: false,
|
|
7347
|
+
message: error instanceof Error ? error.message : "Start failed"
|
|
7348
|
+
}
|
|
7349
|
+
});
|
|
7350
|
+
}
|
|
7351
|
+
},
|
|
7352
|
+
[controls, updateDeviceState]
|
|
7353
|
+
);
|
|
7354
|
+
const sendStopCommand = useCallback8(
|
|
7355
|
+
async (nodeId) => {
|
|
7356
|
+
const binding = controls.get(nodeId);
|
|
7357
|
+
if (!binding) return;
|
|
7358
|
+
updateDeviceState(nodeId, { isRunning: false, status: "stopping" });
|
|
7359
|
+
try {
|
|
7360
|
+
await binding.actions.onStop?.();
|
|
7361
|
+
updateDeviceState(nodeId, {
|
|
7362
|
+
status: "off",
|
|
7363
|
+
lastCommandTime: Date.now(),
|
|
7364
|
+
lastCommandResult: { success: true, message: "Device stopped" }
|
|
7365
|
+
});
|
|
7366
|
+
} catch (error) {
|
|
7367
|
+
updateDeviceState(nodeId, {
|
|
7368
|
+
isRunning: true,
|
|
7369
|
+
status: "fault",
|
|
7370
|
+
lastCommandResult: {
|
|
7371
|
+
success: false,
|
|
7372
|
+
message: error instanceof Error ? error.message : "Stop failed"
|
|
7373
|
+
}
|
|
7374
|
+
});
|
|
7375
|
+
}
|
|
7376
|
+
},
|
|
7377
|
+
[controls, updateDeviceState]
|
|
7378
|
+
);
|
|
7379
|
+
const sendCustomAction = useCallback8(
|
|
7380
|
+
async (nodeId, actionId) => {
|
|
7381
|
+
const binding = controls.get(nodeId);
|
|
7382
|
+
if (!binding) return;
|
|
7383
|
+
try {
|
|
7384
|
+
await binding.actions.onCustomAction?.(actionId);
|
|
7385
|
+
updateDeviceState(nodeId, {
|
|
7386
|
+
lastCommandTime: Date.now(),
|
|
7387
|
+
lastCommandResult: { success: true, message: `Action ${actionId} executed` }
|
|
7388
|
+
});
|
|
7389
|
+
} catch (error) {
|
|
7390
|
+
updateDeviceState(nodeId, {
|
|
7391
|
+
lastCommandResult: {
|
|
7392
|
+
success: false,
|
|
7393
|
+
message: error instanceof Error ? error.message : "Action failed"
|
|
7394
|
+
}
|
|
7395
|
+
});
|
|
7396
|
+
}
|
|
7397
|
+
},
|
|
7398
|
+
[controls, updateDeviceState]
|
|
7399
|
+
);
|
|
7400
|
+
return {
|
|
7401
|
+
controls,
|
|
7402
|
+
updateControl,
|
|
7403
|
+
updateControlBatch,
|
|
7404
|
+
updateDeviceState,
|
|
7405
|
+
updateParameter,
|
|
7406
|
+
setControlBinding,
|
|
7407
|
+
removeControlBinding,
|
|
7408
|
+
getControlBinding,
|
|
7409
|
+
// Command helpers
|
|
7410
|
+
sendModeChange,
|
|
7411
|
+
sendParameterChange,
|
|
7412
|
+
sendStartCommand,
|
|
7413
|
+
sendStopCommand,
|
|
7414
|
+
sendCustomAction
|
|
7415
|
+
};
|
|
7416
|
+
}
|
|
7417
|
+
|
|
6389
7418
|
// src/diagram/hooks/useSimulation.ts
|
|
6390
|
-
import { useEffect as
|
|
7419
|
+
import { useEffect as useEffect12 } from "react";
|
|
6391
7420
|
function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
|
|
6392
7421
|
const {
|
|
6393
7422
|
interval = 2e3,
|
|
@@ -6398,7 +7427,7 @@ function useSimulation(telemetry, updateTelemetryBatch, options = {}) {
|
|
|
6398
7427
|
historyLength = 10,
|
|
6399
7428
|
generateValue
|
|
6400
7429
|
} = options;
|
|
6401
|
-
|
|
7430
|
+
useEffect12(() => {
|
|
6402
7431
|
if (!enabled) return;
|
|
6403
7432
|
const intervalId = setInterval(() => {
|
|
6404
7433
|
const updates = [];
|
|
@@ -6455,6 +7484,7 @@ export {
|
|
|
6455
7484
|
ControlPanel,
|
|
6456
7485
|
DEFAULT_THRESHOLDS,
|
|
6457
7486
|
DashboardCard,
|
|
7487
|
+
DeviceControlPanel,
|
|
6458
7488
|
DisplayModeToggle,
|
|
6459
7489
|
EquipmentIndicator,
|
|
6460
7490
|
EquipmentIndicatorWithSparkline,
|
|
@@ -6466,6 +7496,7 @@ export {
|
|
|
6466
7496
|
LeftToggleButton,
|
|
6467
7497
|
LegacyValueEntry,
|
|
6468
7498
|
NodeConfigPanel,
|
|
7499
|
+
NodeControlsPanel,
|
|
6469
7500
|
PIDCanvas,
|
|
6470
7501
|
PanelContent,
|
|
6471
7502
|
PanelTabs,
|
|
@@ -6485,6 +7516,7 @@ export {
|
|
|
6485
7516
|
ZoomButton,
|
|
6486
7517
|
ZoomControls,
|
|
6487
7518
|
calculateThresholdStatus,
|
|
7519
|
+
createControlBinding,
|
|
6488
7520
|
exampleDiagram,
|
|
6489
7521
|
exportDiagram,
|
|
6490
7522
|
generateRoutePoints,
|
|
@@ -6495,6 +7527,9 @@ export {
|
|
|
6495
7527
|
mockSymbolLibrary,
|
|
6496
7528
|
nodeHasPort,
|
|
6497
7529
|
overlayStyles,
|
|
7530
|
+
registerSymbol,
|
|
7531
|
+
registerSymbols,
|
|
7532
|
+
useDeviceControls,
|
|
6498
7533
|
useDrag,
|
|
6499
7534
|
useKeyboardShortcuts,
|
|
6500
7535
|
useSelection,
|