@adcops/autocore-react 3.3.75 → 3.3.79

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.
Files changed (56) hide show
  1. package/dist/components/Indicator.d.ts +29 -52
  2. package/dist/components/Indicator.d.ts.map +1 -1
  3. package/dist/components/Indicator.js +1 -1
  4. package/dist/components/ams/AmsProvider.d.ts +7 -0
  5. package/dist/components/ams/AmsProvider.d.ts.map +1 -1
  6. package/dist/components/ams/AssetDetailView.d.ts.map +1 -1
  7. package/dist/components/ams/AssetDetailView.js +1 -1
  8. package/dist/components/ams/AssetRegistryTable.d.ts.map +1 -1
  9. package/dist/components/ams/AssetRegistryTable.js +1 -1
  10. package/dist/components/ams/CalibrationEntryDialog.d.ts.map +1 -1
  11. package/dist/components/ams/CalibrationEntryDialog.js +1 -1
  12. package/dist/components/ams/MissingAssetsBanner.d.ts +11 -0
  13. package/dist/components/ams/MissingAssetsBanner.d.ts.map +1 -0
  14. package/dist/components/ams/MissingAssetsBanner.js +1 -0
  15. package/dist/components/ams/PlaceholderHealthPanel.d.ts +3 -0
  16. package/dist/components/ams/PlaceholderHealthPanel.d.ts.map +1 -0
  17. package/dist/components/ams/PlaceholderHealthPanel.js +1 -0
  18. package/dist/components/ams/index.d.ts +2 -0
  19. package/dist/components/ams/index.d.ts.map +1 -1
  20. package/dist/components/ams/index.js +1 -1
  21. package/dist/components/index.d.ts +8 -0
  22. package/dist/components/index.d.ts.map +1 -1
  23. package/dist/components/index.js +1 -1
  24. package/dist/components/network/NetworkPanel.d.ts +8 -0
  25. package/dist/components/network/NetworkPanel.d.ts.map +1 -0
  26. package/dist/components/network/NetworkPanel.js +1 -0
  27. package/dist/components/network/NetworkProvider.d.ts +72 -0
  28. package/dist/components/network/NetworkProvider.d.ts.map +1 -0
  29. package/dist/components/network/NetworkProvider.js +1 -0
  30. package/dist/components/network/StagedChangeBanner.d.ts +8 -0
  31. package/dist/components/network/StagedChangeBanner.d.ts.map +1 -0
  32. package/dist/components/network/StagedChangeBanner.js +1 -0
  33. package/dist/components/network/index.d.ts +7 -0
  34. package/dist/components/network/index.d.ts.map +1 -0
  35. package/dist/components/network/index.js +1 -0
  36. package/dist/components/tis/ProjectManager.d.ts +7 -0
  37. package/dist/components/tis/ProjectManager.d.ts.map +1 -0
  38. package/dist/components/tis/ProjectManager.js +1 -0
  39. package/dist/components/tis/ResultHistoryTable.d.ts.map +1 -1
  40. package/dist/components/tis/ResultHistoryTable.js +1 -1
  41. package/package.json +1 -1
  42. package/src/components/Indicator.tsx +177 -162
  43. package/src/components/ams/AmsProvider.tsx +7 -0
  44. package/src/components/ams/AssetDetailView.tsx +287 -4
  45. package/src/components/ams/AssetRegistryTable.tsx +325 -21
  46. package/src/components/ams/CalibrationEntryDialog.tsx +163 -30
  47. package/src/components/ams/MissingAssetsBanner.tsx +124 -0
  48. package/src/components/ams/PlaceholderHealthPanel.tsx +188 -0
  49. package/src/components/ams/index.ts +2 -0
  50. package/src/components/index.ts +26 -0
  51. package/src/components/network/NetworkPanel.tsx +363 -0
  52. package/src/components/network/NetworkProvider.tsx +349 -0
  53. package/src/components/network/StagedChangeBanner.tsx +101 -0
  54. package/src/components/network/index.ts +17 -0
  55. package/src/components/tis/ProjectManager.tsx +393 -0
  56. package/src/components/tis/ResultHistoryTable.tsx +126 -188
@@ -1,67 +1,44 @@
1
- import React, { Component } from 'react';
2
- import { type EventEmitterContextType } from '../core/EventEmitterContext';
3
- import { IndicatorColor } from "../core/IndicatorColor";
1
+ import React from 'react';
2
+ import { IndicatorColor } from '../core/IndicatorColor';
4
3
  export { IndicatorColor };
