@procaaso/alphinity-ui-components 1.13.0 → 1.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/IMPLEMENTATION_GUIDE.md +1351 -1351
- package/README.md +98 -98
- package/dist/index.cjs +83 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +54 -19
- package/dist/index.d.ts +54 -19
- package/dist/index.js +83 -52
- package/dist/index.js.map +1 -1
- package/package.json +85 -85
package/dist/index.d.cts
CHANGED
|
@@ -528,10 +528,29 @@ interface CustomAction {
|
|
|
528
528
|
* Device control capabilities and commands
|
|
529
529
|
*/
|
|
530
530
|
interface ControlCapabilities {
|
|
531
|
-
/**
|
|
531
|
+
/**
|
|
532
|
+
* Can the device be started? When `canStart` or `canStop` is true, the
|
|
533
|
+
* panel shows BOTH the START and the STOP button, each in a fixed place
|
|
534
|
+
* (alphinity-tffi #3853). A false `canStart` then shows START disabled.
|
|
535
|
+
* It does not remove START and it does not let STOP take its place.
|
|
536
|
+
*/
|
|
532
537
|
canStart?: boolean;
|
|
533
|
-
/** Can the device be stopped? */
|
|
538
|
+
/** Can the device be stopped? See `canStart`. */
|
|
534
539
|
canStop?: boolean;
|
|
540
|
+
/**
|
|
541
|
+
* Does START apply now? Default: true (enabled). Set false to show START
|
|
542
|
+
* disabled, for example on a pump that runs already. Use this with
|
|
543
|
+
* `canStart: true` to keep "the device has a START" apart from "START
|
|
544
|
+
* applies now". A disabled START does not call `onStart`.
|
|
545
|
+
*/
|
|
546
|
+
startEnabled?: boolean;
|
|
547
|
+
/**
|
|
548
|
+
* Does STOP apply now? Default: true (enabled). Set false to show STOP
|
|
549
|
+
* disabled, for example on a pump that is stopped. The panel itself never
|
|
550
|
+
* disables STOP for a pending command. A disabled STOP does not call
|
|
551
|
+
* `onStop`.
|
|
552
|
+
*/
|
|
553
|
+
stopEnabled?: boolean;
|
|
535
554
|
/** Can the device be paused? */
|
|
536
555
|
canPause?: boolean;
|
|
537
556
|
/** Can the device be reset? */
|
|
@@ -609,8 +628,11 @@ interface ControlState {
|
|
|
609
628
|
* Current status. `unknown` marks an untrusted read (OPC UA StatusCode
|
|
610
629
|
* severity Bad). This library never infers `unknown`; it only displays a
|
|
611
630
|
* value the backend has already published as `unknown`.
|
|
631
|
+
*
|
|
632
|
+
* `forced` marks a device that a maintenance force holds. It resolves to
|
|
633
|
+
* `FORCED_MARK_COLOR`, the same violet as every other forced mark.
|
|
612
634
|
*/
|
|
613
|
-
status?: 'normal' | 'warning' | 'alarm' | 'fault' | 'off' | 'starting' | 'stopping' | 'unknown';
|
|
635
|
+
status?: 'normal' | 'warning' | 'alarm' | 'fault' | 'off' | 'starting' | 'stopping' | 'unknown' | 'forced';
|
|
614
636
|
/** Status message */
|
|
615
637
|
statusMessage?: string;
|
|
616
638
|
/** Last command timestamp */
|
|
@@ -775,12 +797,18 @@ interface DeviceControlPanelProps {
|
|
|
775
797
|
/** Called when stop button clicked */
|
|
776
798
|
onStop?: () => void;
|
|
777
799
|
/**
|
|
778
|
-
* Start command is in flight (awaiting ack).
|
|
779
|
-
*
|
|
780
|
-
*
|
|
800
|
+
* Start command is in flight (awaiting ack). START shows "STARTING..." and
|
|
801
|
+
* is disabled, so a second tap cannot send a second start. STOP stays
|
|
802
|
+
* enabled: a pending start never disables STOP (alphinity-tffi #3853).
|
|
803
|
+
* Wire from the hook's `isCommandPending(nodeId, 'start')`, or from the
|
|
804
|
+
* host's own in-flight state.
|
|
781
805
|
*/
|
|
782
806
|
startPending?: boolean;
|
|
783
|
-
/**
|
|
807
|
+
/**
|
|
808
|
+
* Stop command is in flight (awaiting ack). STOP shows "STOPPING..." and
|
|
809
|
+
* stays enabled, so STOP is always one tap. Only `capabilities.canStop`
|
|
810
|
+
* or `capabilities.stopEnabled` can disable STOP.
|
|
811
|
+
*/
|
|
784
812
|
stopPending?: boolean;
|
|
785
813
|
/** Called when custom action clicked */
|
|
786
814
|
onCustomAction?: (actionId: string) => void;
|
|
@@ -1166,7 +1194,7 @@ declare const ThemeToggle: React__default.FC<ThemeToggleProps>;
|
|
|
1166
1194
|
* from a number or a threshold. The library only displays an `unknown` value
|
|
1167
1195
|
* that the backend has already published.
|
|
1168
1196
|
*/
|
|
1169
|
-
type DeviceStatus = 'normal' | 'warning' | 'alarm' | 'fault' | 'off' | 'starting' | 'stopping' | 'unknown';
|
|
1197
|
+
type DeviceStatus = 'normal' | 'warning' | 'alarm' | 'fault' | 'off' | 'starting' | 'stopping' | 'unknown' | 'forced';
|
|
1170
1198
|
/** Color entry covering both SVG node and overlay/panel needs */
|
|
1171
1199
|
interface StatusColorEntry {
|
|
1172
1200
|
/** Fill color for SVG node symbols */
|
|
@@ -1219,6 +1247,22 @@ declare const ISA_UNKNOWN_DARK: {
|
|
|
1219
1247
|
readonly bg: "#23263a";
|
|
1220
1248
|
readonly border: "#6f74a3";
|
|
1221
1249
|
};
|
|
1250
|
+
/**
|
|
1251
|
+
* Maintenance-force marking color (#3607, R19). A forced value is not a
|
|
1252
|
+
* health status, and must never share a color with warning/alarm/fault or
|
|
1253
|
+
* read as one of them. Violet is unused elsewhere in this palette.
|
|
1254
|
+
*
|
|
1255
|
+
* `DEFAULT_STATUS_COLORS.forced` points at this same object (alphinity-tffi
|
|
1256
|
+
* #3771). A device that a maintenance force holds then gets the forced
|
|
1257
|
+
* violet on its status dot, and not the `off` grey fallback. The forced
|
|
1258
|
+
* entry is a marker, not a severity: it stays outside the
|
|
1259
|
+
* warning/alarm/fault colours.
|
|
1260
|
+
*
|
|
1261
|
+
* Light fill + dark text, not a solid vivid chip: reads as a calm marker
|
|
1262
|
+
* rather than an alarm sticker, while the vivid `border` shade still
|
|
1263
|
+
* outlines a forced value's box/ring so it stays findable at a glance.
|
|
1264
|
+
*/
|
|
1265
|
+
declare const FORCED_MARK_COLOR: StatusColorEntry;
|
|
1222
1266
|
/**
|
|
1223
1267
|
* ISA-101 defaults.
|
|
1224
1268
|
*
|
|
@@ -1231,6 +1275,8 @@ declare const ISA_UNKNOWN_DARK: {
|
|
|
1231
1275
|
* - stopping: amber (transitional)
|
|
1232
1276
|
* - unknown: periwinkle (untrusted read; OPC UA severity Bad). Derived
|
|
1233
1277
|
* from ISA_UNKNOWN above, the shared token.
|
|
1278
|
+
* - forced: violet (a maintenance force holds the device). The same
|
|
1279
|
+
* object as FORCED_MARK_COLOR above.
|
|
1234
1280
|
*
|
|
1235
1281
|
* The unknown entry deliberately does NOT rely on its fill. The flat fill
|
|
1236
1282
|
* sits a CIEDE2000 delta-E of 0.45 from the off fill after greyscale
|
|
@@ -1245,17 +1291,6 @@ declare const ISA_UNKNOWN_DARK: {
|
|
|
1245
1291
|
* apart. That is why unknown never relies on colour anywhere.
|
|
1246
1292
|
*/
|
|
1247
1293
|
declare const DEFAULT_STATUS_COLORS: Record<DeviceStatus, StatusColorEntry>;
|
|
1248
|
-
/**
|
|
1249
|
-
* Maintenance-force marking color (#3607, R19). Deliberately outside
|
|
1250
|
-
* DEFAULT_STATUS_COLORS: a forced value is not a health status, and must
|
|
1251
|
-
* never share a color with warning/alarm/fault or read as one of them.
|
|
1252
|
-
* Violet is unused elsewhere in this palette.
|
|
1253
|
-
*
|
|
1254
|
-
* Light fill + dark text, not a solid vivid chip: reads as a calm marker
|
|
1255
|
-
* rather than an alarm sticker, while the vivid `border` shade still
|
|
1256
|
-
* outlines a forced value's box/ring so it stays findable at a glance.
|
|
1257
|
-
*/
|
|
1258
|
-
declare const FORCED_MARK_COLOR: StatusColorEntry;
|
|
1259
1294
|
/**
|
|
1260
1295
|
* Normalize a status string to its canonical `DeviceStatus` key.
|
|
1261
1296
|
*
|
package/dist/index.d.ts
CHANGED
|
@@ -528,10 +528,29 @@ interface CustomAction {
|
|
|
528
528
|
* Device control capabilities and commands
|
|
529
529
|
*/
|
|
530
530
|
interface ControlCapabilities {
|
|
531
|
-
/**
|
|
531
|
+
/**
|
|
532
|
+
* Can the device be started? When `canStart` or `canStop` is true, the
|
|
533
|
+
* panel shows BOTH the START and the STOP button, each in a fixed place
|
|
534
|
+
* (alphinity-tffi #3853). A false `canStart` then shows START disabled.
|
|
535
|
+
* It does not remove START and it does not let STOP take its place.
|
|
536
|
+
*/
|
|
532
537
|
canStart?: boolean;
|
|
533
|
-
/** Can the device be stopped? */
|
|
538
|
+
/** Can the device be stopped? See `canStart`. */
|
|
534
539
|
canStop?: boolean;
|
|
540
|
+
/**
|
|
541
|
+
* Does START apply now? Default: true (enabled). Set false to show START
|
|
542
|
+
* disabled, for example on a pump that runs already. Use this with
|
|
543
|
+
* `canStart: true` to keep "the device has a START" apart from "START
|
|
544
|
+
* applies now". A disabled START does not call `onStart`.
|
|
545
|
+
*/
|
|
546
|
+
startEnabled?: boolean;
|
|
547
|
+
/**
|
|
548
|
+
* Does STOP apply now? Default: true (enabled). Set false to show STOP
|
|
549
|
+
* disabled, for example on a pump that is stopped. The panel itself never
|
|
550
|
+
* disables STOP for a pending command. A disabled STOP does not call
|
|
551
|
+
* `onStop`.
|
|
552
|
+
*/
|
|
553
|
+
stopEnabled?: boolean;
|
|
535
554
|
/** Can the device be paused? */
|
|
536
555
|
canPause?: boolean;
|
|
537
556
|
/** Can the device be reset? */
|
|
@@ -609,8 +628,11 @@ interface ControlState {
|
|
|
609
628
|
* Current status. `unknown` marks an untrusted read (OPC UA StatusCode
|
|
610
629
|
* severity Bad). This library never infers `unknown`; it only displays a
|
|
611
630
|
* value the backend has already published as `unknown`.
|
|
631
|
+
*
|
|
632
|
+
* `forced` marks a device that a maintenance force holds. It resolves to
|
|
633
|
+
* `FORCED_MARK_COLOR`, the same violet as every other forced mark.
|
|
612
634
|
*/
|
|
613
|
-
status?: 'normal' | 'warning' | 'alarm' | 'fault' | 'off' | 'starting' | 'stopping' | 'unknown';
|
|
635
|
+
status?: 'normal' | 'warning' | 'alarm' | 'fault' | 'off' | 'starting' | 'stopping' | 'unknown' | 'forced';
|
|
614
636
|
/** Status message */
|
|
615
637
|
statusMessage?: string;
|
|
616
638
|
/** Last command timestamp */
|
|
@@ -775,12 +797,18 @@ interface DeviceControlPanelProps {
|
|
|
775
797
|
/** Called when stop button clicked */
|
|
776
798
|
onStop?: () => void;
|
|
777
799
|
/**
|
|
778
|
-
* Start command is in flight (awaiting ack).
|
|
779
|
-
*
|
|
780
|
-
*
|
|
800
|
+
* Start command is in flight (awaiting ack). START shows "STARTING..." and
|
|
801
|
+
* is disabled, so a second tap cannot send a second start. STOP stays
|
|
802
|
+
* enabled: a pending start never disables STOP (alphinity-tffi #3853).
|
|
803
|
+
* Wire from the hook's `isCommandPending(nodeId, 'start')`, or from the
|
|
804
|
+
* host's own in-flight state.
|
|
781
805
|
*/
|
|
782
806
|
startPending?: boolean;
|
|
783
|
-
/**
|
|
807
|
+
/**
|
|
808
|
+
* Stop command is in flight (awaiting ack). STOP shows "STOPPING..." and
|
|
809
|
+
* stays enabled, so STOP is always one tap. Only `capabilities.canStop`
|
|
810
|
+
* or `capabilities.stopEnabled` can disable STOP.
|
|
811
|
+
*/
|
|
784
812
|
stopPending?: boolean;
|
|
785
813
|
/** Called when custom action clicked */
|
|
786
814
|
onCustomAction?: (actionId: string) => void;
|
|
@@ -1166,7 +1194,7 @@ declare const ThemeToggle: React__default.FC<ThemeToggleProps>;
|
|
|
1166
1194
|
* from a number or a threshold. The library only displays an `unknown` value
|
|
1167
1195
|
* that the backend has already published.
|
|
1168
1196
|
*/
|
|
1169
|
-
type DeviceStatus = 'normal' | 'warning' | 'alarm' | 'fault' | 'off' | 'starting' | 'stopping' | 'unknown';
|
|
1197
|
+
type DeviceStatus = 'normal' | 'warning' | 'alarm' | 'fault' | 'off' | 'starting' | 'stopping' | 'unknown' | 'forced';
|
|
1170
1198
|
/** Color entry covering both SVG node and overlay/panel needs */
|
|
1171
1199
|
interface StatusColorEntry {
|
|
1172
1200
|
/** Fill color for SVG node symbols */
|
|
@@ -1219,6 +1247,22 @@ declare const ISA_UNKNOWN_DARK: {
|
|
|
1219
1247
|
readonly bg: "#23263a";
|
|
1220
1248
|
readonly border: "#6f74a3";
|
|
1221
1249
|
};
|
|
1250
|
+
/**
|
|
1251
|
+
* Maintenance-force marking color (#3607, R19). A forced value is not a
|
|
1252
|
+
* health status, and must never share a color with warning/alarm/fault or
|
|
1253
|
+
* read as one of them. Violet is unused elsewhere in this palette.
|
|
1254
|
+
*
|
|
1255
|
+
* `DEFAULT_STATUS_COLORS.forced` points at this same object (alphinity-tffi
|
|
1256
|
+
* #3771). A device that a maintenance force holds then gets the forced
|
|
1257
|
+
* violet on its status dot, and not the `off` grey fallback. The forced
|
|
1258
|
+
* entry is a marker, not a severity: it stays outside the
|
|
1259
|
+
* warning/alarm/fault colours.
|
|
1260
|
+
*
|
|
1261
|
+
* Light fill + dark text, not a solid vivid chip: reads as a calm marker
|
|
1262
|
+
* rather than an alarm sticker, while the vivid `border` shade still
|
|
1263
|
+
* outlines a forced value's box/ring so it stays findable at a glance.
|
|
1264
|
+
*/
|
|
1265
|
+
declare const FORCED_MARK_COLOR: StatusColorEntry;
|
|
1222
1266
|
/**
|
|
1223
1267
|
* ISA-101 defaults.
|
|
1224
1268
|
*
|
|
@@ -1231,6 +1275,8 @@ declare const ISA_UNKNOWN_DARK: {
|
|
|
1231
1275
|
* - stopping: amber (transitional)
|
|
1232
1276
|
* - unknown: periwinkle (untrusted read; OPC UA severity Bad). Derived
|
|
1233
1277
|
* from ISA_UNKNOWN above, the shared token.
|
|
1278
|
+
* - forced: violet (a maintenance force holds the device). The same
|
|
1279
|
+
* object as FORCED_MARK_COLOR above.
|
|
1234
1280
|
*
|
|
1235
1281
|
* The unknown entry deliberately does NOT rely on its fill. The flat fill
|
|
1236
1282
|
* sits a CIEDE2000 delta-E of 0.45 from the off fill after greyscale
|
|
@@ -1245,17 +1291,6 @@ declare const ISA_UNKNOWN_DARK: {
|
|
|
1245
1291
|
* apart. That is why unknown never relies on colour anywhere.
|
|
1246
1292
|
*/
|
|
1247
1293
|
declare const DEFAULT_STATUS_COLORS: Record<DeviceStatus, StatusColorEntry>;
|
|
1248
|
-
/**
|
|
1249
|
-
* Maintenance-force marking color (#3607, R19). Deliberately outside
|
|
1250
|
-
* DEFAULT_STATUS_COLORS: a forced value is not a health status, and must
|
|
1251
|
-
* never share a color with warning/alarm/fault or read as one of them.
|
|
1252
|
-
* Violet is unused elsewhere in this palette.
|
|
1253
|
-
*
|
|
1254
|
-
* Light fill + dark text, not a solid vivid chip: reads as a calm marker
|
|
1255
|
-
* rather than an alarm sticker, while the vivid `border` shade still
|
|
1256
|
-
* outlines a forced value's box/ring so it stays findable at a glance.
|
|
1257
|
-
*/
|
|
1258
|
-
declare const FORCED_MARK_COLOR: StatusColorEntry;
|
|
1259
1294
|
/**
|
|
1260
1295
|
* Normalize a status string to its canonical `DeviceStatus` key.
|
|
1261
1296
|
*
|
package/dist/index.js
CHANGED
|
@@ -277,6 +277,13 @@ var ISA_UNKNOWN_DARK = {
|
|
|
277
277
|
bg: "#23263a",
|
|
278
278
|
border: "#6f74a3"
|
|
279
279
|
};
|
|
280
|
+
var FORCED_MARK_COLOR = {
|
|
281
|
+
fill: "#ede9fe",
|
|
282
|
+
stroke: "#5b21b6",
|
|
283
|
+
bg: "#ede9fe",
|
|
284
|
+
text: "#5b21b6",
|
|
285
|
+
border: "#7c3aed"
|
|
286
|
+
};
|
|
280
287
|
var DEFAULT_STATUS_COLORS = {
|
|
281
288
|
normal: { fill: "#888888", stroke: "#6b6b6b", bg: "#888888", text: "#ffffff", border: "#6b6b6b" },
|
|
282
289
|
warning: { fill: "#f59e0b", stroke: "#d97706", bg: "#FFD700", text: "#000000", border: "#d97706" },
|
|
@@ -285,14 +292,8 @@ var DEFAULT_STATUS_COLORS = {
|
|
|
285
292
|
off: { fill: "#edeeef", stroke: "#000000", bg: "#666666", text: "#ffffff", border: "#4b5563" },
|
|
286
293
|
starting: { fill: "#90EE90", stroke: "#22c55e", bg: "#90EE90", text: "#000000", border: "#22c55e" },
|
|
287
294
|
stopping: { fill: "#FFD700", stroke: "#d97706", bg: "#FFD700", text: "#000000", border: "#d97706" },
|
|
288
|
-
unknown: { fill: ISA_UNKNOWN.bg, stroke: ISA_UNKNOWN.border, bg: ISA_UNKNOWN.bg, text: ISA_UNKNOWN.fg, border: ISA_UNKNOWN.border }
|
|
289
|
-
|
|
290
|
-
var FORCED_MARK_COLOR = {
|
|
291
|
-
fill: "#ede9fe",
|
|
292
|
-
stroke: "#5b21b6",
|
|
293
|
-
bg: "#ede9fe",
|
|
294
|
-
text: "#5b21b6",
|
|
295
|
-
border: "#7c3aed"
|
|
295
|
+
unknown: { fill: ISA_UNKNOWN.bg, stroke: ISA_UNKNOWN.border, bg: ISA_UNKNOWN.bg, text: ISA_UNKNOWN.fg, border: ISA_UNKNOWN.border },
|
|
296
|
+
forced: FORCED_MARK_COLOR
|
|
296
297
|
};
|
|
297
298
|
var STATUS_ALIASES = {
|
|
298
299
|
running: "normal",
|
|
@@ -1138,6 +1139,10 @@ var NodeControlsPanel = ({
|
|
|
1138
1139
|
// src/components/DeviceControlPanel/DeviceControlPanel.tsx
|
|
1139
1140
|
import React6, { useState as useState5, useEffect as useEffect2 } from "react";
|
|
1140
1141
|
import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1142
|
+
var DISABLED_BUTTON_BG = "#e5e7eb";
|
|
1143
|
+
var DISABLED_BUTTON_TEXT = "#4b5563";
|
|
1144
|
+
var DISABLED_BUTTON_BORDER = "#6b7280";
|
|
1145
|
+
var DISABLED_BUTTON_HATCH = "repeating-linear-gradient(135deg, rgba(0,0,0,0.10) 0px, rgba(0,0,0,0.10) 4px, transparent 4px, transparent 10px)";
|
|
1141
1146
|
function DeviceControlPanelImpl({
|
|
1142
1147
|
binding,
|
|
1143
1148
|
onClose,
|
|
@@ -1218,6 +1223,36 @@ function DeviceControlPanelImpl({
|
|
|
1218
1223
|
const statusEntry = resolveStatusColor(binding.state.status, binding.theme?.statusColors);
|
|
1219
1224
|
const statusColor = statusEntry.bg;
|
|
1220
1225
|
const isUnknownStatus = normalizeDeviceStatus(binding.state.status) === "unknown";
|
|
1226
|
+
const startStopRowShown = binding.display?.showStartStop !== false && (activeCapabilities?.canStart === true || activeCapabilities?.canStop === true);
|
|
1227
|
+
const startEnabledNow = activeCapabilities?.canStart === true && activeCapabilities?.startEnabled !== false && !startPending;
|
|
1228
|
+
const stopEnabledNow = activeCapabilities?.canStop === true && activeCapabilities?.stopEnabled !== false;
|
|
1229
|
+
const startStopFontPx = Math.max(18, Math.round(18 * fontScale));
|
|
1230
|
+
const startStopButtonStyle = (enabled, enabledBg) => ({
|
|
1231
|
+
flex: 1,
|
|
1232
|
+
minWidth: 0,
|
|
1233
|
+
height: Math.max(touchSize, 56),
|
|
1234
|
+
borderRadius: "6px",
|
|
1235
|
+
fontSize: `${startStopFontPx}px`,
|
|
1236
|
+
fontWeight: 700,
|
|
1237
|
+
fontFamily: "Arial, sans-serif",
|
|
1238
|
+
letterSpacing: "0.5px",
|
|
1239
|
+
...enabled ? {
|
|
1240
|
+
backgroundColor: enabledBg,
|
|
1241
|
+
color: "#ffffff",
|
|
1242
|
+
border: "2px solid transparent",
|
|
1243
|
+
cursor: "pointer",
|
|
1244
|
+
opacity: 1
|
|
1245
|
+
} : {
|
|
1246
|
+
// Disabled look that does not depend on colour (ISA-101): a dashed
|
|
1247
|
+
// border and a diagonal hatch. A grey fill alone is not enough.
|
|
1248
|
+
backgroundColor: DISABLED_BUTTON_BG,
|
|
1249
|
+
backgroundImage: DISABLED_BUTTON_HATCH,
|
|
1250
|
+
color: DISABLED_BUTTON_TEXT,
|
|
1251
|
+
border: `2px dashed ${DISABLED_BUTTON_BORDER}`,
|
|
1252
|
+
cursor: "not-allowed",
|
|
1253
|
+
opacity: 1
|
|
1254
|
+
}
|
|
1255
|
+
});
|
|
1221
1256
|
const handleModeChange = (mode) => {
|
|
1222
1257
|
onModeChange?.(mode);
|
|
1223
1258
|
};
|
|
@@ -1403,6 +1438,7 @@ function DeviceControlPanelImpl({
|
|
|
1403
1438
|
/* @__PURE__ */ jsx9(
|
|
1404
1439
|
"div",
|
|
1405
1440
|
{
|
|
1441
|
+
"data-testid": "device-status-dot",
|
|
1406
1442
|
style: {
|
|
1407
1443
|
width: "10px",
|
|
1408
1444
|
height: "10px",
|
|
@@ -1988,50 +2024,45 @@ function DeviceControlPanelImpl({
|
|
|
1988
2024
|
param.id
|
|
1989
2025
|
))
|
|
1990
2026
|
] }),
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
},
|
|
2031
|
-
children: stopPending ? "STOPPING\u2026" : "STOP"
|
|
2032
|
-
}
|
|
2033
|
-
)
|
|
2034
|
-
] }),
|
|
2027
|
+
startStopRowShown && /* @__PURE__ */ jsxs8(
|
|
2028
|
+
"div",
|
|
2029
|
+
{
|
|
2030
|
+
"data-testid": "start-stop-row",
|
|
2031
|
+
style: { display: "flex", gap: spacing.gap, marginBottom: spacing.marginBottom },
|
|
2032
|
+
children: [
|
|
2033
|
+
/* @__PURE__ */ jsx9(
|
|
2034
|
+
"button",
|
|
2035
|
+
{
|
|
2036
|
+
type: "button",
|
|
2037
|
+
"data-control": "start",
|
|
2038
|
+
"data-enabled": startEnabledNow ? "true" : "false",
|
|
2039
|
+
onClick: () => {
|
|
2040
|
+
if (startEnabledNow) onStart?.();
|
|
2041
|
+
},
|
|
2042
|
+
disabled: !startEnabledNow,
|
|
2043
|
+
"aria-busy": startPending || void 0,
|
|
2044
|
+
style: startStopButtonStyle(startEnabledNow, "#10b981"),
|
|
2045
|
+
children: startPending ? "STARTING\u2026" : "START"
|
|
2046
|
+
}
|
|
2047
|
+
),
|
|
2048
|
+
/* @__PURE__ */ jsx9(
|
|
2049
|
+
"button",
|
|
2050
|
+
{
|
|
2051
|
+
type: "button",
|
|
2052
|
+
"data-control": "stop",
|
|
2053
|
+
"data-enabled": stopEnabledNow ? "true" : "false",
|
|
2054
|
+
onClick: () => {
|
|
2055
|
+
if (stopEnabledNow) onStop?.();
|
|
2056
|
+
},
|
|
2057
|
+
disabled: !stopEnabledNow,
|
|
2058
|
+
"aria-busy": stopPending || void 0,
|
|
2059
|
+
style: startStopButtonStyle(stopEnabledNow, "#ef4444"),
|
|
2060
|
+
children: stopPending ? "STOPPING\u2026" : "STOP"
|
|
2061
|
+
}
|
|
2062
|
+
)
|
|
2063
|
+
]
|
|
2064
|
+
}
|
|
2065
|
+
),
|
|
2035
2066
|
activeCapabilities?.customActions && activeCapabilities.customActions.length > 0 && /* @__PURE__ */ jsx9("div", { style: { display: "flex", flexWrap: "wrap", gap: "8px" }, children: activeCapabilities.customActions.map((action) => {
|
|
2036
2067
|
const actionDisabled = action.disabled === true;
|
|
2037
2068
|
return /* @__PURE__ */ jsxs8(
|