5
- interface IndicatorProps {
4
+ export interface IndicatorProps {
6
5
  /**
7
- * Label of the group/row. Can be any element.
6
+ * State to be displayed.
8
7
  *
9
- * ## Examples
10
- * ```
11
- * <Indicator label="Simple Text" />
12
- * <Indicator label={<span><i className="pi pi-check"></i> Icon and Text</span>} />
13
- * <Indicator label={<YourCustomIconComponent />} />
14
- * ```
15
- */
16
- label?: React.ReactNode;
17
- /**
18
- * State to be displayed<br/>
19
- *
20
- * Available states: **on**, **off** and **not available**:
21
- *
22
- * * `true` is treated as **on**
23
- * * `false` is treated as **off**
24
- * * `undefined` is treated as **not available**
25
- */
26
- value?: boolean | undefined;
27
- /**
28
- * CSS color for **enabled** state
8
+ * * `true` → on
9
+ * * `false` → off
10
+ * * `undefined` not available (invalid color)
29
11
  */
12
+ value?: boolean;
13
+ /** CSS color when value is true. Defaults to IndicatorColor.IndicatorGreen. */
30
14
  onColor?: string;
31
- /**
32
- * CSS color for **disabled** state
33
- */
15
+ /** CSS color when value is false. Defaults to IndicatorColor.IndicatorOff (gray). */
34
16
  offColor?: string;
35
- /**
36
- * CSS color for **not available** state
37
- */
17
+ /** CSS color when value is undefined. Defaults to IndicatorColor.IndicatorInvalid (black). */
38
18
  invalidColor?: string;
39
19
  /**
40
- * Custom class name to be attached
20
+ * Optional broadcast topic to subscribe to. The latest broadcast value
21
+ * is used when `value` is left undefined; an explicit `value` always
22
+ * wins so callers can drive the indicator from React state instead.
41
23
  */
24
+ topic?: string;
25
+ /** Additional CSS class names applied to the outer box. */
42
26
  className?: string;
27
+ /** Inline style overrides for the outer box. */
28
+ style?: React.CSSProperties;
43
29
  /**
44
- * The topic to monitor to display. Optional.
30
+ * Legacy text label rendered next to a small color swatch. Mutually
31
+ * exclusive with `children` — pass one or the other. Plain strings or
32
+ * React nodes both work.
45
33
  */
46
- topic?: string;
47
- }
48
- interface IndicatorState {
49
- subscribedValue?: boolean | null;
50
- fontSize?: string;
51
- }
52
- export declare class Indicator extends Component<IndicatorProps, IndicatorState> {
53
- static contextType: React.Context<EventEmitterContextType>;
54
- protected unsubscribeTopicId: number | null;
55
- static defaultProps: {
56
- onColor: string;
57
- offColor: string;
58
- invalidColor: string;
59
- };
60
- constructor(props: IndicatorProps);
61
- componentDidMount(): void;
62
- componentDidUpdate(prevProps: IndicatorProps): void;
63
- componentWillUnmount(): void;
64
- render(): import("react/jsx-runtime").JSX.Element;
34
+ label?: React.ReactNode;
35
+ /**
36
+ * Icon (or any node) to display on top of the colored backdrop.
37
+ * Use this for the modern square-button-shaped indicator, e.g.
38
+ * `<Indicator ...><i className="pi pi-power-off" /></Indicator>`.
39
+ */
40
+ children?: React.ReactNode;
65
41
  }
42
+ export declare const Indicator: React.FC<IndicatorProps>;
66
43
  export default Indicator;
67
44
  //# sourceMappingURL=Indicator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Indicator.d.ts","sourceRoot":"","sources":["../../src/components/Indicator.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEzC,OAAO,EAAuB,KAAK,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAEhG,OAAO,EAAC,cAAc,EAAC,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAC,cAAc,EAAC,CAAA;AAOvB,UAAU,cAAc;IAGpB;;;;;;;;;OASG;IACH,KAAK,CAAC,EAAG,KAAK,CAAC,SAAS,CAAC;IAGzB;;;;;;;;OAQG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAGlB;AAGD,UAAU,cAAc;IACpB,eAAe,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAGD,qBAAa,SAAU,SAAQ,SAAS,CAAC,cAAc,EAAE,cAAc,CAAC;IACpE,MAAM,CAAC,WAAW,yCAAuB;IACzC,SAAS,CAAC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAGnD,MAAM,CAAC,YAAY;;;;MAIjB;gBAEU,KAAK,EAAE,cAAc;IAQjC,iBAAiB;IAUjB,kBAAkB,CAAC,SAAS,EAAE,cAAc;IAM5C,oBAAoB;IAQpB,MAAM;CAoET;AAED,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"Indicator.d.ts","sourceRoot":"","sources":["../../src/components/Indicator.tsx"],"names":[],"mappings":"AAmCA,OAAO,KAA0C,MAAM,OAAO,CAAC;AAG/D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,CAAC;AAE1B,MAAM,WAAW,cAAc;IAC3B;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qFAAqF;IACrF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8FAA8F;IAC9F,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,2DAA2D;IAC3D,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,gDAAgD;IAChD,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAE5B;;;;OAIG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAExB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC9B;AAiBD,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,CAyG9C,CAAC;AAEF,eAAe,SAAS,CAAC"}
@@ -1 +1 @@
1
- import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React,{Component}from"react";import{EventEmitterContext}from"../core/EventEmitterContext";import{IndicatorColor}from"../core/IndicatorColor";export{IndicatorColor};export class Indicator extends Component{constructor(e){super(e),Object.defineProperty(this,"unsubscribeTopicId",{enumerable:!0,configurable:!0,writable:!0,value:null}),this.state={subscribedValue:e.value,fontSize:"100%"}}componentDidMount(){const{topic:e}=this.props;if(e&&null===this.unsubscribeTopicId){const{subscribe:t}=this.context;this.unsubscribeTopicId=t(e,e=>{this.setState({subscribedValue:e})})}}componentDidUpdate(e){e.value!==this.props.value&&this.setState({subscribedValue:this.props.value})}componentWillUnmount(){if(null!==this.unsubscribeTopicId){const{unsubscribe:e}=this.context;e(this.unsubscribeTopicId),this.unsubscribeTopicId=null}}render(){const{label:e,value:t,onColor:o,offColor:r,invalidColor:s}=this.props,{subscribedValue:i}=this.state;let n,a=i;switch(void 0!==t&&(a=t),a){case!0:n=o;break;case!1:n=r;break;default:n=s}return _jsxs("div",{className:"p-inputgroup",style:{alignItems:"center",width:"auto",flex:"0 0 auto"},children:[_jsx("span",{className:"p-inputgroup-addon",style:{backgroundColor:n,width:"22px"},children:" "}),_jsx("span",{className:"p-inputgroup-addon",children:e})]})}}Object.defineProperty(Indicator,"contextType",{enumerable:!0,configurable:!0,writable:!0,value:EventEmitterContext}),Object.defineProperty(Indicator,"defaultProps",{enumerable:!0,configurable:!0,writable:!0,value:{onColor:"green",offColor:"gray",invalidColor:"black"}});export default Indicator;
1
+ import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React,{useContext,useEffect,useState}from"react";import clsx from"clsx";import{EventEmitterContext}from"../core/EventEmitterContext";import{IndicatorColor}from"../core/IndicatorColor";export{IndicatorColor};const pickColor=(o,t,r,e)=>!0===o?t:!1===o?r:e;export const Indicator=({value:o,onColor:t=IndicatorColor.IndicatorGreen,offColor:r=IndicatorColor.IndicatorOff,invalidColor:e=IndicatorColor.IndicatorInvalid,topic:n,className:i,style:s,label:a,children:c})=>{const{subscribe:l,unsubscribe:d}=useContext(EventEmitterContext),[x,p]=useState(void 0);useEffect(()=>{if(!n||!l)return;const o=l(n,o=>{p(null==o?void 0:!!o)});return()=>{try{d&&void 0!==o&&d(o)}catch{}}},[n,l,d]);const u=pickColor(void 0!==o?o:x,t,r,e);if(null!=c){const o={backgroundColor:u,color:"white",display:"inline-flex",alignItems:"center",justifyContent:"center",borderRadius:0,boxShadow:"inset 2px 2px 3px rgba(0, 0, 0, 0.55), inset -1px -1px 2px rgba(255, 255, 255, 0.20)",boxSizing:"border-box",...s};return _jsx("span",{className:clsx("indicator",i),style:o,role:"status","aria-label":"string"==typeof a?a:void 0,children:c})}const m={alignItems:"center",width:"auto",flex:"0 0 auto",...s},f={backgroundColor:u,width:"22px",borderRadius:0,boxShadow:"inset 1px 1px 2px rgba(0, 0, 0, 0.5), inset -1px -1px 1px rgba(255, 255, 255, 0.18)"};return _jsxs("div",{className:clsx("p-inputgroup indicator",i),style:m,role:"status",children:[_jsx("span",{className:"p-inputgroup-addon",style:f,children:" "}),void 0!==a&&_jsx("span",{className:"p-inputgroup-addon",children:a})]})};export default Indicator;
@@ -18,6 +18,13 @@ export interface AmsRole {
18
18
  description: string | null;
19
19
  /** Test method IDs whose start_test will pick up an asset in this role. */
20
20
  used_by: string[];
21
+ /** Module names whose configs reference this role via
22
+ * `${ams.by_location.<location>.*}` placeholders. Surfaces in the
23
+ * AIS Role dropdown so the operator can see *why* a role exists
24
+ * even when no test method directly resolves it (e.g., a load_cell
25
+ * feeding NI bridge channel calibration). Empty for purely
26
+ * test-method-driven roles. */
27
+ used_by_modules: string[];
21
28
  }
22
29
  export type AmsRoleRegistry = {
23
30
  [assetType: string]: AmsRole[];
@@ -1 +1 @@
1
- {"version":3,"file":"AmsProvider.d.ts","sourceRoot":"","sources":["../../../src/components/ams/AmsProvider.tsx"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,EAOV,KAAK,SAAS,EACjB,MAAM,OAAO,CAAC;AAQf,MAAM,MAAM,aAAa,GAAG,GAAG,CAAC;AAChC,MAAM,MAAM,iBAAiB,GAAG;IAAE,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,CAAA;CAAE,CAAC;AAEvE;;;;;GAKG;AACH,MAAM,WAAW,OAAO;IACpB,kEAAkE;IAClE,QAAQ,EAAE,MAAM,CAAC;IACjB,+DAA+D;IAC/D,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,4DAA4D;IAC5D,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,2EAA2E;IAC3E,OAAO,EAAE,MAAM,EAAE,CAAC;CACrB;AACD,MAAM,MAAM,eAAe,GAAG;IAAE,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,EAAE,CAAA;CAAE,CAAC;AAEjE,MAAM,WAAW,SAAS;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,QAAQ,GAAG,SAAS,GAAG,iBAAiB,CAAC;IACjD,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;CACzC;AAED,MAAM,WAAW,YAAY;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC5B,OAAO,EAAE,iBAAiB,CAAC;IAC3B,aAAa,EAAE,OAAO,CAAC;IACvB;;;;OAIG;IACH,KAAK,EAAE,eAAe,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,SAAS,CAAC;IAClB,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;IACpD,gBAAgB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACzD,eAAe,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;IACzE,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;IACpD,SAAS,EAAE,YAAY,CAAC;IACxB,YAAY,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;CACxD;AA0BD,MAAM,WAAW,gBAAgB;IAC7B,QAAQ,EAAE,SAAS,CAAC;CACvB;AAED,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAmIlD,CAAC;AAMF,eAAO,MAAM,MAAM,uBAAwC,CAAC;AAC5D,eAAO,MAAM,aAAa,yBAAyC,CAAC;AACpE,eAAO,MAAM,WAAW,uBAAyC,CAAC;AAClE,eAAO,MAAM,YAAY,iBAAyC,CAAC;AACnE,eAAO,MAAM,YAAY,uBAAyC,CAAC;AACnE,eAAO,MAAM,eAAe,wCA7KF,OAAO,CAAC,YAAY,CAAC,KAAK,IAAI,CAgLvD,CAAC"}
1
+ {"version":3,"file":"AmsProvider.d.ts","sourceRoot":"","sources":["../../../src/components/ams/AmsProvider.tsx"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,EAOV,KAAK,SAAS,EACjB,MAAM,OAAO,CAAC;AAQf,MAAM,MAAM,aAAa,GAAG,GAAG,CAAC;AAChC,MAAM,MAAM,iBAAiB,GAAG;IAAE,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,CAAA;CAAE,CAAC;AAEvE;;;;;GAKG;AACH,MAAM,WAAW,OAAO;IACpB,kEAAkE;IAClE,QAAQ,EAAE,MAAM,CAAC;IACjB,+DAA+D;IAC/D,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,4DAA4D;IAC5D,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,2EAA2E;IAC3E,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB;;;;;oCAKgC;IAChC,eAAe,EAAE,MAAM,EAAE,CAAC;CAC7B;AACD,MAAM,MAAM,eAAe,GAAG;IAAE,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,EAAE,CAAA;CAAE,CAAC;AAEjE,MAAM,WAAW,SAAS;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,QAAQ,GAAG,SAAS,GAAG,iBAAiB,CAAC;IACjD,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;CACzC;AAED,MAAM,WAAW,YAAY;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC5B,OAAO,EAAE,iBAAiB,CAAC;IAC3B,aAAa,EAAE,OAAO,CAAC;IACvB;;;;OAIG;IACH,KAAK,EAAE,eAAe,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,SAAS,CAAC;IAClB,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;IACpD,gBAAgB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACzD,eAAe,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;IACzE,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;IACpD,SAAS,EAAE,YAAY,CAAC;IACxB,YAAY,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;CACxD;AA0BD,MAAM,WAAW,gBAAgB;IAC7B,QAAQ,EAAE,SAAS,CAAC;CACvB;AAED,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAmIlD,CAAC;AAMF,eAAO,MAAM,MAAM,uBAAwC,CAAC;AAC5D,eAAO,MAAM,aAAa,yBAAyC,CAAC;AACpE,eAAO,MAAM,WAAW,uBAAyC,CAAC;AAClE,eAAO,MAAM,YAAY,iBAAyC,CAAC;AACnE,eAAO,MAAM,YAAY,uBAAyC,CAAC;AACnE,eAAO,MAAM,eAAe,wCA7KF,OAAO,CAAC,YAAY,CAAC,KAAK,IAAI,CAgLvD,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"AssetDetailView.d.ts","sourceRoot":"","sources":["../../../src/components/ams/AssetDetailView.tsx"],"names":[],"mappings":"AAQA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAOnD,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EA4FnC,CAAC"}
1
+ {"version":3,"file":"AssetDetailView.d.ts","sourceRoot":"","sources":["../../../src/components/ams/AssetDetailView.tsx"],"names":[],"mappings":"AAQA,OAAO,KAA0C,MAAM,OAAO,CAAC;AAU/D,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAwPnC,CAAC"}
@@ -1 +1 @@
1
- import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React,{useEffect,useState}from"react";import{Button}from"primereact/button";import{DataTable}from"primereact/datatable";import{Column}from"primereact/column";import{useAms}from"./AmsProvider";import{CalibrationEntryDialog}from"./CalibrationEntryDialog";export const AssetDetailView=()=>{const{selection:e,schemas:s,roles:t,readAsset:a,listCalibrations:r,readCalibration:i,readUsage:l}=useAms(),[n,o]=useState(null),[d,c]=useState([]),[_,m]=useState(null),[p,x]=useState(!1),u=async()=>{if(!e.assetId)return o(null),c([]),void m(null);const s=await a(e.assetId);o(s);const t=await r(e.assetId),n=await Promise.all(t.map(s=>i(e.assetId,s)));c(n.filter(Boolean));const d=await l(e.assetId);m(d)};if(useEffect(()=>{u()},[e.assetId]),!e.assetId)return _jsx("div",{style:{padding:"1rem",color:"#9ca3af"},children:"Select an asset from the registry to see its details."});if(!n)return _jsx("div",{style:{padding:"1rem"},children:"Loading…"});const f=s[n.asset_type]?.label??n.asset_type,j=t[n.asset_type]?.find(e=>e.location===n.location),h=j?j.label??j.location:n.location;return _jsxs("div",{style:{display:"flex",flexDirection:"column",gap:"1rem"},children:[_jsxs("div",{style:{display:"grid",gridTemplateColumns:"auto 1fr auto 1fr",gap:"0.5rem 1.5rem",alignItems:"baseline"},children:[_jsx("strong",{children:"Asset ID"})," ",_jsx("span",{children:n.asset_id}),_jsx("strong",{children:"Type"})," ",_jsx("span",{children:f}),_jsx("strong",{children:"Serial"})," ",_jsx("span",{children:n.serial||_jsx("em",{style:{color:"#9ca3af"},children:"(none)"})}),_jsx("strong",{children:"Role"})," ",_jsx("span",{children:h||_jsx("em",{style:{color:"#9ca3af"},children:"(none)"})}),_jsx("strong",{children:"Status"})," ",_jsx("span",{children:n.status}),_jsx("strong",{children:"Installed"}),_jsx("span",{children:n.install_date?new Date(n.install_date).toLocaleString():"—"}),_jsx("strong",{children:"Current Cal"}),_jsx("span",{children:n.current_calibration_id??_jsx("em",{style:{color:"#f59e0b"},children:"none"})}),_jsx("strong",{children:"Cycles"})," ",_jsx("span",{children:_?.cycles??0})]}),_jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center"},children:[_jsx("h4",{style:{margin:0},children:"Calibration History"}),_jsx(Button,{label:"+ Calibration",icon:"pi pi-plus",onClick:()=>x(!0)})]}),_jsxs(DataTable,{value:d,size:"small",stripedRows:!0,emptyMessage:"No calibrations recorded for this asset.",children:[_jsx(Column,{field:"cal_id",header:"Cal ID"}),_jsx(Column,{field:"performed_at",header:"Performed",body:e=>e.performed_at?new Date(e.performed_at).toLocaleString():"—"}),_jsx(Column,{field:"performed_by",header:"By"}),_jsx(Column,{field:"expires_at",header:"Expires",body:e=>e.expires_at?new Date(e.expires_at).toLocaleDateString():"—"}),_jsx(Column,{field:"cert_ref",header:"Cert"}),_jsx(Column,{header:"Values",body:e=>_jsx("code",{style:{fontSize:"0.75rem"},children:JSON.stringify(e.values)})})]}),_jsx(CalibrationEntryDialog,{visible:p,assetId:n.asset_id,assetType:n.asset_type,onHide:()=>x(!1),onAdded:()=>{u()}})]})};
1
+ import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React,{useContext,useEffect,useState}from"react";import{Button}from"primereact/button";import{DataTable}from"primereact/datatable";import{Column}from"primereact/column";import{ConfirmDialog,confirmDialog}from"primereact/confirmdialog";import{EventEmitterContext}from"../../core/EventEmitterContext";import{MessageType}from"../../hub/CommandMessage";import{useAms}from"./AmsProvider";import{CalibrationEntryDialog}from"./CalibrationEntryDialog";export const AssetDetailView=()=>{const{selection:e,schemas:t,roles:s,readAsset:r,listCalibrations:a,readCalibration:i,readUsage:l,refreshAssets:n,setSelection:o}=useAms(),{invoke:d}=useContext(EventEmitterContext),[c,m]=useState(null),[_,p]=useState([]),[u,h]=useState(null),[x,f]=useState(!1),[y,j]=useState(!1),g=async()=>{if(!e.assetId)return m(null),p([]),void h(null);const t=await r(e.assetId);m(t);const s=await a(e.assetId),n=await Promise.all(s.map(t=>i(e.assetId,t)));p(n.filter(Boolean));const o=await l(e.assetId);h(o)};if(useEffect(()=>{g()},[e.assetId]),!e.assetId)return _jsx("div",{style:{padding:"1rem",color:"#9ca3af"},children:"Select an asset from the registry to see its details."});if(!c)return _jsx("div",{style:{padding:"1rem"},children:"Loading…"});const b=t[c.asset_type]?.label??c.asset_type,v=s[c.asset_type]?.find(e=>e.location===c.location),C=v?v.label??v.location:c.location,S=Array.isArray(t[c.asset_type]?.fields)?t[c.asset_type].fields:[],w=c.custom??{},A=v?.used_by_modules??[];return _jsxs("div",{style:{display:"flex",flexDirection:"column",gap:"1rem"},children:[_jsxs("div",{style:{display:"grid",gridTemplateColumns:"auto 1fr auto 1fr",gap:"0.5rem 1.5rem",alignItems:"baseline"},children:[_jsx("strong",{children:"Asset ID"})," ",_jsx("span",{children:c.asset_id}),_jsx("strong",{children:"Type"})," ",_jsx("span",{children:b}),_jsx("strong",{children:"Serial"})," ",_jsx("span",{children:c.serial||_jsx("em",{style:{color:"#9ca3af"},children:"(none)"})}),_jsx("strong",{children:"Role"})," ",_jsx("span",{children:C||_jsx("em",{style:{color:"#9ca3af"},children:"(none)"})}),_jsx("strong",{children:"Status"})," ",_jsx("span",{children:c.status}),_jsx("strong",{children:"Installed"}),_jsx("span",{children:c.install_date?new Date(c.install_date).toLocaleString():"—"}),_jsx("strong",{children:"Current Cal"}),_jsx("span",{children:c.current_calibration_id??_jsx("em",{style:{color:"#f59e0b"},children:"none"})}),_jsx("strong",{children:"Cycles"})," ",_jsx("span",{children:u?.cycles??0})]}),A.length>0&&_jsxs("div",{style:{fontSize:"0.875rem",color:"#34d399"},children:["✓ Feeds module ",1===A.length?"config":"configs",":"," ",_jsx("strong",{children:A.join(", ")})," — ","their ",_jsxs("code",{children:["$","${ams.by_location."+c.location+".*}"]})," ","placeholders will resolve to the values below."]}),S.length>0&&_jsxs("div",{children:[_jsx("h4",{style:{margin:"0 0 0.5rem 0"},children:"Nameplate"}),_jsx("div",{style:{display:"grid",gridTemplateColumns:"auto 1fr",gap:"0.25rem 1rem",alignItems:"baseline",fontSize:"0.9rem"},children:S.map(e=>{const t=w[e.name],s=null!=t&&""!==t,r=e.label??e.name,a=s?e.units?`${t} ${e.units}`:String(t):"(not set)";return _jsxs(React.Fragment,{children:[_jsx("strong",{title:e.description??void 0,children:r}),_jsx("span",{style:{color:s?void 0:"#f59e0b"},children:a})]},e.name)})})]}),_jsx(SubLocationsPanel,{schema:t[c.asset_type]?.sub_locations,values:c.sub_locations}),_jsx(SubLocationsCalibrationPanel,{schema:t[c.asset_type]?.sub_locations,currentCalibration:_.find(e=>e.cal_id===c.current_calibration_id)}),_jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center"},children:[_jsx("h4",{style:{margin:0},children:"Calibration History"}),_jsxs("div",{style:{display:"flex",gap:"0.5rem"},children:["active"===c.status&&_jsx(Button,{label:"Retire",icon:"pi pi-power-off",severity:"warning",outlined:!0,onClick:async()=>{if(c)try{const e=await d("ams.update_asset",MessageType.Request,{asset_id:c.asset_id,status:"retired"});e?.success&&(await n(),await g())}catch(e){}},tooltip:"Mark inactive. The asset stays on disk; deletion is a separate action available after retirement.",tooltipOptions:{position:"left"}}),"retired"===c.status&&_jsx(Button,{label:"Delete",icon:"pi pi-trash",severity:"danger",outlined:!0,loading:y,onClick:()=>{c&&confirmDialog({message:_jsxs("div",{children:[_jsxs("p",{style:{marginTop:0},children:["Permanently delete asset ",_jsx("code",{children:c.asset_id}),"?"]}),_jsx("p",{style:{marginBottom:0,fontSize:"0.875rem",color:"#9ca3af"},children:"This removes the AMS record (nameplate, calibration history, usage counters). Historical test records that referenced this asset are unaffected — they carry the full asset and calibration data inline."})]}),header:"Delete asset",icon:"pi pi-exclamation-triangle",acceptLabel:"Delete",rejectLabel:"Cancel",acceptClassName:"p-button-danger",accept:()=>{(async()=>{if(c){j(!0);try{const e=await d("ams.delete_asset",MessageType.Request,{asset_id:c.asset_id});e?.success?(o({assetType:null,assetId:null}),await n()):alert(`Delete failed: ${e?.error_message??"unknown error"}`)}catch(e){alert(`Delete threw: ${e?.message??e}`)}finally{j(!1)}}})()}})},tooltip:"Permanent. Removes the AMS record; historical test snapshots are preserved inline.",tooltipOptions:{position:"left"}}),_jsx(Button,{label:"+ Calibration",icon:"pi pi-plus",onClick:()=>f(!0)})]})]}),_jsx(ConfirmDialog,{}),_jsxs(DataTable,{value:_,size:"small",stripedRows:!0,emptyMessage:"No calibrations recorded for this asset.",children:[_jsx(Column,{field:"cal_id",header:"Cal ID"}),_jsx(Column,{field:"performed_at",header:"Performed",body:e=>e.performed_at?new Date(e.performed_at).toLocaleString():"—"}),_jsx(Column,{field:"performed_by",header:"By"}),_jsx(Column,{field:"expires_at",header:"Expires",body:e=>e.expires_at?new Date(e.expires_at).toLocaleDateString():"—"}),_jsx(Column,{field:"cert_ref",header:"Cert"}),_jsx(Column,{header:"Values",body:e=>_jsx("code",{style:{fontSize:"0.75rem"},children:JSON.stringify(e.values)})})]}),_jsx(CalibrationEntryDialog,{visible:x,assetId:c.asset_id,assetType:c.asset_type,onHide:()=>f(!1),onAdded:()=>{g()}})]})};const SubLocationsPanel=({schema:e,values:t})=>{if(!e||!Array.isArray(e.keys)||!Array.isArray(e.fields))return null;const s=t&&"object"==typeof t?t:{};return _jsxs("div",{children:[_jsx("h4",{style:{margin:"0 0 0.5rem 0"},children:e.label??"Sub-locations"}),_jsx("div",{style:{overflowX:"auto"},children:_jsxs("table",{style:{width:"100%",borderCollapse:"collapse",fontSize:"0.875rem"},children:[_jsx("thead",{children:_jsxs("tr",{children:[_jsx("th",{style:{textAlign:"left",padding:"0.25rem 0.5rem",borderBottom:"1px solid var(--surface-border)"},children:e.key_label??"Key"}),e.fields.map(e=>_jsxs("th",{title:e.description??void 0,style:{textAlign:"left",padding:"0.25rem 0.5rem",borderBottom:"1px solid var(--surface-border)"},children:[e.label??e.name,e.units?` [${e.units}]`:""]},e.name))]})}),_jsx("tbody",{children:e.keys.map(t=>{const r=s[t]??{};return _jsxs("tr",{children:[_jsx("td",{style:{padding:"0.25rem 0.5rem",fontWeight:600},children:t}),e.fields.map(e=>{const t=r[e.name],s=null!=t&&""!==t;return _jsx("td",{style:{padding:"0.25rem 0.5rem",color:s?void 0:"#f59e0b"},children:s?String(t):"(not set)"},e.name)})]},t)})})]})})]})},SubLocationsCalibrationPanel=({schema:e,currentCalibration:t})=>{if(!e||!Array.isArray(e.keys)||!Array.isArray(e.calibration_fields)||0===e.calibration_fields.length)return null;if(!t)return null;const s=t.values&&"object"==typeof t.values?t.values:{};return _jsxs("div",{children:[_jsx("h4",{style:{margin:"0 0 0.5rem 0"},children:"Current Calibration — Per-axis Values"}),_jsx("div",{style:{overflowX:"auto"},children:_jsxs("table",{style:{width:"100%",borderCollapse:"collapse",fontSize:"0.875rem"},children:[_jsx("thead",{children:_jsxs("tr",{children:[_jsx("th",{style:{textAlign:"left",padding:"0.25rem 0.5rem",borderBottom:"1px solid var(--surface-border)"},children:e.key_label??"Key"}),e.calibration_fields.map(e=>_jsxs("th",{style:{textAlign:"left",padding:"0.25rem 0.5rem",borderBottom:"1px solid var(--surface-border)"},children:[e.label??e.name,e.units?` [${e.units}]`:""]},e.name))]})}),_jsx("tbody",{children:e.keys.map(t=>{const r=s[t]??{};return _jsxs("tr",{children:[_jsx("td",{style:{padding:"0.25rem 0.5rem",fontWeight:600},children:t}),e.calibration_fields.map(e=>{const t=r[e.name],s=null!=t&&""!==t;return _jsx("td",{style:{padding:"0.25rem 0.5rem",color:s?void 0:"#f59e0b"},children:s?String(t):"(not set)"},e.name)})]},t)})})]})})]})};
@@ -1 +1 @@
1
- {"version":3,"file":"AssetRegistryTable.d.ts","sourceRoot":"","sources":["../../../src/components/ams/AssetRegistryTable.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAwC,MAAM,OAAO,CAAC;AA+C7D,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAmRtC,CAAC"}
1
+ {"version":3,"file":"AssetRegistryTable.d.ts","sourceRoot":"","sources":["../../../src/components/ams/AssetRegistryTable.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAmD,MAAM,OAAO,CAAC;AA6HxE,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAqftC,CAAC"}
@@ -1 +1 @@
1
- import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import React,{useContext,useMemo,useState}from"react";import{Button}from"primereact/button";import{DataTable}from"primereact/datatable";import{Column}from"primereact/column";import{Dropdown}from"primereact/dropdown";import{InputText}from"primereact/inputtext";import{Dialog}from"primereact/dialog";import{EventEmitterContext}from"../../core/EventEmitterContext";import{MessageType}from"../../hub/CommandMessage";import{useAms}from"./AmsProvider";const ROLE_OTHER="__other__",EMPTY_ADD={open:!1,assetType:"",serial:"",roleSelection:"",location:""};function roleLabel(e){return e.label??e.location}function roleUsageSummary(e){return 0===e.used_by.length?"No test methods reference this role.":1===e.used_by.length?`Used by: ${e.used_by[0]}`:`Used by: ${e.used_by.join(", ")}`}export const AssetRegistryTable=()=>{const{schemas:e,roles:t,assets:s,refreshAssets:l,setSelection:a,selection:o}=useAms(),{invoke:r}=useContext(EventEmitterContext),[n,i]=useState(null),[c,d]=useState(null),[p,u]=useState(EMPTY_ADD),m=useMemo(()=>Object.keys(e).map(t=>({label:e[t]?.label??t,value:t})),[e]),_=useMemo(()=>p.assetType?t[p.assetType]??[]:[],[p.assetType,t]),h=_.length>0,y=useMemo(()=>{const e=_.map(e=>({label:roleLabel(e),value:e.location}));return e.push({label:"Other (advanced — type a custom role)",value:ROLE_OTHER}),e},[_]),x=useMemo(()=>p.roleSelection===ROLE_OTHER?null:_.find(e=>e.location===p.roleSelection)??null,[p.roleSelection,_]),b=useMemo(()=>s.filter(e=>(!n||e.asset_type===n)&&(!c||e.status===c)),[s,n,c]),g=!p.assetType||h&&(""===p.roleSelection||p.roleSelection===ROLE_OTHER&&!p.location.trim());return _jsxs("div",{style:{display:"flex",flexDirection:"column",gap:"0.5rem"},children:[_jsxs("div",{style:{display:"flex",gap:"0.75rem",alignItems:"center"},children:[_jsx(Dropdown,{value:n,options:[{label:"All Types",value:null},...m],onChange:e=>i(e.value),placeholder:"Filter by type"}),_jsx(Dropdown,{value:c,options:[{label:"All Statuses",value:null},{label:"Active",value:"active"},{label:"Out for Service",value:"out_for_service"},{label:"Retired",value:"retired"}],onChange:e=>d(e.value),placeholder:"Filter by status"}),_jsx("span",{style:{marginLeft:"auto"},children:_jsx(Button,{icon:"pi pi-plus",label:"Add Asset",onClick:()=>u(e=>({...e,open:!0})),disabled:0===m.length})})]}),_jsxs(DataTable,{value:b,selectionMode:"single",selection:b.find(e=>e.asset_id===o.assetId)??null,onSelectionChange:e=>{const t=e.value;t&&a({assetType:t.asset_type,assetId:t.asset_id})},dataKey:"asset_id",emptyMessage:0===m.length?"AMS not enabled in this project (no asset_types declared).":"No assets registered yet.",size:"small",stripedRows:!0,children:[_jsx(Column,{field:"asset_id",header:"Asset ID"}),_jsx(Column,{field:"asset_type",header:"Type",body:t=>e[t.asset_type]?.label??t.asset_type}),_jsx(Column,{field:"serial",header:"Serial"}),_jsx(Column,{field:"location",header:"Role",body:e=>e.location?((e,s)=>{const l=(t[e]??[]).find(e=>e.location===s);return l?roleLabel(l):s})(e.asset_type,e.location):_jsx("span",{style:{color:"#9ca3af"},children:"—"})}),_jsx(Column,{field:"status",header:"Status"}),_jsx(Column,{header:"Calibration",body:e=>e.current_calibration_id?_jsx("span",{title:e.current_calibration_id,children:"✓"}):_jsx("span",{style:{color:"#f59e0b"},children:"none"})})]}),_jsxs(Dialog,{header:"Add New Asset",visible:p.open,style:{width:"32rem"},onHide:()=>u(EMPTY_ADD),footer:_jsxs(_Fragment,{children:[_jsx(Button,{label:"Cancel",severity:"secondary",onClick:()=>u(EMPTY_ADD)}),_jsx(Button,{label:"Create",icon:"pi pi-check",onClick:async()=>{if(p.assetType)try{const e=await r("ams.create_asset",MessageType.Request,{asset_type:p.assetType,serial:p.serial,location:p.location});e?.success&&(u(EMPTY_ADD),await l(),e.data?.asset_id&&a({assetType:p.assetType,assetId:e.data.asset_id}))}catch(e){}},disabled:g})]}),children:[_jsxs("div",{style:{display:"grid",gridTemplateColumns:"auto 1fr",gap:"0.5rem 1rem",alignItems:"center"},children:[_jsx("label",{children:"Type *"}),_jsx(Dropdown,{value:p.assetType,options:m,onChange:e=>(e=>{const s=t[e]??[];1===s.length?u(t=>({...t,assetType:e,roleSelection:s[0].location,location:s[0].location})):u(t=>({...t,assetType:e,roleSelection:"",location:""}))})(e.value),placeholder:"Choose asset type"}),_jsx("label",{children:"Serial"}),_jsx(InputText,{value:p.serial,onChange:e=>u(t=>({...t,serial:e.target.value}))}),h&&_jsxs(_Fragment,{children:[_jsx("label",{children:"Role *"}),_jsx(Dropdown,{value:p.roleSelection,options:y,onChange:e=>{return t=e.value,void u(t===ROLE_OTHER?e=>({...e,roleSelection:ROLE_OTHER,location:""}):e=>({...e,roleSelection:t,location:t}));var t},placeholder:"Choose where this asset is mounted"}),p.roleSelection===ROLE_OTHER&&_jsxs(_Fragment,{children:[_jsx("label",{children:"Custom role"}),_jsx(InputText,{value:p.location,placeholder:"e.g. tsdr_secondary",onChange:e=>u(t=>({...t,location:e.target.value}))})]})]})]}),_jsxs("div",{style:{fontSize:"0.875rem",color:"#9ca3af",marginTop:"1rem"},children:[h&&x&&_jsxs(_Fragment,{children:[x.description&&_jsx("p",{style:{margin:"0 0 0.5rem 0"},children:x.description}),_jsxs("p",{style:{margin:"0 0 0.5rem 0",color:"#34d399"},children:["✓ ",roleUsageSummary(x)]})]}),h&&p.roleSelection===ROLE_OTHER&&_jsx("p",{style:{margin:"0 0 0.5rem 0",color:"#f59e0b"},children:"⚠ No test method on this machine references this custom role yet. The asset will be registered but won't be picked up at start_test unless you add an asset_ref to a test method's project.json."}),!h&&p.assetType&&_jsx("p",{style:{margin:"0 0 0.5rem 0"},children:"This asset type isn't selected by physical role on this machine — test methods reference it by ID instead. Just register the asset and pick it by ID on the Test Setup form when running a test."}),_jsxs("p",{style:{margin:0},children:["The asset_id is generated by the server (format:"," ",_jsxs("code",{children:[p.assetType?e[p.assetType]?.id_prefix??"A-":"A-","YYYYMMDDTHHMMSS"]}),"). Manufacturer serial is recorded for traceability but is not used as the unique key."]})]})]})]})};
1
+ import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import React,{useContext,useEffect,useMemo,useState}from"react";import{Button}from"primereact/button";import{DataTable}from"primereact/datatable";import{Column}from"primereact/column";import{Dropdown}from"primereact/dropdown";import{InputText}from"primereact/inputtext";import{Dialog}from"primereact/dialog";import{EventEmitterContext}from"../../core/EventEmitterContext";import{MessageType}from"../../hub/CommandMessage";import{useAms}from"./AmsProvider";const ROLE_OTHER="__other__",EMPTY_ADD={open:!1,assetType:"",serial:"",roleSelection:"",location:"",customFields:{},subLocationFields:{}};function roleLabel(e){return e.label??e.location}function roleUsageSummary(e){const s=[];return e.used_by.length>0&&s.push(`Used by test method${1===e.used_by.length?"":"s"}: ${e.used_by.join(", ")}`),e.used_by_modules.length>0&&s.push(`Used by module${1===e.used_by_modules.length?"":"s"}: ${e.used_by_modules.join(", ")}`),0===s.length?"Not referenced by any test method or module.":s.join(" • ")}function fieldsFor(e,s){const t=e?.[s]?.fields;return Array.isArray(t)?t:[]}function subLocationsFor(e,s){const t=e?.[s]?.sub_locations;return t&&Array.isArray(t.keys)&&Array.isArray(t.fields)?t:null}function coerceField(e,s){if(void 0!==s&&""!==s)switch(e.type){case"f32":case"f64":case"i8":case"i16":case"i32":case"i64":case"u8":case"u16":case"u32":case"u64":{const e=Number(s);return Number.isFinite(e)?e:void 0}case"bool":return"true"===s||"1"===s;default:return s}}export const AssetRegistryTable=()=>{const{schemas:e,roles:s,assets:t,refreshAssets:o,setSelection:l,selection:a}=useAms(),{invoke:r}=useContext(EventEmitterContext),[i,n]=useState(null),[c,d]=useState(null),[u,m]=useState(EMPTY_ADD);useEffect(()=>{const e=e=>{const s=e.detail,t=s?.assetType??"",o=s?.location??"";t&&m({...EMPTY_ADD,open:!0,assetType:t,roleSelection:o,location:o})};return window.addEventListener("ams:prefill-add",e),()=>window.removeEventListener("ams:prefill-add",e)},[]);const p=useMemo(()=>Object.keys(e).map(s=>({label:e[s]?.label??s,value:s})),[e]),y=useMemo(()=>u.assetType?s[u.assetType]??[]:[],[u.assetType,s]),_=y.length>0,h=useMemo(()=>{const e=y.map(e=>({label:roleLabel(e),value:e.location}));return e.push({label:"Other (advanced — type a custom role)",value:ROLE_OTHER}),e},[y]),b=useMemo(()=>u.roleSelection===ROLE_OTHER?null:y.find(e=>e.location===u.roleSelection)??null,[u.roleSelection,y]),f=useMemo(()=>t.filter(e=>(!i||e.asset_type===i)&&(!c||e.status===c)),[t,i,c]),x=useMemo(()=>fieldsFor(e,u.assetType),[e,u.assetType]),g=useMemo(()=>subLocationsFor(e,u.assetType),[e,u.assetType]),j=!u.assetType||_&&(""===u.roleSelection||u.roleSelection===ROLE_OTHER&&!u.location.trim())||x.some(e=>e.required&&!u.customFields[e.name]?.toString().trim())||(g?.keys.some(e=>g.fields.some(s=>s.required&&!u.subLocationFields[e]?.[s.name]?.toString().trim()))??!1);return _jsxs("div",{style:{display:"flex",flexDirection:"column",gap:"0.5rem"},children:[_jsxs("div",{style:{display:"flex",gap:"0.75rem",alignItems:"center"},children:[_jsx(Dropdown,{value:i,options:[{label:"All Types",value:null},...p],onChange:e=>n(e.value),placeholder:"Filter by type"}),_jsx(Dropdown,{value:c,options:[{label:"All Statuses",value:null},{label:"Active",value:"active"},{label:"Out for Service",value:"out_for_service"},{label:"Retired",value:"retired"}],onChange:e=>d(e.value),placeholder:"Filter by status"}),_jsx("span",{style:{marginLeft:"auto"},children:_jsx(Button,{icon:"pi pi-plus",label:"Add Asset",onClick:()=>m(e=>({...e,open:!0})),disabled:0===p.length})})]}),_jsxs(DataTable,{value:f,selectionMode:"single",selection:f.find(e=>e.asset_id===a.assetId)??null,onSelectionChange:e=>{const s=e.value;s&&l({assetType:s.asset_type,assetId:s.asset_id})},dataKey:"asset_id",emptyMessage:0===p.length?"AMS not enabled in this project (no asset_types declared).":"No assets registered yet.",size:"small",stripedRows:!0,children:[_jsx(Column,{field:"asset_id",header:"Asset ID"}),_jsx(Column,{field:"asset_type",header:"Type",body:s=>e[s.asset_type]?.label??s.asset_type}),_jsx(Column,{field:"serial",header:"Serial"}),_jsx(Column,{field:"location",header:"Role",body:e=>e.location?((e,t)=>{const o=(s[e]??[]).find(e=>e.location===t);return o?roleLabel(o):t})(e.asset_type,e.location):_jsx("span",{style:{color:"#9ca3af"},children:"—"})}),_jsx(Column,{field:"status",header:"Status"}),_jsx(Column,{header:"Calibration",body:e=>e.current_calibration_id?_jsx("span",{title:e.current_calibration_id,children:"✓"}):_jsx("span",{style:{color:"#f59e0b"},children:"none"})})]}),_jsxs(Dialog,{header:"Add New Asset",visible:u.open,style:{width:"32rem"},onHide:()=>m(EMPTY_ADD),footer:_jsxs(_Fragment,{children:[_jsx(Button,{label:"Cancel",severity:"secondary",onClick:()=>m(EMPTY_ADD)}),_jsx(Button,{label:"Create",icon:"pi pi-check",onClick:async()=>{if(!u.assetType)return;const e={};for(const s of x){const t=u.customFields[s.name];if(void 0!==t&&""!==t)switch(s.type){case"f32":case"f64":case"i8":case"i16":case"i32":case"i64":case"u8":case"u16":case"u32":case"u64":{const o=Number(t);Number.isFinite(o)&&(e[s.name]=o);break}case"bool":e[s.name]="true"===t||"1"===t;break;default:e[s.name]=t}}const s={};if(g)for(const e of g.keys){const t={};for(const s of g.fields){const o=coerceField(s,u.subLocationFields[e]?.[s.name]??"");void 0!==o&&(t[s.name]=o)}s[e]=t}const t={asset_type:u.assetType,serial:u.serial,location:u.location,custom:e};g&&(t.sub_locations=s);try{const e=await r("ams.create_asset",MessageType.Request,t);e?.success&&(m(EMPTY_ADD),await o(),e.data?.asset_id&&l({assetType:u.assetType,assetId:e.data.asset_id}))}catch(e){}},disabled:j})]}),children:[_jsxs("div",{style:{display:"grid",gridTemplateColumns:"auto 1fr",gap:"0.5rem 1rem",alignItems:"center"},children:[_jsx("label",{children:"Type *"}),_jsx(Dropdown,{value:u.assetType,options:p,onChange:e=>(e=>{const t=s[e]??[],o=1===t.length?{roleSelection:t[0].location,location:t[0].location}:{roleSelection:"",location:""};m(s=>({...s,assetType:e,...o,customFields:{},subLocationFields:{}}))})(e.value),placeholder:"Choose asset type"}),_jsx("label",{children:"Serial"}),_jsx(InputText,{value:u.serial,onChange:e=>m(s=>({...s,serial:e.target.value}))}),_&&_jsxs(_Fragment,{children:[_jsx("label",{children:"Role *"}),_jsx(Dropdown,{value:u.roleSelection,options:h,onChange:e=>{return s=e.value,void m(s===ROLE_OTHER?e=>({...e,roleSelection:ROLE_OTHER,location:""}):e=>({...e,roleSelection:s,location:s}));var s},placeholder:"Choose where this asset is mounted"}),u.roleSelection===ROLE_OTHER&&_jsxs(_Fragment,{children:[_jsx("label",{children:"Custom role"}),_jsx(InputText,{value:u.location,placeholder:"e.g. tsdr_secondary",onChange:e=>m(s=>({...s,location:e.target.value}))})]})]}),x.map(e=>{const s=e.label??e.name,t=e.units?`${s} [${e.units}]${e.required?" *":""}`:`${s}${e.required?" *":""}`,o="string"!==e.type&&"bool"!==e.type;return _jsxs(React.Fragment,{children:[_jsx("label",{title:e.description??void 0,children:t}),"bool"===e.type?_jsx(Dropdown,{value:u.customFields[e.name]??"",options:[{label:"true",value:"true"},{label:"false",value:"false"}],onChange:s=>m(t=>({...t,customFields:{...t.customFields,[e.name]:s.value}})),placeholder:"—"}):_jsx(InputText,{value:u.customFields[e.name]??"",keyfilter:o?"num":void 0,placeholder:e.description??void 0,onChange:s=>m(t=>({...t,customFields:{...t.customFields,[e.name]:s.target.value}}))})]},e.name)})]}),g&&_jsxs("div",{style:{marginTop:"1.5rem"},children:[_jsx("h4",{style:{margin:"0 0 0.5rem 0"},children:g.label??"Sub-locations"}),_jsx("div",{style:{overflowX:"auto"},children:_jsxs("table",{style:{width:"100%",borderCollapse:"collapse",fontSize:"0.875rem"},children:[_jsx("thead",{children:_jsxs("tr",{children:[_jsx("th",{style:{textAlign:"left",padding:"0.25rem 0.5rem",borderBottom:"1px solid var(--surface-border)"},children:g.key_label??"Key"}),g.fields.map(e=>_jsxs("th",{title:e.description??void 0,style:{textAlign:"left",padding:"0.25rem 0.5rem",borderBottom:"1px solid var(--surface-border)"},children:[e.label??e.name,e.units?` [${e.units}]`:"",e.required?" *":""]},e.name))]})}),_jsx("tbody",{children:g.keys.map(e=>_jsxs("tr",{children:[_jsx("td",{style:{padding:"0.25rem 0.5rem",fontWeight:600},children:e}),g.fields.map(s=>{const t=u.subLocationFields[e]?.[s.name]??"",o="string"!==s.type&&"bool"!==s.type;return _jsx("td",{style:{padding:"0.25rem 0.5rem"},children:_jsx(InputText,{value:t,keyfilter:o?"num":void 0,onChange:t=>{const o=t.target.value;m(t=>({...t,subLocationFields:{...t.subLocationFields,[e]:{...t.subLocationFields[e]??{},[s.name]:o}}}))},style:{width:"100%"}})},s.name)})]},e))})]})})]}),_jsxs("div",{style:{fontSize:"0.875rem",color:"#9ca3af",marginTop:"1rem"},children:[_&&b&&_jsxs(_Fragment,{children:[b.description&&_jsx("p",{style:{margin:"0 0 0.5rem 0"},children:b.description}),_jsxs("p",{style:{margin:"0 0 0.5rem 0",color:"#34d399"},children:["✓ ",roleUsageSummary(b)]})]}),_&&u.roleSelection===ROLE_OTHER&&_jsx("p",{style:{margin:"0 0 0.5rem 0",color:"#f59e0b"},children:"⚠ No test method on this machine references this custom role yet. The asset will be registered but won't be picked up at start_test unless you add an asset_ref to a test method's project.json."}),!_&&u.assetType&&_jsx("p",{style:{margin:"0 0 0.5rem 0"},children:"This asset type isn't selected by physical role on this machine — test methods reference it by ID instead. Just register the asset and pick it by ID on the Test Setup form when running a test."}),_jsxs("p",{style:{margin:0},children:["The asset_id is generated by the server (format:"," ",_jsxs("code",{children:[u.assetType?e[u.assetType]?.id_prefix??"A-":"A-","YYYYMMDDTHHMMSS"]}),"). Manufacturer serial is recorded for traceability but is not used as the unique key."]})]})]})]})};
@@ -1 +1 @@
1
- {"version":3,"file":"CalibrationEntryDialog.d.ts","sourceRoot":"","sources":["../../../src/components/ams/CalibrationEntryDialog.tsx"],"names":[],"mappings":"AAUA,OAAO,KAA0C,MAAM,OAAO,CAAC;AAW/D,MAAM,WAAW,2BAA2B;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC;AAYD,eAAO,MAAM,sBAAsB,EAAE,KAAK,CAAC,EAAE,CAAC,2BAA2B,CA6JxE,CAAC"}
1
+ {"version":3,"file":"CalibrationEntryDialog.d.ts","sourceRoot":"","sources":["../../../src/components/ams/CalibrationEntryDialog.tsx"],"names":[],"mappings":"AAUA,OAAO,KAA0C,MAAM,OAAO,CAAC;AAW/D,MAAM,WAAW,2BAA2B;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC;AAwBD,eAAO,MAAM,sBAAsB,EAAE,KAAK,CAAC,EAAE,CAAC,2BAA2B,CAsRxE,CAAC"}
@@ -1 +1 @@
1
- import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import React,{useContext,useEffect,useState}from"react";import{Button}from"primereact/button";import{Dialog}from"primereact/dialog";import{InputText}from"primereact/inputtext";import{InputNumber}from"primereact/inputnumber";import{Calendar}from"primereact/calendar";import{Dropdown}from"primereact/dropdown";import{EventEmitterContext}from"../../core/EventEmitterContext";import{MessageType}from"../../hub/CommandMessage";import{useAmsSchemas}from"./AmsProvider";export const CalibrationEntryDialog=({visible:e,assetId:a,assetType:t,onHide:r,onAdded:n})=>{const s=useAmsSchemas(),{invoke:l}=useContext(EventEmitterContext),i=s[t]?.calibration_fields??[],[o,u]=useState({}),[m,c]=useState(""),[d,p]=useState(null),[x,g]=useState(""),[f,_]=useState(""),[v,h]=useState(!1),[b,j]=useState(null);useEffect(()=>{e&&(u({}),c(""),p(null),g(""),_(""),j(null))},[e]);return _jsxs(Dialog,{header:`Add Calibration — ${a}`,visible:e,onHide:r,style:{width:"40rem"},footer:_jsxs(_Fragment,{children:[_jsx(Button,{label:"Cancel",severity:"secondary",onClick:r,disabled:v}),_jsx(Button,{label:"Save",icon:"pi pi-check",onClick:async()=>{for(const e of i)if(e.required&&(void 0===o[e.name]||null===o[e.name]||""===o[e.name]))return void j(`Field "${e.label??e.name}" is required.`);h(!0),j(null);try{const e=await l("ams.add_calibration",MessageType.Request,{asset_id:a,performed_by:m,expires_at:d?d.toISOString():null,cert_ref:x,notes:f,values:o});e?.success?(n?.(e.data.cal_id),r()):j(e?.error_message??"add_calibration failed")}catch(e){j(String(e?.message??e))}finally{h(!1)}},loading:v})]}),children:[_jsxs("div",{style:{display:"grid",gridTemplateColumns:"auto 1fr",gap:"0.5rem 1rem",alignItems:"center"},children:[i.flatMap((e,a)=>{const[t,r]=(e=>{const a=`${e.label??e.name}${e.units?` [${e.units}]`:""}${e.required?" *":""}`,t=_jsx("label",{title:e.description??"",children:a}),r=a=>u(t=>({...t,[e.name]:a}));let n;switch(e.type){case"string":default:n=_jsx(InputText,{value:o[e.name]??"",onChange:e=>r(e.target.value)});break;case"enum":n=_jsx(Dropdown,{value:o[e.name]??null,options:(e.values??[]).map(e=>({label:e,value:e})),onChange:e=>r(e.value),placeholder:"Choose…"});break;case"bool":n=_jsx(Dropdown,{value:o[e.name]??null,options:[{label:"true",value:!0},{label:"false",value:!1}],onChange:e=>r(e.value)});break;case"u8":case"u16":case"u32":case"u64":case"i8":case"i16":case"i32":case"i64":case"f32":case"f64":n=_jsx(InputNumber,{value:o[e.name]??null,onValueChange:e=>r(e.value),useGrouping:!1,maxFractionDigits:e.type.startsWith("f")?9:0})}return[t,n]})(e);return[_jsx(React.Fragment,{children:t},`l-${a}`),_jsx(React.Fragment,{children:r},`i-${a}`)]}),_jsx("hr",{style:{gridColumn:"1 / span 2",width:"100%"}}),_jsx("label",{children:"Performed by"}),_jsx(InputText,{value:m,onChange:e=>c(e.target.value)}),_jsx("label",{children:"Expires at"}),_jsx(Calendar,{value:d,onChange:e=>p(e.value??null),showIcon:!0,dateFormat:"yy-mm-dd"}),_jsx("label",{children:"Certificate ref"}),_jsx(InputText,{value:x,onChange:e=>g(e.target.value)}),_jsx("label",{children:"Notes"}),_jsx(InputText,{value:f,onChange:e=>_(e.target.value)})]}),b&&_jsx("div",{style:{marginTop:"1rem",color:"#ef4444"},children:b})]})};
1
+ import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import React,{useContext,useEffect,useState}from"react";import{Button}from"primereact/button";import{Dialog}from"primereact/dialog";import{InputText}from"primereact/inputtext";import{InputNumber}from"primereact/inputnumber";import{Calendar}from"primereact/calendar";import{Dropdown}from"primereact/dropdown";import{EventEmitterContext}from"../../core/EventEmitterContext";import{MessageType}from"../../hub/CommandMessage";import{useAmsSchemas}from"./AmsProvider";export const CalibrationEntryDialog=({visible:e,assetId:t,assetType:a,onHide:r,onAdded:n})=>{const l=useAmsSchemas(),{invoke:s}=useContext(EventEmitterContext),i=l[a]?.calibration_fields??[],o=(()=>{const e=l[a]?.sub_locations;return e&&Array.isArray(e.keys)?e:null})(),u=o?.calibration_fields??[],d=u.length>0,[m,c]=useState({}),[p,x]=useState({}),[h,g]=useState(""),[_,f]=useState(null),[v,b]=useState(""),[j,y]=useState(""),[C,I]=useState(!1),[S,T]=useState(null);useEffect(()=>{e&&(c({}),x({}),g(""),f(null),b(""),y(""),T(null))},[e]);return _jsxs(Dialog,{header:`Add Calibration — ${t}`,visible:e,onHide:r,style:{width:"40rem"},footer:_jsxs(_Fragment,{children:[_jsx(Button,{label:"Cancel",severity:"secondary",onClick:r,disabled:C}),_jsx(Button,{label:"Save",icon:"pi pi-check",onClick:async()=>{if(d&&o)for(const e of o.keys)for(const t of u){if(!t.required)continue;const a=p[e]?.[t.name];if(null==a||""===a)return void T(`Field "${t.label??t.name}" on axis "${e}" is required.`)}else for(const e of i)if(e.required&&(void 0===m[e.name]||null===m[e.name]||""===m[e.name]))return void T(`Field "${e.label??e.name}" is required.`);const e=d?p:m;I(!0),T(null);try{const a=await s("ams.add_calibration",MessageType.Request,{asset_id:t,performed_by:h,expires_at:_?_.toISOString():null,cert_ref:v,notes:j,values:e});a?.success?(n?.(a.data.cal_id),r()):T(a?.error_message??"add_calibration failed")}catch(e){T(String(e?.message??e))}finally{I(!1)}},loading:C})]}),children:[_jsxs("div",d&&o?{children:[_jsx("h4",{style:{margin:"0 0 0.5rem 0"},children:o.label??"Per-axis calibration"}),_jsx("div",{style:{overflowX:"auto",marginBottom:"1rem"},children:_jsxs("table",{style:{width:"100%",borderCollapse:"collapse",fontSize:"0.875rem"},children:[_jsx("thead",{children:_jsxs("tr",{children:[_jsx("th",{style:{textAlign:"left",padding:"0.25rem 0.5rem",borderBottom:"1px solid var(--surface-border)"},children:o.key_label??"Key"}),u.map(e=>_jsxs("th",{title:e.description??void 0,style:{textAlign:"left",padding:"0.25rem 0.5rem",borderBottom:"1px solid var(--surface-border)"},children:[e.label??e.name,e.units?` [${e.units}]`:"",e.required?" *":""]},e.name))]})}),_jsx("tbody",{children:o.keys.map(e=>_jsxs("tr",{children:[_jsx("td",{style:{padding:"0.25rem 0.5rem",fontWeight:600},children:e}),u.map(t=>{const a=p[e]?.[t.name],r="string"!==t.type&&"bool"!==t.type;return _jsx("td",{style:{padding:"0.25rem 0.5rem"},children:r?_jsx(InputNumber,{value:a??null,onValueChange:a=>{x(r=>({...r,[e]:{...r[e]??{},[t.name]:a.value}}))},useGrouping:!1,maxFractionDigits:t.type.startsWith("f")?9:0,inputStyle:{width:"100%"}}):_jsx(InputText,{value:a??"",onChange:a=>{x(r=>({...r,[e]:{...r[e]??{},[t.name]:a.target.value}}))},style:{width:"100%"}})},t.name)})]},e))})]})}),_jsxs("div",{style:{display:"grid",gridTemplateColumns:"auto 1fr",gap:"0.5rem 1rem",alignItems:"center"},children:[_jsx("label",{children:"Performed by"}),_jsx(InputText,{value:h,onChange:e=>g(e.target.value)}),_jsx("label",{children:"Expires at"}),_jsx(Calendar,{value:_,onChange:e=>f(e.value??null),showIcon:!0,dateFormat:"yy-mm-dd"}),_jsx("label",{children:"Certificate ref"}),_jsx(InputText,{value:v,onChange:e=>b(e.target.value)}),_jsx("label",{children:"Notes"}),_jsx(InputText,{value:j,onChange:e=>y(e.target.value)})]})]}:{style:{display:"grid",gridTemplateColumns:"auto 1fr",gap:"0.5rem 1rem",alignItems:"center"},children:[i.flatMap((e,t)=>{const[a,r]=(e=>{const t=`${e.label??e.name}${e.units?` [${e.units}]`:""}${e.required?" *":""}`,a=_jsx("label",{title:e.description??"",children:t}),r=t=>c(a=>({...a,[e.name]:t}));let n;switch(e.type){case"string":default:n=_jsx(InputText,{value:m[e.name]??"",onChange:e=>r(e.target.value)});break;case"enum":n=_jsx(Dropdown,{value:m[e.name]??null,options:(e.values??[]).map(e=>({label:e,value:e})),onChange:e=>r(e.value),placeholder:"Choose…"});break;case"bool":n=_jsx(Dropdown,{value:m[e.name]??null,options:[{label:"true",value:!0},{label:"false",value:!1}],onChange:e=>r(e.value)});break;case"u8":case"u16":case"u32":case"u64":case"i8":case"i16":case"i32":case"i64":case"f32":case"f64":n=_jsx(InputNumber,{value:m[e.name]??null,onValueChange:e=>r(e.value),useGrouping:!1,maxFractionDigits:e.type.startsWith("f")?9:0})}return[a,n]})(e);return[_jsx(React.Fragment,{children:a},`l-${t}`),_jsx(React.Fragment,{children:r},`i-${t}`)]}),_jsx("hr",{style:{gridColumn:"1 / span 2",width:"100%"}}),_jsx("label",{children:"Performed by"}),_jsx(InputText,{value:h,onChange:e=>g(e.target.value)}),_jsx("label",{children:"Expires at"}),_jsx(Calendar,{value:_,onChange:e=>f(e.value??null),showIcon:!0,dateFormat:"yy-mm-dd"}),_jsx("label",{children:"Certificate ref"}),_jsx(InputText,{value:v,onChange:e=>b(e.target.value)}),_jsx("label",{children:"Notes"}),_jsx(InputText,{value:j,onChange:e=>y(e.target.value)})]}),S&&_jsx("div",{style:{marginTop:"1rem",color:"#ef4444"},children:S})]})};
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ /** Custom event the banner emits; <AssetRegistryTable> listens for it
3
+ * and opens its Add dialog pre-populated. Decouples the two so the
4
+ * banner can sit anywhere relative to the table in the layout. */
5
+ export declare const PREFILL_ADD_EVENT = "ams:prefill-add";
6
+ export interface PrefillAddDetail {
7
+ assetType: string;
8
+ location: string;
9
+ }
10
+ export declare const MissingAssetsBanner: React.FC;
11
+ //# sourceMappingURL=MissingAssetsBanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MissingAssetsBanner.d.ts","sourceRoot":"","sources":["../../../src/components/ams/MissingAssetsBanner.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAIvC;;mEAEmE;AACnE,eAAO,MAAM,iBAAiB,oBAAoB,CAAC;AACnD,MAAM,WAAW,gBAAgB;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAG,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAiGvC,CAAC"}
@@ -0,0 +1 @@
1
+ import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React,{useMemo}from"react";import{Button}from"primereact/button";import{useAms}from"./AmsProvider";export const PREFILL_ADD_EVENT="ams:prefill-add";export const MissingAssetsBanner=()=>{const{roles:e,assets:s,rolesLoaded:t}=useAms(),o=useMemo(()=>{const t=[];for(const[o,r]of Object.entries(e))for(const e of r){s.some(s=>s.asset_type===o&&s.location===e.location&&"active"===s.status)||t.push({assetType:o,role:e})}return t},[e,s]);if(!t)return null;if(0===o.length)return null;const r=(e,s,t)=>1===e?s:t;return _jsxs("div",{role:"alert",style:{borderLeft:"4px solid #f59e0b",background:"rgba(245, 158, 11, 0.08)",padding:"0.75rem 1rem",marginBottom:"1rem",borderRadius:"4px"},children:[_jsxs("div",{style:{display:"flex",alignItems:"center",gap:"0.5rem",marginBottom:"0.5rem"},children:[_jsx("i",{className:"pi pi-exclamation-triangle",style:{color:"#f59e0b"}}),_jsxs("strong",{children:[o.length," ",r(o.length,"role has","roles have")," no active asset registered."]}),_jsxs("span",{style:{color:"var(--text-secondary-color)",fontSize:"0.875rem"},children:["Modules and tests depending on ",r(o.length,"it","them")," will refuse to start."]})]}),_jsx("ul",{style:{margin:0,paddingLeft:"1.5rem"},children:o.map(({assetType:e,role:s})=>{const t=s.label??s.location,o=[s.used_by.length>0?`methods: ${s.used_by.join(", ")}`:null,s.used_by_modules.length>0?`modules: ${s.used_by_modules.join(", ")}`:null].filter(Boolean).join(" • ");return _jsxs("li",{style:{marginBottom:"0.25rem",display:"flex",alignItems:"center",gap:"0.5rem"},children:[_jsxs("span",{children:[_jsx("strong",{children:t}),_jsxs("span",{style:{color:"var(--text-secondary-color)"},children:[" ","(",e," at ",_jsx("code",{children:s.location}),")"]}),o&&_jsxs("span",{style:{color:"var(--text-secondary-color)",fontSize:"0.85em",marginLeft:"0.5rem"},children:["— ",o]})]}),_jsx(Button,{label:"Register",icon:"pi pi-plus",size:"small",outlined:!0,onClick:()=>((e,s)=>{const t={assetType:e,location:s};window.dispatchEvent(new CustomEvent("ams:prefill-add",{detail:t}))})(e,s.location)})]},`${e}/${s.location}`)})})]})};
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ export declare const PlaceholderHealthPanel: React.FC;
3
+ //# sourceMappingURL=PlaceholderHealthPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PlaceholderHealthPanel.d.ts","sourceRoot":"","sources":["../../../src/components/ams/PlaceholderHealthPanel.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAuD,MAAM,OAAO,CAAC;AA+B5E,eAAO,MAAM,sBAAsB,EAAE,KAAK,CAAC,EA+I1C,CAAC"}
@@ -0,0 +1 @@
1
+ import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React,{useCallback,useContext,useEffect,useState}from"react";import{Button}from"primereact/button";import{DataTable}from"primereact/datatable";import{Column}from"primereact/column";import{EventEmitterContext}from"../../core/EventEmitterContext";import{MessageType}from"../../hub/CommandMessage";import{useAms}from"./AmsProvider";export const PlaceholderHealthPanel=()=>{const{invoke:e}=useContext(EventEmitterContext),{assets:s,refreshAssets:l}=useAms(),[t,o]=useState(null),[r,a]=useState(null),[n,i]=useState(!1),[d,c]=useState(null),m=useCallback(async()=>{i(!0),c(null);try{const s=await e("ams.diagnose_placeholders",MessageType.Request,{});s?.success?(o(s.data?.placeholders??[]),a(s.data?.summary??null)):c(s?.error_message??"diagnose_placeholders failed")}catch(e){c(String(e?.message??e))}finally{i(!1)}},[e]);useEffect(()=>{m()},[m,s]);const u=r&&_jsx("span",{children:0===r.total?_jsxs("span",{style:{color:"#9ca3af"},children:["No ",_jsx("code",{children:"${ams.*}"})," placeholders in any enabled module's config."]}):0===r.unresolved?_jsxs("span",{style:{color:"#34d399"},children:["✓ All ",r.total," placeholder",1===r.total?"":"s"," resolved. Modules will start cleanly."]}):_jsxs("span",{style:{color:"#f59e0b"},children:[r.unresolved," of ",r.total," placeholder",1===r.total?"":"s"," can't be resolved. Register the missing asset",1===r.unresolved?"":"s"," before starting the affected module",1===r.unresolved?"":"s","."]})});return _jsxs("div",{style:{display:"flex",flexDirection:"column",gap:"0.75rem"},children:[_jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center"},children:[_jsx("h4",{style:{margin:0},children:"Module Placeholder Health"}),_jsx(Button,{icon:"pi pi-refresh",label:"Refresh",onClick:()=>{l(),m()},loading:n,severity:"secondary",outlined:!0})]}),d&&_jsxs("div",{style:{color:"#ef4444",fontSize:"0.875rem"},children:["Couldn't fetch placeholder diagnostic: ",d]}),_jsx("div",{style:{fontSize:"0.875rem"},children:u}),t&&t.length>0&&_jsxs(DataTable,{value:t,size:"small",stripedRows:!0,sortField:"status",sortOrder:-1,emptyMessage:"No placeholders to report.",children:[_jsx(Column,{header:"",body:e=>"ok"===e.status?_jsx("span",{style:{color:"#34d399",display:"inline-flex",alignItems:"center",gap:"0.25rem"},children:_jsx("i",{className:"pi pi-check-circle"})}):_jsx("span",{style:{color:"#f59e0b",display:"inline-flex",alignItems:"center",gap:"0.25rem"},children:_jsx("i",{className:"pi pi-exclamation-triangle"})}),style:{width:"2rem"}}),_jsx(Column,{field:"module",header:"Module",style:{width:"8rem"}}),_jsx(Column,{field:"location",header:"Role",style:{width:"10rem"}}),_jsx(Column,{header:"Value / Reason",body:e=>{if("unresolved"===e.status)return _jsx("span",{style:{color:"#f59e0b"},children:e.reason??"unresolved"});const s=e.resolved_value;let l;return l="string"==typeof s?_jsxs("code",{children:['"',s,'"']}):"number"==typeof s?_jsx("code",{children:s}):null==s?_jsx("em",{style:{color:"#9ca3af"},children:"null"}):_jsx("code",{children:JSON.stringify(s)}),l}}),_jsx(Column,{header:"Asset",body:e=>"ok"===e.status&&e.asset_id?_jsx("code",{style:{fontSize:"0.85em"},children:e.asset_id}):_jsx("span",{style:{color:"#9ca3af"},children:"—"}),style:{width:"14rem"}}),_jsx(Column,{field:"path",header:"Config path",body:e=>_jsx("code",{style:{fontSize:"0.8em"},children:e.path})})]})]})};
@@ -4,4 +4,6 @@ export { AssetRegistryTable } from './AssetRegistryTable';
4
4
  export { AssetDetailView } from './AssetDetailView';
5
5
  export { CalibrationEntryDialog } from './CalibrationEntryDialog';
6
6
  export { SubLocationPicker } from './SubLocationPicker';
7
+ export { PlaceholderHealthPanel } from './PlaceholderHealthPanel';
8
+ export { MissingAssetsBanner } from './MissingAssetsBanner';
7
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/ams/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAC7H,YAAY,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/ams/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAC7H,YAAY,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC"}
@@ -1 +1 @@
1
- export{AmsProvider,useAms,useAmsSchemas,useAmsRoles,useAmsAlerts,useAmsAssets,useAmsSelection}from"./AmsProvider";export{AssetRegistryTable}from"./AssetRegistryTable";export{AssetDetailView}from"./AssetDetailView";export{CalibrationEntryDialog}from"./CalibrationEntryDialog";export{SubLocationPicker}from"./SubLocationPicker";
1
+ export{AmsProvider,useAms,useAmsSchemas,useAmsRoles,useAmsAlerts,useAmsAssets,useAmsSelection}from"./AmsProvider";export{AssetRegistryTable}from"./AssetRegistryTable";export{AssetDetailView}from"./AssetDetailView";export{CalibrationEntryDialog}from"./CalibrationEntryDialog";export{SubLocationPicker}from"./SubLocationPicker";export{PlaceholderHealthPanel}from"./PlaceholderHealthPanel";export{MissingAssetsBanner}from"./MissingAssetsBanner";
@@ -14,6 +14,8 @@ export { TestDataView } from './tis/TestDataView';
14
14
  export type { TestDataViewProps, ChartAxis, ChartSeries, ChartView, RawDataShape } from './tis/TestDataView';
15
15
  export { TestRawDataView } from './tis/TestRawDataView';
16
16
  export type { TestRawDataViewProps } from './tis/TestRawDataView';
17
+ export { ProjectManager } from './tis/ProjectManager';
18
+ export type { ProjectManagerProps } from './tis/ProjectManager';
17
19
  export { AmsProvider, useAms, useAmsSchemas, useAmsAlerts, useAmsAssets, useAmsSelection, } from './ams/AmsProvider';
18
20
  export type { AmsProviderProps, AmsContextValue, AmsAlerts, AmsAssetEntry, AmsSelection, AmsSchemaRegistry, AmsTypeSchema, } from './ams/AmsProvider';
19
21
  export { AssetRegistryTable } from './ams/AssetRegistryTable';
@@ -21,4 +23,10 @@ export { AssetDetailView } from './ams/AssetDetailView';
21
23
  export { CalibrationEntryDialog } from './ams/CalibrationEntryDialog';
22
24
  export type { CalibrationEntryDialogProps } from './ams/CalibrationEntryDialog';
23
25
  export { SubLocationPicker } from './ams/SubLocationPicker';
26
+ export { NetworkProvider, useNetwork } from './network/NetworkProvider';
27
+ export type { NetworkProviderProps, NetworkContextValue, NetworkStatus, NetworkInterface, NetworkConnection, NetworkDeviceIp4, WifiAp, StagedChange, } from './network/NetworkProvider';
28
+ export { NetworkPanel } from './network/NetworkPanel';
29
+ export type { NetworkPanelProps } from './network/NetworkPanel';
30
+ export { StagedChangeBanner } from './network/StagedChangeBanner';
31
+ export type { StagedChangeBannerProps } from './network/StagedChangeBanner';
24
32
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAQA,OAAO,EACH,WAAW,EACX,UAAU,EACV,MAAM,EACN,aAAa,EACb,WAAW,EACX,eAAe,EACf,UAAU,EACV,SAAS,GACZ,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACR,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,eAAe,GAClB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,eAAe,EAAE,MAAU,uBAAuB,CAAC;AAC5D,YAAY,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAElE,OAAO,EAAE,aAAa,EAAE,MAAY,qBAAqB,CAAC;AAC1D,YAAY,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAE9D,OAAO,EAAE,iBAAiB,EAAE,MAAQ,yBAAyB,CAAC;AAC9D,YAAY,EAAE,sBAAsB,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAEvF,OAAO,EAAE,gBAAgB,EAAE,MAAS,wBAAwB,CAAC;AAC7D,YAAY,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAEpE,OAAO,EAAE,kBAAkB,EAAE,MAAO,0BAA0B,CAAC;AAC/D,YAAY,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAExE,OAAO,EAAE,YAAY,EAAE,MAAa,oBAAoB,CAAC;AACzD,YAAY,EAAE,iBAAiB,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE7G,OAAO,EAAE,eAAe,EAAE,MAAU,uBAAuB,CAAC;AAC5D,YAAY,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAMlE,OAAO,EACH,WAAW,EACX,MAAM,EACN,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,eAAe,GAClB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACR,gBAAgB,EAChB,eAAe,EACf,SAAS,EACT,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,aAAa,GAChB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,MAAS,0BAA0B,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAY,uBAAuB,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AACtE,YAAY,EAAE,2BAA2B,EAAE,MAAM,8BAA8B,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAE,MAAU,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAQA,OAAO,EACH,WAAW,EACX,UAAU,EACV,MAAM,EACN,aAAa,EACb,WAAW,EACX,eAAe,EACf,UAAU,EACV,SAAS,GACZ,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACR,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,eAAe,GAClB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,eAAe,EAAE,MAAU,uBAAuB,CAAC;AAC5D,YAAY,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAElE,OAAO,EAAE,aAAa,EAAE,MAAY,qBAAqB,CAAC;AAC1D,YAAY,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAE9D,OAAO,EAAE,iBAAiB,EAAE,MAAQ,yBAAyB,CAAC;AAC9D,YAAY,EAAE,sBAAsB,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAEvF,OAAO,EAAE,gBAAgB,EAAE,MAAS,wBAAwB,CAAC;AAC7D,YAAY,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAEpE,OAAO,EAAE,kBAAkB,EAAE,MAAO,0BAA0B,CAAC;AAC/D,YAAY,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAExE,OAAO,EAAE,YAAY,EAAE,MAAa,oBAAoB,CAAC;AACzD,YAAY,EAAE,iBAAiB,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE7G,OAAO,EAAE,eAAe,EAAE,MAAU,uBAAuB,CAAC;AAC5D,YAAY,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAElE,OAAO,EAAE,cAAc,EAAE,MAAW,sBAAsB,CAAC;AAC3D,YAAY,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAMhE,OAAO,EACH,WAAW,EACX,MAAM,EACN,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,eAAe,GAClB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACR,gBAAgB,EAChB,eAAe,EACf,SAAS,EACT,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,aAAa,GAChB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,MAAS,0BAA0B,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAY,uBAAuB,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AACtE,YAAY,EAAE,2BAA2B,EAAE,MAAM,8BAA8B,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAE,MAAU,yBAAyB,CAAC;AAShE,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACxE,YAAY,EACR,oBAAoB,EACpB,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,MAAM,EACN,YAAY,GACf,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,YAAY,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,YAAY,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC"}
@@ -1 +1 @@
1
- export{TisProvider,TisContext,useTis,useTisSchemas,useTisState,useTisSelection,useTisRuns,useTisRun}from"./tis/TisProvider";export{ProjectSelector}from"./tis/ProjectSelector";export{TestSetupForm}from"./tis/TestSetupForm";export{ProjectInfoDialog}from"./tis/ProjectInfoDialog";export{TestMethodDialog}from"./tis/TestMethodDialog";export{ResultHistoryTable}from"./tis/ResultHistoryTable";export{TestDataView}from"./tis/TestDataView";export{TestRawDataView}from"./tis/TestRawDataView";export{AmsProvider,useAms,useAmsSchemas,useAmsAlerts,useAmsAssets,useAmsSelection}from"./ams/AmsProvider";export{AssetRegistryTable}from"./ams/AssetRegistryTable";export{AssetDetailView}from"./ams/AssetDetailView";export{CalibrationEntryDialog}from"./ams/CalibrationEntryDialog";export{SubLocationPicker}from"./ams/SubLocationPicker";
1
+ export{TisProvider,TisContext,useTis,useTisSchemas,useTisState,useTisSelection,useTisRuns,useTisRun}from"./tis/TisProvider";export{ProjectSelector}from"./tis/ProjectSelector";export{TestSetupForm}from"./tis/TestSetupForm";export{ProjectInfoDialog}from"./tis/ProjectInfoDialog";export{TestMethodDialog}from"./tis/TestMethodDialog";export{ResultHistoryTable}from"./tis/ResultHistoryTable";export{TestDataView}from"./tis/TestDataView";export{TestRawDataView}from"./tis/TestRawDataView";export{ProjectManager}from"./tis/ProjectManager";export{AmsProvider,useAms,useAmsSchemas,useAmsAlerts,useAmsAssets,useAmsSelection}from"./ams/AmsProvider";export{AssetRegistryTable}from"./ams/AssetRegistryTable";export{AssetDetailView}from"./ams/AssetDetailView";export{CalibrationEntryDialog}from"./ams/CalibrationEntryDialog";export{SubLocationPicker}from"./ams/SubLocationPicker";export{NetworkProvider,useNetwork}from"./network/NetworkProvider";export{NetworkPanel}from"./network/NetworkPanel";export{StagedChangeBanner}from"./network/StagedChangeBanner";
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ export interface NetworkPanelProps {
3
+ /** Optional CSS class on the outer container. */
4
+ className?: string;
5
+ }
6
+ export declare const NetworkPanel: React.FC<NetworkPanelProps>;
7
+ export default NetworkPanel;
8
+ //# sourceMappingURL=NetworkPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NetworkPanel.d.ts","sourceRoot":"","sources":["../../../src/components/network/NetworkPanel.tsx"],"names":[],"mappings":"AAeA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAuBnD,MAAM,WAAW,iBAAiB;IAC9B,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CA6TpD,CAAC;AAEF,eAAe,YAAY,CAAC"}
@@ -0,0 +1 @@
1
+ import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import React,{useEffect,useState}from"react";import{Button}from"primereact/button";import{DataTable}from"primereact/datatable";import{Column}from"primereact/column";import{Dialog}from"primereact/dialog";import{Password}from"primereact/password";import{InputSwitch}from"primereact/inputswitch";import{ConfirmDialog,confirmDialog}from"primereact/confirmdialog";import{useNetwork}from"./NetworkProvider";const signalBars=e=>e>=75?"▰▰▰▰":e>=50?"▰▰▰▱":e>=25?"▰▰▱▱":e>0?"▰▱▱▱":"▱▱▱▱",isSecured=e=>{const i=(e??"").trim();return i.length>0&&"--"!==i};export const NetworkPanel=({className:e})=>{const i=useNetwork(),[s,t]=useState(null),[r,n]=useState(""),[a,l]=useState(!1);useEffect(()=>{0!==i.aps.length||i.scanning||i.scanWifi()},[]);const o=i.status.interfaces.filter(e=>"ethernet"===e.type),d=i.status.interfaces.filter(e=>"wifi"===e.type),c=d.find(e=>"connected"===e.state)??d[0];return _jsxs("div",{className:e,style:{width:"100%",maxWidth:"100%",boxSizing:"border-box"},children:[_jsx(ConfirmDialog,{}),_jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:"1rem",gap:"0.5rem",flexWrap:"wrap"},children:[_jsxs("div",{children:[_jsx("h3",{style:{margin:0},children:"Network"}),c?_jsxs("div",{style:{fontSize:"0.875rem",color:"#9ca3af",marginTop:"0.25rem"},children:["connected"===c.state?_jsxs(_Fragment,{children:["Connected to ",_jsx("code",{children:c.connection||"(unnamed)"})," on ",_jsx("code",{children:c.device})]}):_jsxs(_Fragment,{children:["WiFi: ",c.state]}),c.ip4.addresses.length>0&&_jsxs(_Fragment,{children:[" · ",c.ip4.addresses[0]]})]}):_jsx("div",{style:{fontSize:"0.875rem",color:"#9ca3af",marginTop:"0.25rem"},children:"No WiFi device detected."})]}),_jsxs("div",{style:{display:"flex",gap:"0.75rem",alignItems:"center",flexWrap:"wrap"},children:[_jsxs("label",{style:{display:"inline-flex",alignItems:"center",gap:"0.4rem"},children:[_jsx("span",{style:{fontSize:"0.875rem"},children:"WiFi radio"}),_jsx(InputSwitch,{checked:!!i.status.wifi_radio,onChange:e=>{i.setRadio(!!e.value)},disabled:null===i.status.wifi_radio})]}),_jsx(Button,{icon:"pi pi-refresh",label:"Refresh",size:"small",onClick:()=>{i.refreshStatus()}})]})]}),i.lastError&&_jsx("div",{style:{background:"#7f1d1d",color:"white",padding:"0.5rem 0.75rem",borderRadius:4,marginBottom:"1rem",fontSize:"0.875rem"},children:i.lastError}),_jsxs("div",{style:{marginBottom:"1.5rem",padding:"0.75rem 1rem",border:"1px solid #2a2a2a",borderRadius:4,background:"#161616"},children:[_jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:"0.75rem"},children:[_jsx("strong",{children:"WiFi Networks"}),_jsx(Button,{icon:i.scanning?"pi pi-spin pi-spinner":"pi pi-search",label:i.scanning?"Scanning…":"Scan",size:"small",outlined:!0,disabled:i.scanning||!1===i.status.wifi_radio,onClick:()=>{i.scanWifi()}})]}),_jsxs(DataTable,{value:i.aps,emptyMessage:!1===i.status.wifi_radio?"WiFi radio is off.":"No networks found yet. Click Scan to refresh.",scrollable:!0,scrollHeight:"20rem",tableStyle:{minWidth:0},style:{width:"100%"},children:[_jsx(Column,{header:"SSID",body:e=>_jsxs("span",{children:[e.in_use&&_jsx("i",{className:"pi pi-check",style:{marginRight:"0.4rem",color:"#22c55e"}}),e.ssid]}),style:{minWidth:"10rem"}}),_jsx(Column,{header:"Signal",body:e=>_jsxs("span",{style:{fontFamily:"monospace"},children:[signalBars(e.signal)," ",_jsxs("span",{style:{color:"#9ca3af"},children:[e.signal,"%"]})]}),style:{width:"10rem"},sortable:!0,sortField:"signal"}),_jsx(Column,{header:"Security",body:e=>_jsx("span",{children:isSecured(e.security)?e.security:"Open"}),style:{width:"8rem"}}),_jsx(Column,{header:"Action",style:{width:"9rem"},body:e=>_jsx(Button,{icon:"pi pi-link",label:e.in_use?"Reconnect":"Connect",size:"small",outlined:!0,disabled:!!i.staged,onClick:()=>(e=>{t(e),n("")})(e)})})]})]}),i.status.connections.length>0&&_jsxs("div",{style:{marginBottom:"1.5rem",padding:"0.75rem 1rem",border:"1px solid #2a2a2a",borderRadius:4,background:"#161616"},children:[_jsx("strong",{style:{display:"block",marginBottom:"0.75rem"},children:"Saved Connections"}),_jsxs(DataTable,{value:i.status.connections,emptyMessage:"No saved profiles.",tableStyle:{minWidth:0},style:{width:"100%"},children:[_jsx(Column,{field:"name",header:"Name",style:{minWidth:"10rem"}}),_jsx(Column,{field:"type",header:"Type",style:{width:"8rem"}}),_jsx(Column,{field:"device",header:"Device",style:{minWidth:"8rem"}}),_jsx(Column,{header:"Active",style:{width:"6rem"},body:e=>e.active?_jsx("i",{className:"pi pi-check",style:{color:"#22c55e"}}):null}),_jsx(Column,{header:"Action",style:{width:"8rem"},body:e=>"wifi"===e.type?_jsx(Button,{icon:"pi pi-trash",label:"Forget",size:"small",severity:"danger",outlined:!0,onClick:()=>{var s;confirmDialog({header:"Forget network",icon:"pi pi-exclamation-triangle",acceptLabel:"Forget",rejectLabel:"Cancel",acceptClassName:"p-button-danger",message:_jsxs("div",{children:[_jsxs("p",{style:{marginTop:0},children:["Remove saved profile ",_jsx("code",{children:(s=e).name}),"?"]}),_jsx("p",{style:{marginBottom:0,fontSize:"0.875rem",color:"#9ca3af"},children:"The password is deleted. You'll need to re-enter it next time you connect to this network."})]}),accept:()=>{i.forgetConnection(s.uuid)}})}}):null})]})]}),_jsxs("div",{style:{padding:"0.75rem 1rem",border:"1px solid #2a2a2a",borderRadius:4,background:"#161616"},children:[_jsx("strong",{style:{display:"block",marginBottom:"0.25rem"},children:"Wired Interfaces"}),_jsx("div",{style:{fontSize:"0.75rem",color:"#6b7280",marginBottom:"0.75rem"},children:"Wired configuration is managed by netplan and is read-only here."}),_jsxs(DataTable,{value:o,emptyMessage:"No wired interfaces.",tableStyle:{minWidth:0},style:{width:"100%"},children:[_jsx(Column,{field:"device",header:"Device",style:{minWidth:"8rem"}}),_jsx(Column,{field:"state",header:"State",style:{width:"8rem"}}),_jsx(Column,{header:"IP Address",body:e=>e.ip4.addresses.length>0?e.ip4.addresses.join(", "):_jsx("span",{style:{color:"#6b7280"},children:"—"}),style:{minWidth:"10rem"}}),_jsx(Column,{header:"Gateway",body:e=>e.ip4.gateway||_jsx("span",{style:{color:"#6b7280"},children:"—"}),style:{minWidth:"8rem"}}),_jsx(Column,{header:"DNS",body:e=>e.ip4.dns.length>0?e.ip4.dns.join(", "):_jsx("span",{style:{color:"#6b7280"},children:"—"}),style:{minWidth:"8rem"}})]})]}),_jsx(Dialog,{header:s?`Connect to ${s.ssid}`:"Connect",visible:!!s,style:{width:"24rem"},onHide:()=>{a||t(null)},modal:!0,draggable:!1,children:s&&_jsxs("div",{style:{display:"flex",flexDirection:"column",gap:"0.75rem"},children:[_jsxs("div",{style:{fontSize:"0.875rem",color:"#9ca3af"},children:[_jsxs("div",{children:["Signal: ",s.signal,"%"]}),_jsxs("div",{children:["Security: ",isSecured(s.security)?s.security:"Open"]})]}),isSecured(s.security)?_jsxs(_Fragment,{children:[_jsx("label",{htmlFor:"nw-pw",style:{fontSize:"0.875rem"},children:"Password"}),_jsx(Password,{inputId:"nw-pw",value:r,onChange:e=>n(e.target.value),feedback:!1,toggleMask:!0,autoFocus:!0})]}):_jsx("div",{style:{fontSize:"0.875rem"},children:"This is an open network. No password required."}),_jsx("div",{style:{background:"#78350f",color:"white",padding:"0.5rem 0.75rem",borderRadius:4,fontSize:"0.875rem"},children:"After connecting, you have 60 seconds to confirm the change. If you don't, the server will auto-revert to the previous network — that way a bad password from a remote session can't lock you out."}),_jsxs("div",{style:{display:"flex",justifyContent:"flex-end",gap:"0.4rem"},children:[_jsx(Button,{label:"Cancel",outlined:!0,onClick:()=>t(null),disabled:a}),_jsx(Button,{label:a?"Connecting…":"Connect",icon:a?"pi pi-spin pi-spinner":"pi pi-link",onClick:()=>{(async()=>{if(s){l(!0);try{const e=isSecured(s.security)?r:void 0;await i.wifiConnect(s.ssid,e)&&(t(null),n(""))}finally{l(!1)}}})()},disabled:a||isSecured(s.security)&&0===r.length})]})]})})]})};export default NetworkPanel;
@@ -0,0 +1,72 @@
1
+ import React, { type ReactNode } from 'react';
2
+ export interface NetworkDeviceIp4 {
3
+ addresses: string[];
4
+ gateway: string;
5
+ dns: string[];
6
+ }
7
+ export interface NetworkInterface {
8
+ device: string;
9
+ type: string;
10
+ state: string;
11
+ connection: string;
12
+ ip4: NetworkDeviceIp4;
13
+ }
14
+ export interface NetworkConnection {
15
+ name: string;
16
+ uuid: string;
17
+ type: string;
18
+ device: string;
19
+ active: boolean;
20
+ }
21
+ export interface WifiAp {
22
+ ssid: string;
23
+ bssid: string;
24
+ signal: number;
25
+ security: string;
26
+ in_use: boolean;
27
+ }
28
+ export interface StagedChange {
29
+ staged_id: string;
30
+ device: string;
31
+ ssid: string;
32
+ prev_connection_uuid: string;
33
+ new_connection_uuid: string;
34
+ new_profile_created: boolean;
35
+ revert_in_seconds: number;
36
+ /**
37
+ * Absolute deadline (ms since epoch) computed when the staged
38
+ * change was received. The banner uses this to render a
39
+ * monotonically-decreasing countdown that doesn't depend on
40
+ * `revert_in_seconds` staying fresh in React state.
41
+ */
42
+ deadline_ms: number;
43
+ }
44
+ export interface NetworkStatus {
45
+ interfaces: NetworkInterface[];
46
+ connections: NetworkConnection[];
47
+ wifi_radio: boolean | null;
48
+ }
49
+ export interface NetworkContextValue {
50
+ status: NetworkStatus;
51
+ statusLoaded: boolean;
52
+ refreshStatus: () => Promise<void>;
53
+ aps: WifiAp[];
54
+ scanning: boolean;
55
+ scanWifi: (device?: string) => Promise<void>;
56
+ /** Latest pending stage, or null when none in flight. */
57
+ staged: StagedChange | null;
58
+ /** Connect to an SSID; returns the staged change record on success. */
59
+ wifiConnect: (ssid: string, password?: string, device?: string) => Promise<StagedChange | null>;
60
+ confirmConnection: (stagedId: string) => Promise<boolean>;
61
+ cancelStaged: (stagedId: string) => Promise<boolean>;
62
+ forgetConnection: (uuid: string) => Promise<boolean>;
63
+ setRadio: (enabled: boolean) => Promise<boolean>;
64
+ /** Most recent error from any network action, or empty string. */
65
+ lastError: string;
66
+ }
67
+ export interface NetworkProviderProps {
68
+ children: ReactNode;
69
+ }
70
+ export declare const NetworkProvider: React.FC<NetworkProviderProps>;
71
+ export declare const useNetwork: () => NetworkContextValue;
72
+ //# sourceMappingURL=NetworkProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NetworkProvider.d.ts","sourceRoot":"","sources":["../../../src/components/network/NetworkProvider.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,EAOV,KAAK,SAAS,EACjB,MAAM,OAAO,CAAC;AAQf,MAAM,WAAW,gBAAgB;IAC7B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,gBAAgB,CAAC;CACzB;AAED,MAAM,WAAW,iBAAiB;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,MAAM;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,oBAAoB,EAAE,MAAM,CAAC;IAC7B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,iBAAiB,EAAE,MAAM,CAAC;IAC1B;;;;;OAKG;IACH,WAAW,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC1B,UAAU,EAAE,gBAAgB,EAAE,CAAC;IAC/B,WAAW,EAAE,iBAAiB,EAAE,CAAC;IACjC,UAAU,EAAE,OAAO,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,mBAAmB;IAChC,MAAM,EAAE,aAAa,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;IACtB,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnC,GAAG,EAAE,MAAM,EAAE,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7C,yDAAyD;IACzD,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAE5B,uEAAuE;IACvE,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;IAChG,iBAAiB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1D,YAAY,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACrD,gBAAgB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACrD,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAEjD,kEAAkE;IAClE,SAAS,EAAE,MAAM,CAAC;CACrB;AA4BD,MAAM,WAAW,oBAAoB;IACjC,QAAQ,EAAE,SAAS,CAAC;CACvB;AAED,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CA0M1D,CAAC;AAMF,eAAO,MAAM,UAAU,2BAAmC,CAAC"}
@@ -0,0 +1 @@
1
+ import{jsx as _jsx}from"react/jsx-runtime";import React,{createContext,useCallback,useContext,useEffect,useMemo,useState}from"react";import{EventEmitterContext}from"../../core/EventEmitterContext";import{MessageType}from"../../hub/CommandMessage";const EMPTY_STATUS={interfaces:[],connections:[],wifi_radio:null},NetworkContext=createContext({status:EMPTY_STATUS,statusLoaded:!1,refreshStatus:async()=>{},aps:[],scanning:!1,scanWifi:async()=>{},staged:null,wifiConnect:async()=>null,confirmConnection:async()=>!1,cancelStaged:async()=>!1,forgetConnection:async()=>!1,setRadio:async()=>!1,lastError:""});export const NetworkProvider=({children:e})=>{const{invoke:t,subscribe:s,unsubscribe:n}=useContext(EventEmitterContext),[a,r]=useState(EMPTY_STATUS),[c,i]=useState(!1),[o,d]=useState([]),[u,_]=useState(!1),[g,l]=useState(null),[f,w]=useState(""),m=useCallback(async()=>{try{const[e,s]=await Promise.all([t("nw.list_interfaces",MessageType.Request,{}),t("nw.status",MessageType.Request,{})]),n=e?.success?e.data?.interfaces??[]:[],a=s?.success?s.data?.connections??[]:[],c=s?.success&&"boolean"==typeof s.data?.wifi_radio?s.data.wifi_radio:null;r({interfaces:n,connections:a,wifi_radio:c}),i(!0),w(e?.success?s?.success?"":s?.error_message??"":e?.error_message??"")}catch(e){w(e instanceof Error?e.message:String(e))}},[t]);useEffect(()=>{m()},[m]),useEffect(()=>{const e=[s("nw.staged_change",e=>{if(!e||"object"!=typeof e)return;const t=Number(e.revert_in_seconds??0);l({staged_id:String(e.staged_id??""),device:String(e.device??""),ssid:String(e.ssid??""),prev_connection_uuid:String(e.prev_connection_uuid??""),new_connection_uuid:String(e.new_connection_uuid??""),new_profile_created:!!e.new_profile_created,revert_in_seconds:t,deadline_ms:Date.now()+1e3*t})}),s("nw.confirmed",e=>{const t=String(e?.staged_id??"");l(e=>e&&e.staged_id===t?null:e),m()}),s("nw.revert_fired",e=>{const t=String(e?.staged_id??"");l(e=>e&&e.staged_id===t?null:e),m()}),s("nw.connection_deleted",()=>{m()})];return()=>{e.forEach(n)}},[s,n,m]);const S=useCallback(async e=>{_(!0),w("");try{const s={};e&&(s.device=e);const n=await t("nw.scan_wifi",MessageType.Request,s);n?.success?d(n.data?.access_points??[]):w(n?.error_message??"scan_wifi failed")}catch(e){w(e instanceof Error?e.message:String(e))}finally{_(!1)}},[t]),y=useCallback(async(e,s,n)=>{w("");try{const a={ssid:e};s&&(a.password=s),n&&(a.device=n);const r=await t("nw.wifi_connect",MessageType.Request,a);if(!r?.success)return w(r?.error_message??"wifi_connect failed"),null;const c=Number(r.data?.revert_in_seconds??0),i={staged_id:String(r.data?.staged_id??""),device:String(r.data?.device??""),ssid:String(r.data?.ssid??e),prev_connection_uuid:String(r.data?.prev_connection_uuid??""),new_connection_uuid:String(r.data?.new_connection_uuid??""),new_profile_created:!!r.data?.new_profile_created,revert_in_seconds:c,deadline_ms:Date.now()+1e3*c};return l(i),i}catch(e){return w(e instanceof Error?e.message:String(e)),null}},[t]),p=useCallback(async e=>{try{const s=await t("nw.confirm_connection",MessageType.Request,{staged_id:e});return s?.success?(l(t=>t&&t.staged_id===e?null:t),!0):(w(s?.error_message??"confirm_connection failed"),!1)}catch(e){return w(e instanceof Error?e.message:String(e)),!1}},[t]),C=useCallback(async e=>{try{const s=await t("nw.cancel_staged",MessageType.Request,{staged_id:e});return!!s?.success}catch(e){return w(e instanceof Error?e.message:String(e)),!1}},[t]),v=useCallback(async e=>{try{const s=await t("nw.forget_connection",MessageType.Request,{uuid:e});return s?.success?(m(),!0):(w(s?.error_message??"forget_connection failed"),!1)}catch(e){return w(e instanceof Error?e.message:String(e)),!1}},[t,m]),E=useCallback(async e=>{try{const s=await t("nw.set_radio",MessageType.Request,{enabled:e});return s?.success?(r(t=>({...t,wifi_radio:e})),!0):(w(s?.error_message??"set_radio failed"),!1)}catch(e){return w(e instanceof Error?e.message:String(e)),!1}},[t]),b=useMemo(()=>({status:a,statusLoaded:c,refreshStatus:m,aps:o,scanning:u,scanWifi:S,staged:g,wifiConnect:y,confirmConnection:p,cancelStaged:C,forgetConnection:v,setRadio:E,lastError:f}),[a,c,m,o,u,S,g,y,p,C,v,E,f]);return _jsx(NetworkContext.Provider,{value:b,children:e})};export const useNetwork=()=>useContext(NetworkContext);
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ export interface StagedChangeBannerProps {
3
+ /** Override the banner placement. Defaults to a fixed top bar. */
4
+ style?: React.CSSProperties;
5
+ }
6
+ export declare const StagedChangeBanner: React.FC<StagedChangeBannerProps>;
7
+ export default StagedChangeBanner;
8
+ //# sourceMappingURL=StagedChangeBanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StagedChangeBanner.d.ts","sourceRoot":"","sources":["../../../src/components/network/StagedChangeBanner.tsx"],"names":[],"mappings":"AAYA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAInD,MAAM,WAAW,uBAAuB;IACpC,kEAAkE;IAClE,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC/B;AAED,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CA6EhE,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
@@ -0,0 +1 @@
1
+ import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React,{useEffect,useState}from"react";import{Button}from"primereact/button";import{useNetwork}from"./NetworkProvider";export const StagedChangeBanner=({style:e})=>{const{staged:t,confirmConnection:i,cancelStaged:n}=useNetwork(),[r,s]=useState(()=>Date.now());if(useEffect(()=>{if(!t)return;const e=window.setInterval(()=>s(Date.now()),250);return()=>window.clearInterval(e)},[t]),!t)return null;const o=Math.max(0,Math.ceil((t.deadline_ms-r)/1e3)),a=Math.max(1,t.revert_in_seconds),d=Math.max(0,Math.min(100,o/a*100)),l={position:"sticky",top:0,zIndex:1e3,padding:"0.75rem 1rem",background:o<=10?"#7f1d1d":"#78350f",color:"white",borderBottom:"1px solid #1f2937",boxShadow:"0 2px 4px rgba(0, 0, 0, 0.3)",...e};return _jsxs("div",{style:l,role:"alertdialog","aria-live":"polite",children:[_jsxs("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",gap:"1rem",flexWrap:"wrap"},children:[_jsxs("div",{style:{minWidth:0},children:[_jsx("strong",{children:"WiFi change pending:"})," ","connected to ",_jsx("code",{children:t.ssid})," on ",_jsx("code",{children:t.device})]}),_jsxs("div",{style:{fontVariantNumeric:"tabular-nums",fontSize:"1.1rem"},children:["Reverting in ",_jsxs("strong",{children:[o,"s"]})]}),_jsxs("div",{style:{display:"flex",gap:"0.4rem"},children:[_jsx(Button,{label:"Confirm",icon:"pi pi-check",size:"small",severity:"success",onClick:()=>{i(t.staged_id)}}),_jsx(Button,{label:"Cancel & Revert",icon:"pi pi-undo",size:"small",severity:"danger",outlined:!0,onClick:()=>{n(t.staged_id)}})]})]}),_jsx("div",{style:{marginTop:"0.5rem",height:"0.25rem",background:"rgba(255, 255, 255, 0.2)",borderRadius:0,overflow:"hidden"},children:_jsx("div",{style:{width:`${d}%`,height:"100%",background:"white",transition:"width 0.25s linear"}})})]})};export default StagedChangeBanner;
@@ -0,0 +1,7 @@
1
+ export { NetworkProvider, useNetwork } from './NetworkProvider';
2
+ export type { NetworkProviderProps, NetworkContextValue, NetworkStatus, NetworkInterface, NetworkConnection, NetworkDeviceIp4, WifiAp, StagedChange, } from './NetworkProvider';
3
+ export { NetworkPanel } from './NetworkPanel';
4
+ export type { NetworkPanelProps } from './NetworkPanel';
5
+ export { StagedChangeBanner } from './StagedChangeBanner';
6
+ export type { StagedChangeBannerProps } from './StagedChangeBanner';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/network/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAChE,YAAY,EACR,oBAAoB,EACpB,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,MAAM,EACN,YAAY,GACf,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,YAAY,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1 @@
1
+ export{NetworkProvider,useNetwork}from"./NetworkProvider";export{NetworkPanel}from"./NetworkPanel";export{StagedChangeBanner}from"./StagedChangeBanner";
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ export interface ProjectManagerProps {
3
+ /** Override the project scope. Defaults to `useTis().selection.projectId`. */
4
+ projectId?: string;
5
+ }
6
+ export declare const ProjectManager: React.FC<ProjectManagerProps>;
7
+ //# sourceMappingURL=ProjectManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProjectManager.d.ts","sourceRoot":"","sources":["../../../src/components/tis/ProjectManager.tsx"],"names":[],"mappings":"AAmBA,OAAO,KAAuD,MAAM,OAAO,CAAC;AAU5E,MAAM,WAAW,mBAAmB;IAChC,8EAA8E;IAC9E,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAyBD,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CA+UxD,CAAC"}