@adcops/autocore-react 3.3.77 → 3.3.82

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.
@@ -1 +1 @@
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,CA8F9C,CAAC;AAEF,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,{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),[u,x]=useState(void 0);useEffect(()=>{if(!n||!l)return;const o=l(n,o=>{x(null==o?void 0:!!o)});return()=>{try{d&&void 0!==o&&d(o)}catch{}}},[n,l,d]);const p=pickColor(void 0!==o?o:u,t,r,e);if(null!=c){const o={backgroundColor:p,color:"white",display:"inline-flex",alignItems:"center",justifyContent:"center",borderRadius:0,boxShadow:"inset 0 1px 3px rgba(0, 0, 0, 0.45)",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:p,width:"22px",borderRadius:0,boxShadow:"inset 0 1px 2px rgba(0, 0, 0, 0.4)"};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;
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;
@@ -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;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
+ {"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,CAoIlD,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,wCA9KF,OAAO,CAAC,YAAY,CAAC,KAAK,IAAI,CAiLvD,CAAC"}
@@ -1 +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_ALERTS={assetCount:0,calibrationOverdue:0,laneUnavailable:0},AmsContext=createContext({schemas:{},schemasLoaded:!1,roles:{},rolesLoaded:!1,alerts:EMPTY_ALERTS,assets:[],refreshAssets:async()=>{},readAsset:async()=>null,listCalibrations:async()=>[],readCalibration:async()=>null,readUsage:async()=>null,selection:{assetType:null,assetId:null},setSelection:()=>{}});export const AmsProvider=({children:e})=>{const{invoke:s,subscribe:t,unsubscribe:a}=useContext(EventEmitterContext),[n,r]=useState({}),[c,o]=useState(!1),[u,l]=useState({}),[i,m]=useState(!1),[d,C]=useState(EMPTY_ALERTS),[x,y]=useState([]),[b,_]=useState({assetType:null,assetId:null}),A=useCallback(e=>{_(s=>({...s,...e}))},[]);useEffect(()=>{let e=!1;return(async()=>{try{const t=await s("ams.list_schemas",MessageType.Request,{});if(e)return;t?.success&&t.data&&(r(t.data.asset_types??{}),o(!0))}catch(e){}})(),(async()=>{try{const t=await s("ams.list_roles",MessageType.Request,{});if(e)return;t?.success&&t.data?(l(t.data.roles??{}),m(!0)):m(!0)}catch(e){m(!0)}})(),()=>{e=!0}},[]);const p=useCallback(async()=>{try{const e=await s("ams.list_assets",MessageType.Request,{include_retired:!0});e?.success&&y(e.data.assets??[])}catch(e){}},[s]);useEffect(()=>{p()},[p]),useEffect(()=>{const e=[t("ams.asset_changed",()=>{p()}),t("ams.calibration_added",()=>{p()}),t("ams.asset_count",e=>C(s=>({...s,assetCount:Number(e)||0}))),t("ams.alert_calibration_overdue",e=>C(s=>({...s,calibrationOverdue:Number(e)||0}))),t("ams.alert_lane_unavailable",e=>C(s=>({...s,laneUnavailable:Number(e)||0})))];return()=>{e.forEach(a)}},[t,a,p]);const h=useCallback(async e=>{try{const t=await s("ams.read_asset",MessageType.Request,{asset_id:e});return t?.success?t.data:null}catch{return null}},[s]),f=useCallback(async e=>{try{const t=await s("ams.list_calibrations",MessageType.Request,{asset_id:e});return t?.success?t.data.cal_ids??[]:[]}catch{return[]}},[s]),E=useCallback(async(e,t)=>{try{const a=await s("ams.read_calibration",MessageType.Request,{asset_id:e,cal_id:t});return a?.success?a.data:null}catch{return null}},[s]),S=useCallback(async e=>{try{const t=await s("ams.read_usage",MessageType.Request,{asset_id:e});return t?.success?t.data:null}catch{return null}},[s]),T=useMemo(()=>({schemas:n,schemasLoaded:c,roles:u,rolesLoaded:i,alerts:d,assets:x,refreshAssets:p,readAsset:h,listCalibrations:f,readCalibration:E,readUsage:S,selection:b,setSelection:A}),[n,c,u,i,d,x,p,h,f,E,S,b,A]);return _jsx(AmsContext.Provider,{value:T,children:e})};export const useAms=()=>useContext(AmsContext);export const useAmsSchemas=()=>useContext(AmsContext).schemas;export const useAmsRoles=()=>useContext(AmsContext).roles;export const useAmsAlerts=()=>useContext(AmsContext).alerts;export const useAmsAssets=()=>useContext(AmsContext).assets;export const useAmsSelection=()=>{const e=useContext(AmsContext);return[e.selection,e.setSelection]};
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_ALERTS={assetCount:0,calibrationOverdue:0,laneUnavailable:0},AmsContext=createContext({schemas:{},schemasLoaded:!1,roles:{},rolesLoaded:!1,alerts:EMPTY_ALERTS,assets:[],refreshAssets:async()=>{},readAsset:async()=>null,listCalibrations:async()=>[],readCalibration:async()=>null,readUsage:async()=>null,selection:{assetType:null,assetId:null},setSelection:()=>{}});export const AmsProvider=({children:e})=>{const{invoke:s,subscribe:t,unsubscribe:a}=useContext(EventEmitterContext),[n,r]=useState({}),[c,o]=useState(!1),[u,l]=useState({}),[i,m]=useState(!1),[d,C]=useState(EMPTY_ALERTS),[x,y]=useState([]),[b,_]=useState({assetType:null,assetId:null}),A=useCallback(e=>{_(s=>({...s,...e}))},[]);useEffect(()=>{let e=!1;return(async()=>{try{const t=await s("ams.list_schemas",MessageType.Request,{});if(e)return;t?.success&&t.data&&(r(t.data.asset_types??{}),o(!0))}catch(e){}})(),(async()=>{try{const t=await s("ams.list_roles",MessageType.Request,{});if(e)return;t?.success&&t.data?(l(t.data.roles??{}),m(!0)):m(!0)}catch(e){m(!0)}})(),()=>{e=!0}},[]);const p=useCallback(async()=>{try{const e=await s("ams.list_assets",MessageType.Request,{include_retired:!0});e?.success&&y(e.data.assets??[])}catch(e){}},[s]);useEffect(()=>{p()},[p]),useEffect(()=>{const e=[t("ams.asset_changed",()=>{p()}),t("ams.calibration_added",()=>{p()}),t("ams.calibration_updated",()=>{p()}),t("ams.asset_count",e=>C(s=>({...s,assetCount:Number(e)||0}))),t("ams.alert_calibration_overdue",e=>C(s=>({...s,calibrationOverdue:Number(e)||0}))),t("ams.alert_lane_unavailable",e=>C(s=>({...s,laneUnavailable:Number(e)||0})))];return()=>{e.forEach(a)}},[t,a,p]);const h=useCallback(async e=>{try{const t=await s("ams.read_asset",MessageType.Request,{asset_id:e});return t?.success?t.data:null}catch{return null}},[s]),f=useCallback(async e=>{try{const t=await s("ams.list_calibrations",MessageType.Request,{asset_id:e});return t?.success?t.data.cal_ids??[]:[]}catch{return[]}},[s]),E=useCallback(async(e,t)=>{try{const a=await s("ams.read_calibration",MessageType.Request,{asset_id:e,cal_id:t});return a?.success?a.data:null}catch{return null}},[s]),S=useCallback(async e=>{try{const t=await s("ams.read_usage",MessageType.Request,{asset_id:e});return t?.success?t.data:null}catch{return null}},[s]),T=useMemo(()=>({schemas:n,schemasLoaded:c,roles:u,rolesLoaded:i,alerts:d,assets:x,refreshAssets:p,readAsset:h,listCalibrations:f,readCalibration:E,readUsage:S,selection:b,setSelection:A}),[n,c,u,i,d,x,p,h,f,E,S,b,A]);return _jsx(AmsContext.Provider,{value:T,children:e})};export const useAms=()=>useContext(AmsContext);export const useAmsSchemas=()=>useContext(AmsContext).schemas;export const useAmsRoles=()=>useContext(AmsContext).roles;export const useAmsAlerts=()=>useContext(AmsContext).alerts;export const useAmsAssets=()=>useContext(AmsContext).assets;export const useAmsSelection=()=>{const e=useContext(AmsContext);return[e.selection,e.setSelection]};
@@ -1 +1 @@
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
+ {"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,EA8QnC,CAAC"}
@@ -1 +1 @@
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
+ 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:i,listCalibrations:r,readCalibration:a,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(null),[b,g]=useState(!1),v=async()=>{if(!e.assetId)return m(null),_([]),void h(null);const t=await i(e.assetId);m(t);const s=await r(e.assetId),n=await Promise.all(s.map(t=>a(e.assetId,t)));_(n.filter(Boolean));const o=await l(e.assetId);h(o)};if(useEffect(()=>{v()},[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 C=t[c.asset_type]?.label??c.asset_type,S=s[c.asset_type]?.find(e=>e.location===c.location),w=S?S.label??S.location:c.location,A=Array.isArray(t[c.asset_type]?.fields)?t[c.asset_type].fields:[],D=c.custom??{},I=S?.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:C}),_jsx("strong",{children:"Serial"})," ",_jsx("span",{children:c.serial||_jsx("em",{style:{color:"#9ca3af"},children:"(none)"})}),_jsx("strong",{children:"Role"})," ",_jsx("span",{children:w||_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})]}),I.length>0&&_jsxs("div",{style:{fontSize:"0.875rem",color:"#34d399"},children:["✓ Feeds module ",1===I.length?"config":"configs",":"," ",_jsx("strong",{children:I.join(", ")})," — ","their ",_jsxs("code",{children:["$","${ams.by_location."+c.location+".*}"]})," ","placeholders will resolve to the values below."]}),A.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:A.map(e=>{const t=D[e.name],s=null!=t&&""!==t,i=e.label??e.name,r=s?e.units?`${t} ${e.units}`:String(t):"(not set)";return _jsxs(React.Fragment,{children:[_jsx("strong",{title:e.description??void 0,children:i}),_jsx("span",{style:{color:s?void 0:"#f59e0b"},children:r})]},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:p.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 v())}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:b,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){g(!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{g(!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:()=>{j(null),f(!0)}})]})]}),_jsx(ConfirmDialog,{}),_jsxs(DataTable,{value:p,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(Column,{header:"",style:{width:"5rem"},body:e=>e.cal_id===c.current_calibration_id?_jsx(Button,{icon:"pi pi-pencil",text:!0,rounded:!0,size:"small",tooltip:"Edit this calibration (fixes a typo in place).",tooltipOptions:{position:"left"},onClick:()=>{j(e),f(!0)}}):null})]}),_jsx(CalibrationEntryDialog,{visible:x,assetId:c.asset_id,assetType:c.asset_type,editing:y,onHide:()=>{f(!1),j(null)},onAdded:()=>{v()}})]})};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 i=s[t]??{};return _jsxs("tr",{children:[_jsx("td",{style:{padding:"0.25rem 0.5rem",fontWeight:600},children:t}),e.fields.map(e=>{const t=i[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 i=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=i[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)})})]})})]})};
@@ -4,7 +4,22 @@ export interface CalibrationEntryDialogProps {
4
4
  assetId: string;
5
5
  assetType: string;
6
6
  onHide: () => void;
7
+ /** Fires after a successful add OR edit. The cal_id is the same as
8
+ * the editing record on edit, or a freshly minted id on add. */
7
9
  onAdded?: (calId: string) => void;
10
+ /** When set, the dialog opens in edit mode pre-seeded from this
11
+ * Calibration record. cal_id is preserved through the round-trip.
12
+ * Caller is responsible for only passing the asset's *current*
13
+ * calibration — the server rejects edits to historical records. */
14
+ editing?: {
15
+ cal_id: string;
16
+ performed_at?: string;
17
+ performed_by?: string;
18
+ expires_at?: string | null;
19
+ cert_ref?: string;
20
+ notes?: string;
21
+ values: any;
22
+ } | null;
8
23
  }
9
24
  export declare const CalibrationEntryDialog: React.FC<CalibrationEntryDialogProps>;
10
25
  //# sourceMappingURL=CalibrationEntryDialog.d.ts.map
@@ -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;AAwBD,eAAO,MAAM,sBAAsB,EAAE,KAAK,CAAC,EAAE,CAAC,2BAA2B,CAsRxE,CAAC"}
1
+ {"version":3,"file":"CalibrationEntryDialog.d.ts","sourceRoot":"","sources":["../../../src/components/ams/CalibrationEntryDialog.tsx"],"names":[],"mappings":"AAgBA,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;qEACiE;IACjE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC;;;wEAGoE;IACpE,OAAO,CAAC,EAAE;QACN,MAAM,EAAE,MAAM,CAAC;QACf,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,GAAG,CAAC;KACf,GAAG,IAAI,CAAC;CACZ;AAwBD,eAAO,MAAM,sBAAsB,EAAE,KAAK,CAAC,EAAE,CAAC,2BAA2B,CA+TxE,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: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})]})};
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:l,editing:n})=>{const s=!!n,i=useAmsSchemas(),{invoke:o}=useContext(EventEmitterContext),u=i[a]?.calibration_fields??[],d=(()=>{const e=i[a]?.sub_locations;return e&&Array.isArray(e.keys)?e:null})(),m=d?.calibration_fields??[],c=m.length>0,[p,x]=useState({}),[h,_]=useState({}),[g,f]=useState(""),[v,b]=useState(null),[j,y]=useState(""),[C,I]=useState(""),[S,w]=useState(!1),[T,$]=useState(null);useEffect(()=>{e&&($(null),n?(c?(x({}),_(n.values&&"object"==typeof n.values?n.values:{})):(x(n.values&&"object"==typeof n.values?n.values:{}),_({})),f(n.performed_by??""),b(n.expires_at?new Date(n.expires_at):null),y(n.cert_ref??""),I(n.notes??"")):(x({}),_({}),f(""),b(null),y(""),I("")))},[e,n,c]);return _jsxs(Dialog,{header:s?`Edit Calibration ${n.cal_id} — ${t}`:`Add Calibration — ${t}`,visible:e,onHide:r,style:{width:"40rem"},footer:_jsxs(_Fragment,{children:[_jsx(Button,{label:"Cancel",severity:"secondary",onClick:r,disabled:S}),_jsx(Button,{label:"Save",icon:"pi pi-check",onClick:async()=>{if(c&&d)for(const e of d.keys)for(const t of m){if(!t.required)continue;const a=h[e]?.[t.name];if(null==a||""===a)return void $(`Field "${t.label??t.name}" on axis "${e}" is required.`)}else for(const e of u)if(e.required&&(void 0===p[e.name]||null===p[e.name]||""===p[e.name]))return void $(`Field "${e.label??e.name}" is required.`);const e=c?h:p;w(!0),$(null);try{const a=s?"ams.update_calibration":"ams.add_calibration",i={asset_id:t,performed_by:g,expires_at:v?v.toISOString():null,cert_ref:j,notes:C,values:e};s&&n&&(i.cal_id=n.cal_id);const u=await o(a,MessageType.Request,i);u?.success?(l?.(u.data.cal_id),r()):$(u?.error_message??`${a} failed`)}catch(e){$(String(e?.message??e))}finally{w(!1)}},loading:S})]}),children:[_jsxs("div",c&&d?{children:[_jsx("h4",{style:{margin:"0 0 0.5rem 0"},children:d.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:d.key_label??"Key"}),m.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:d.keys.map(e=>_jsxs("tr",{children:[_jsx("td",{style:{padding:"0.25rem 0.5rem",fontWeight:600},children:e}),m.map(t=>{const a=h[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=>{_(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=>{_(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:g,onChange:e=>f(e.target.value)}),_jsx("label",{children:"Expires at"}),_jsx(Calendar,{value:v,onChange:e=>b(e.value??null),showIcon:!0,dateFormat:"yy-mm-dd"}),_jsx("label",{children:"Certificate ref"}),_jsx(InputText,{value:j,onChange:e=>y(e.target.value)}),_jsx("label",{children:"Notes"}),_jsx(InputText,{value:C,onChange:e=>I(e.target.value)})]})]}:{style:{display:"grid",gridTemplateColumns:"auto 1fr",gap:"0.5rem 1rem",alignItems:"center"},children:[u.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=>x(a=>({...a,[e.name]:t}));let l;switch(e.type){case"string":default:l=_jsx(InputText,{value:p[e.name]??"",onChange:e=>r(e.target.value)});break;case"enum":l=_jsx(Dropdown,{value:p[e.name]??null,options:(e.values??[]).map(e=>({label:e,value:e})),onChange:e=>r(e.value),placeholder:"Choose…"});break;case"bool":l=_jsx(Dropdown,{value:p[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":l=_jsx(InputNumber,{value:p[e.name]??null,onValueChange:e=>r(e.value),useGrouping:!1,maxFractionDigits:e.type.startsWith("f")?9:0})}return[a,l]})(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:g,onChange:e=>f(e.target.value)}),_jsx("label",{children:"Expires at"}),_jsx(Calendar,{value:v,onChange:e=>b(e.value??null),showIcon:!0,dateFormat:"yy-mm-dd"}),_jsx("label",{children:"Certificate ref"}),_jsx(InputText,{value:j,onChange:e=>y(e.target.value)}),_jsx("label",{children:"Notes"}),_jsx(InputText,{value:C,onChange:e=>I(e.target.value)})]}),T&&_jsx("div",{style:{marginTop:"1rem",color:"#ef4444"},children:T})]})};
@@ -1 +1 @@
1
- {"version":3,"file":"ProjectManager.d.ts","sourceRoot":"","sources":["../../../src/components/tis/ProjectManager.tsx"],"names":[],"mappings":"AAiBA,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,CAgVxD,CAAC"}
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"}
@@ -1 +1 @@
1
- import{jsx as _jsx,Fragment as _Fragment,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{ConfirmDialog,confirmDialog}from"primereact/confirmdialog";import{ProgressBar}from"primereact/progressbar";import{EventEmitterContext}from"../../core/EventEmitterContext";import{MessageType}from"../../hub/CommandMessage";import{useTis}from"./TisProvider";const formatBytes=e=>{if(!Number.isFinite(e)||e<=0)return"0 B";const t=["B","KiB","MiB","GiB","TiB","PiB"];let r=0,s=e;for(;s>=1024&&r<t.length-1;)s/=1024,r++;return`${s.toFixed(s>=100?0:s>=10?1:2)} ${t[r]}`},formatDate=e=>{if(!e)return"";const t=new Date(e);return Number.isNaN(t.getTime())?e:t.toLocaleString()};export const ProjectManager=e=>{const t=useTis(),r=e.projectId??t.selection.projectId,{invoke:s}=useContext(EventEmitterContext),[i,a]=useState([]),[o,n]=useState(!1),[l,c]=useState(null),[d,m]=useState(!1),[p,u]=useState(!1),[f,h]=useState(null),[g,_]=useState(""),y=useCallback(async()=>{if(r){n(!0);try{const e=await s("tis.list_tests",MessageType.Request,{project_id:r});e?.success&&e.data?.tests?a(e.data.tests):a([])}catch(e){a([])}finally{n(!1)}}else a([])},[r,s]),j=useCallback(async()=>{try{const e=await s("tis.disk_usage",MessageType.Request,{});e?.success&&e.data?(h(e.data),_("")):(h(null),_(e?.error_message??"disk_usage failed"))}catch(e){h(null),_(e instanceof Error?e.message:String(e))}},[s]);useEffect(()=>{y()},[y,t.state.activeRunId]),useEffect(()=>{j()},[j]);const b=e=>{const i=e?.run_id??"",a=e?.sample_id??"";confirmDialog({header:"Delete test",icon:"pi pi-exclamation-triangle",acceptLabel:"Delete",rejectLabel:"Cancel",acceptClassName:"p-button-danger",message:_jsxs("div",{children:[_jsxs("p",{style:{marginTop:0},children:["Permanently delete run ",_jsx("code",{children:i}),a?_jsxs(_Fragment,{children:[" (sample ",_jsx("code",{children:a}),")"]}):null,"?"]}),_jsxs("p",{style:{marginBottom:0,fontSize:"0.875rem",color:"#9ca3af"},children:["Removes ",_jsx("code",{children:"test.json"}),", cycles, raw and filtered data for this run. This action cannot be undone."]})]}),accept:()=>{(async e=>{const i=e?.run_id,a=e?.method_id;if(r&&a&&i){c(i);try{const e=await s("tis.delete_test",MessageType.Request,{project_id:r,method_id:a,run_id:i});if(!e?.success)return void alert(`Failed to delete test ${i}`+(e?.error_message?`: ${e.error_message}`:""));await y(),t.selection.runId===i&&t.setSelection({runId:null})}catch(e){alert(`Delete failed: ${e instanceof Error?e.message:String(e)}`)}finally{c(null)}}})(e)}})},x=e=>{const t="string"==typeof e?.sample_id?e.sample_id:"";if(t)return t;const r=e?.config;return r&&"object"==typeof r&&"string"==typeof r.sample_id?r.sample_id:""},v=f&&f.total_bytes>0?Math.min(100,Math.round(f.used_bytes/f.total_bytes*100)):0;return _jsxs("div",{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:[_jsx("h3",{style:{margin:0},children:r?`Project Manager: ${r}`:"Project Manager (no project selected)"}),_jsxs("div",{style:{display:"flex",gap:"0.4rem",alignItems:"center",flexWrap:"wrap"},children:[_jsx(Button,{icon:p?"pi pi-spin pi-spinner":"pi pi-box",label:"Download Archive",size:"small",outlined:!0,disabled:!r||p||d,onClick:async()=>{if(r){u(!0);try{const e=await s("tis.export_project_zip",MessageType.Request,{project_id:r});if(!e?.success)return void alert("Failed to build project archive"+(e?.error_message?`: ${e.error_message}`:""));const t="string"==typeof e.data?.download_url?e.data.download_url:"";if(!t)return void alert("Server did not return a download URL for the archive.");const i=document.createElement("a");i.href=t,i.download="string"==typeof e.data?.filename?e.data.filename:`${r}_project_archive.zip`,document.body.appendChild(i),i.click(),i.remove()}catch(e){alert(`Download failed: ${e instanceof Error?e.message:String(e)}`)}finally{u(!1)}}},tooltip:"Download a ZIP of the entire project directory",tooltipOptions:{position:"bottom"}}),_jsx(Button,{icon:d?"pi pi-spin pi-spinner":"pi pi-trash",label:"Delete Project",size:"small",severity:"danger",disabled:!r||d||p,onClick:()=>{if(!r)return;const e=i.length;confirmDialog({header:"Delete project",icon:"pi pi-exclamation-triangle",acceptLabel:"Delete Project",rejectLabel:"Cancel",acceptClassName:"p-button-danger",message:_jsxs("div",{children:[_jsxs("p",{style:{marginTop:0},children:["Permanently delete project ",_jsx("code",{children:r})," and all ",_jsx("strong",{children:e})," test",1===e?"":"s"," inside it?"]}),_jsx("p",{style:{marginBottom:0,fontSize:"0.875rem",color:"#9ca3af"},children:"This removes every method, run, cycle, and raw/filtered blob under the project. Consider downloading the archive first. This action cannot be undone."})]}),accept:()=>{(async()=>{if(r){m(!0);try{const e=await s("tis.delete_project",MessageType.Request,{project_id:r});if(!e?.success)return void alert(`Failed to delete project ${r}`+(e?.error_message?`: ${e.error_message}`:""));t.setSelection({projectId:null,methodId:null,sampleId:null,runId:null}),await t.refreshProjects(),await j(),a([])}catch(e){alert(`Delete failed: ${e instanceof Error?e.message:String(e)}`)}finally{m(!1)}}})()}})},tooltip:"Permanently delete the project and every test inside it",tooltipOptions:{position:"bottom"}}),_jsx(Button,{icon:"pi pi-refresh",label:"Refresh",size:"small",onClick:()=>{y(),j()},disabled:o})]})]}),_jsxs("div",{style:{marginBottom:"1rem",padding:"0.75rem 1rem",border:"1px solid #2a2a2a",borderRadius:4,background:"#161616"},children:[_jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"baseline",flexWrap:"wrap",gap:"0.5rem"},children:[_jsx("strong",{children:"Server Disk Space"}),f?_jsxs("span",{style:{fontSize:"0.875rem",color:"#9ca3af"},children:[formatBytes(f.available_bytes)," free of ",formatBytes(f.total_bytes)," ","(",100-v,"% available)"]}):_jsx("span",g?{style:{fontSize:"0.875rem",color:"#f87171"},children:g}:{style:{fontSize:"0.875rem",color:"#9ca3af"},children:"Loading…"})]}),f&&_jsxs(_Fragment,{children:[_jsx(ProgressBar,{value:v,showValue:!1,style:{height:"0.5rem",marginTop:"0.5rem"},color:v>=90?"#dc2626":v>=75?"#f59e0b":void 0}),_jsx("div",{style:{fontSize:"0.75rem",color:"#6b7280",marginTop:"0.4rem"},children:_jsx("code",{children:f.base_directory})})]})]}),_jsxs(DataTable,{value:i,loading:o,paginator:!0,rows:10,emptyMessage:r?"No tests in this project.":"Select a project to manage.",scrollable:!0,scrollHeight:"flex",tableStyle:{minWidth:0},style:{width:"100%"},children:[_jsx(Column,{header:"Sample ID",body:x,sortable:!0,sortFunction:e=>{const t=[...e.data];return t.sort((t,r)=>x(t).localeCompare(x(r))*(e.order??1)),t},style:{minWidth:"8rem"}}),_jsx(Column,{field:"start_time",header:"Date/Time",sortable:!0,body:e=>formatDate(e.start_time),style:{minWidth:"12rem"}}),_jsx(Column,{field:"method_id",header:"Test Method",sortable:!0,style:{minWidth:"10rem"}}),_jsx(Column,{field:"run_id",header:"Run ID",sortable:!0,style:{minWidth:"12rem"}}),_jsx(Column,{header:"Action",style:{width:"8rem"},body:e=>{const t=l===e.run_id;return _jsx(Button,{icon:t?"pi pi-spin pi-spinner":"pi pi-trash",label:"Delete",size:"small",severity:"danger",outlined:!0,disabled:null!==l||d,onClick:()=>b(e),tooltip:"Permanently delete this test",tooltipOptions:{position:"left"}})}})]})]})};
1
+ import{jsx as _jsx,Fragment as _Fragment,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{confirmDialog}from"primereact/confirmdialog";import{ProgressBar}from"primereact/progressbar";import{EventEmitterContext}from"../../core/EventEmitterContext";import{MessageType}from"../../hub/CommandMessage";import{useTis}from"./TisProvider";const formatBytes=e=>{if(!Number.isFinite(e)||e<=0)return"0 B";const t=["B","KiB","MiB","GiB","TiB","PiB"];let r=0,s=e;for(;s>=1024&&r<t.length-1;)s/=1024,r++;return`${s.toFixed(s>=100?0:s>=10?1:2)} ${t[r]}`},formatDate=e=>{if(!e)return"";const t=new Date(e);return Number.isNaN(t.getTime())?e:t.toLocaleString()};export const ProjectManager=e=>{const t=useTis(),r=e.projectId??t.selection.projectId,{invoke:s}=useContext(EventEmitterContext),[a,i]=useState([]),[o,n]=useState(!1),[l,c]=useState(null),[d,m]=useState(!1),[p,u]=useState(!1),[f,h]=useState(null),[g,_]=useState(""),y=useCallback(async()=>{if(r){n(!0);try{const e=await s("tis.list_tests",MessageType.Request,{project_id:r});e?.success&&e.data?.tests?i(e.data.tests):i([])}catch(e){i([])}finally{n(!1)}}else i([])},[r,s]),j=useCallback(async()=>{try{const e=await s("tis.disk_usage",MessageType.Request,{});e?.success&&e.data?(h(e.data),_("")):(h(null),_(e?.error_message??"disk_usage failed"))}catch(e){h(null),_(e instanceof Error?e.message:String(e))}},[s]);useEffect(()=>{y()},[y,t.state.activeRunId]),useEffect(()=>{j()},[j]);const b=e=>{const a=e?.run_id??"",i=e?.sample_id??"";confirmDialog({header:"Delete test",icon:"pi pi-exclamation-triangle",acceptLabel:"Delete",rejectLabel:"Cancel",acceptClassName:"p-button-danger",message:_jsxs("div",{children:[_jsxs("p",{style:{marginTop:0},children:["Permanently delete run ",_jsx("code",{children:a}),i?_jsxs(_Fragment,{children:[" (sample ",_jsx("code",{children:i}),")"]}):null,"?"]}),_jsxs("p",{style:{marginBottom:0,fontSize:"0.875rem",color:"#9ca3af"},children:["Removes ",_jsx("code",{children:"test.json"}),", cycles, raw and filtered data for this run. This action cannot be undone."]})]}),accept:()=>{(async e=>{const a=e?.run_id,i=e?.method_id;if(r&&i&&a){c(a);try{const e=await s("tis.delete_test",MessageType.Request,{project_id:r,method_id:i,run_id:a});if(!e?.success)return void alert(`Failed to delete test ${a}`+(e?.error_message?`: ${e.error_message}`:""));await y(),t.selection.runId===a&&t.setSelection({runId:null})}catch(e){alert(`Delete failed: ${e instanceof Error?e.message:String(e)}`)}finally{c(null)}}})(e)}})},x=e=>{const t="string"==typeof e?.sample_id?e.sample_id:"";if(t)return t;const r=e?.config;return r&&"object"==typeof r&&"string"==typeof r.sample_id?r.sample_id:""},v=f&&f.total_bytes>0?Math.min(100,Math.round(f.used_bytes/f.total_bytes*100)):0;return _jsxs("div",{style:{width:"100%",maxWidth:"100%",boxSizing:"border-box"},children:[_jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:"1rem",gap:"0.5rem",flexWrap:"wrap"},children:[_jsx("h3",{style:{margin:0},children:r?`Project Manager: ${r}`:"Project Manager (no project selected)"}),_jsxs("div",{style:{display:"flex",gap:"0.4rem",alignItems:"center",flexWrap:"wrap"},children:[_jsx(Button,{icon:p?"pi pi-spin pi-spinner":"pi pi-box",label:"Download Archive",size:"small",outlined:!0,disabled:!r||p||d,onClick:async()=>{if(r){u(!0);try{const e=await s("tis.export_project_zip",MessageType.Request,{project_id:r});if(!e?.success)return void alert("Failed to build project archive"+(e?.error_message?`: ${e.error_message}`:""));const t="string"==typeof e.data?.download_url?e.data.download_url:"";if(!t)return void alert("Server did not return a download URL for the archive.");const a=document.createElement("a");a.href=t,a.download="string"==typeof e.data?.filename?e.data.filename:`${r}_project_archive.zip`,document.body.appendChild(a),a.click(),a.remove()}catch(e){alert(`Download failed: ${e instanceof Error?e.message:String(e)}`)}finally{u(!1)}}},tooltip:"Download a ZIP of the entire project directory",tooltipOptions:{position:"bottom"}}),_jsx(Button,{icon:d?"pi pi-spin pi-spinner":"pi pi-trash",label:"Delete Project",size:"small",severity:"danger",disabled:!r||d||p,onClick:()=>{if(!r)return;const e=a.length;confirmDialog({header:"Delete project",icon:"pi pi-exclamation-triangle",acceptLabel:"Delete Project",rejectLabel:"Cancel",acceptClassName:"p-button-danger",message:_jsxs("div",{children:[_jsxs("p",{style:{marginTop:0},children:["Permanently delete project ",_jsx("code",{children:r})," and all ",_jsx("strong",{children:e})," test",1===e?"":"s"," inside it?"]}),_jsx("p",{style:{marginBottom:0,fontSize:"0.875rem",color:"#9ca3af"},children:"This removes every method, run, cycle, and raw/filtered blob under the project. Consider downloading the archive first. This action cannot be undone."})]}),accept:()=>{(async()=>{if(r){m(!0);try{const e=await s("tis.delete_project",MessageType.Request,{project_id:r});if(!e?.success)return void alert(`Failed to delete project ${r}`+(e?.error_message?`: ${e.error_message}`:""));t.setSelection({projectId:null,methodId:null,sampleId:null,runId:null}),await t.refreshProjects(),await j(),i([])}catch(e){alert(`Delete failed: ${e instanceof Error?e.message:String(e)}`)}finally{m(!1)}}})()}})},tooltip:"Permanently delete the project and every test inside it",tooltipOptions:{position:"bottom"}}),_jsx(Button,{icon:"pi pi-refresh",label:"Refresh",size:"small",onClick:()=>{y(),j()},disabled:o})]})]}),_jsxs("div",{style:{marginBottom:"1rem",padding:"0.75rem 1rem",border:"1px solid #2a2a2a",borderRadius:4,background:"#161616"},children:[_jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"baseline",flexWrap:"wrap",gap:"0.5rem"},children:[_jsx("strong",{children:"Server Disk Space"}),f?_jsxs("span",{style:{fontSize:"0.875rem",color:"#9ca3af"},children:[formatBytes(f.available_bytes)," free of ",formatBytes(f.total_bytes)," ","(",100-v,"% available)"]}):_jsx("span",g?{style:{fontSize:"0.875rem",color:"#f87171"},children:g}:{style:{fontSize:"0.875rem",color:"#9ca3af"},children:"Loading…"})]}),f&&_jsxs(_Fragment,{children:[_jsx(ProgressBar,{value:v,showValue:!1,style:{height:"0.5rem",marginTop:"0.5rem"},color:v>=90?"#dc2626":v>=75?"#f59e0b":void 0}),_jsx("div",{style:{fontSize:"0.75rem",color:"#6b7280",marginTop:"0.4rem"},children:_jsx("code",{children:f.base_directory})})]})]}),_jsxs(DataTable,{value:a,loading:o,paginator:!0,rows:10,emptyMessage:r?"No tests in this project.":"Select a project to manage.",scrollable:!0,scrollHeight:"flex",tableStyle:{minWidth:0},style:{width:"100%"},children:[_jsx(Column,{header:"Sample ID",body:x,sortable:!0,sortFunction:e=>{const t=[...e.data];return t.sort((t,r)=>x(t).localeCompare(x(r))*(e.order??1)),t},style:{minWidth:"8rem"}}),_jsx(Column,{field:"start_time",header:"Date/Time",sortable:!0,body:e=>formatDate(e.start_time),style:{minWidth:"12rem"}}),_jsx(Column,{field:"method_id",header:"Test Method",sortable:!0,style:{minWidth:"10rem"}}),_jsx(Column,{field:"run_id",header:"Run ID",sortable:!0,style:{minWidth:"12rem"}}),_jsx(Column,{header:"Action",style:{width:"8rem"},body:e=>{const t=l===e.run_id;return _jsx(Button,{icon:t?"pi pi-spin pi-spinner":"pi pi-trash",label:"Delete",size:"small",severity:"danger",outlined:!0,disabled:null!==l||d,onClick:()=>b(e),tooltip:"Permanently delete this test",tooltipOptions:{position:"left"}})}})]})]})};
@@ -1 +1 @@
1
- {"version":3,"file":"TestSetupForm.d.ts","sourceRoot":"","sources":["../../../src/components/tis/TestSetupForm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA2D,MAAM,OAAO,CAAC;AAchF;;;;;GAKG;AACH,UAAU,WAAW;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,aAAa,GAAG,aAAa,CAAC;IACtC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IACzB,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;0EACsE;IACtE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;kCAK8B;IAC9B,OAAO,CAAC,EAAE,GAAG,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACvB,cAAc,EAAE,YAAY,EAAE,CAAC;IAC/B,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,YAAY,EAAE,YAAY,EAAE,CAAC;IAC7B,cAAc,EAAE,YAAY,EAAE,CAAC;IAC/B;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,WAAW,EAAE,CAAC;IAC3B;0CACsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;2CACuC;IACvC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;gEAG4D;IAC5D,QAAQ,CAAC,EAAE,GAAG,CAAC;IACf;;sDAEkD;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC/B;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,kBAAkB;IAC/B,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;CAChE;AAyED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAsdtD,CAAC"}
1
+ {"version":3,"file":"TestSetupForm.d.ts","sourceRoot":"","sources":["../../../src/components/tis/TestSetupForm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA2D,MAAM,OAAO,CAAC;AAchF;;;;;GAKG;AACH,UAAU,WAAW;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,aAAa,GAAG,aAAa,CAAC;IACtC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IACzB,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;0EACsE;IACtE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;kCAK8B;IAC9B,OAAO,CAAC,EAAE,GAAG,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACvB,cAAc,EAAE,YAAY,EAAE,CAAC;IAC/B,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,YAAY,EAAE,YAAY,EAAE,CAAC;IAC7B,cAAc,EAAE,YAAY,EAAE,CAAC;IAC/B;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,WAAW,EAAE,CAAC;IAC3B;0CACsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;2CACuC;IACvC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;gEAG4D;IAC5D,QAAQ,CAAC,EAAE,GAAG,CAAC;IACf;;sDAEkD;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC/B;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,kBAAkB;IAC/B,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;CAChE;AAyED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAsetD,CAAC"}
@@ -1 +1 @@
1
- import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import React,{useState,useEffect,useContext,useMemo,useRef}from"react";import{Button}from"primereact/button";import{InputText}from"primereact/inputtext";import{Dropdown}from"primereact/dropdown";import{Dialog}from"primereact/dialog";import{EventEmitterContext}from"../../core/EventEmitterContext";import{AutoCoreTagContext}from"../../core/AutoCoreTagContext";import{MessageType}from"../../hub/CommandMessage";import{ValueInput}from"../ValueInput";import{TextInput}from"../TextInput";import{useTis}from"./TisProvider";import{useAmsAssets,useAmsRoles}from"../ams/AmsProvider";import{TestMethodDialog}from"./TestMethodDialog";const labelOf=e=>{const t=e.label&&e.label.length>0?e.label:e.name;return e.units?`${t} [${e.units}]`:t},hasDescription=e=>"string"==typeof e.description&&e.description.length>0,methodLabelOf=(e,t)=>t?.label&&t.label.length>0?t.label:e,AssetIdPicker=({assetType:e,value:t,onChange:s,invalid:i})=>{const a=useAmsAssets(),n=useAmsRoles(),o=useMemo(()=>a.filter(t=>t.asset_type===e&&"active"===t.status).map(e=>{const t=n[e.asset_type]?.find(t=>t.location===e.location)?.label,s=[e.asset_id];return t?s.push(`— ${t}`):e.location&&s.push(`— ${e.location}`),e.serial&&s.push(`(s/n ${e.serial})`),{label:s.join(" "),value:e.asset_id}}),[a,n,e]);return _jsx(Dropdown,{value:t,options:o,onChange:e=>s(e.value??""),placeholder:0===o.length?`No active ${e} assets registered — add one in Settings → Assets`:`Select ${e}…`,className:i?"p-invalid":"",filter:!0,showClear:!0,disabled:0===o.length})};export const TestSetupForm=({schema:e,defaultMethodId:t,onMethodChange:s,onValidationChange:i})=>{const a=useTis(),{invoke:n,write:o}=useContext(EventEmitterContext),{rawValues:r,findTagByFqdn:l}=useContext(AutoCoreTagContext),c=useMemo(()=>Object.keys(a.schemas),[a.schemas]),d=a.selection.projectId,m=""!==d.trim()&&a.projectKnown(d.trim()),[p,u]=useState(a.selection.methodId||t||a.defaultMethodId||""),[f,h]=useState(a.selection.sampleId||""),g=a.stagedConfig,x=e=>{const t="function"==typeof e?e(a.stagedConfig):e;t!==a.stagedConfig&&a.setStagedConfig(t)},_=e??(p?a.schemas[p]:void 0);useEffect(()=>{a.selection.methodId!==p&&p&&a.setSelection({methodId:p}),s&&s(p)},[p]),useEffect(()=>{a.selection.sampleId!==f&&a.setSelection({sampleId:f})},[f]),useEffect(()=>{a.state.stagedSampleId&&a.state.stagedSampleId!==f&&h(a.state.stagedSampleId)},[a.state.stagedSampleId]),useEffect(()=>{a.selection.methodId&&a.selection.methodId!==p&&u(a.selection.methodId)},[a.selection.methodId]);const[j,v]=useState(!1),[y,b]=useState(!1),[I,C]=useState({open:!1,title:"",body:null}),S=useRef("");useEffect(()=>{_&&p&&S.current!==p&&(S.current=p,x(e=>{let t=e;for(const s of _.config_fields)"sample_id"!==s.name&&void 0!==s.default&&null!==s.default&&(t===e&&(t={...e}),t[s.name]=s.default,s.source&&Promise.resolve().then(()=>o(s.source,s.default)).catch(e=>{}));return t}))},[_,p,o]),useEffect(()=>{_&&x(e=>{let t=e;for(const s of _.config_fields){if("sample_id"===s.name)continue;if(!s.source)continue;const i=l(s.source);if(!i)continue;const a=r[i.tagName];null!=a&&(t[s.name]!==a&&(t===e&&(t={...e}),t[s.name]=a))}return t})},[_,r,l]),useEffect(()=>{if(!_)return void v(!1);let e=!0;m||(e=!1),p.trim()||(e=!1),f.trim()||(e=!1),e&&!a.projectFieldsLoaded&&(e=!1);for(const t of _.config_fields)if("sample_id"!==t.name&&t.required){const s=g[t.name];if(void 0===s||""===s||null===s){e=!1;break}}if(v(e),i&&i(e,g),e){const{sample_id:e,...t}=g??{},s={...a.projectFields,...t};n("tis.stage_test",MessageType.Request,{project_id:d,method_id:p,sample_id:f,config:s}).catch(e=>{})}},[g,_,d,p,f,m,a.projectFields,a.projectFieldsLoaded,i,n]);const T=async(e,t)=>{if(x({...g,[e.name]:t}),e.source)try{await o(e.source,t)}catch(e){}};if(!_)return _jsx("div",{className:"ac-form-grid",style:{padding:"1.25rem"},children:_jsx("h3",{className:"ac-form-section",children:a.schemasLoaded?"No Test Method Selected":"Loading test methods…"})});if(!m)return _jsxs("div",{style:{padding:"1.25rem",maxWidth:"600px"},children:[_jsx("h3",{className:"ac-form-section",children:"No project selected"}),_jsxs("p",{style:{color:"var(--text-secondary-color)",marginTop:"0.5rem"},children:["Pick a project on the ",_jsx("strong",{children:"Project"})," tab first",""!==d.trim()&&` (or click + there to create "${d.trim()}")`,"."]})]});const N=j&&!a.state.lastStartError;return _jsxs("div",{className:"ac-form-grid",style:{padding:"1.25rem",gridTemplateColumns:"auto 1fr 1.75rem 1.75rem"},children:[_jsxs("h3",{className:"ac-form-section",style:{display:"flex",alignItems:"center",gap:"10px"},children:["Test Setup",_jsx(Button,{icon:N?"pi pi-check-circle":"pi pi-exclamation-circle",severity:N?"success":"danger",text:!0,rounded:!0,"aria-label":"Test Setup status",onClick:()=>{const e=(()=>{const e=[];if(m||e.push("No project is selected. Pick or create one on the Project tab."),a.projectFieldsLoaded||e.push("Project fields are still loading."),p.trim()||e.push("No test method selected."),f.trim()||e.push("Sample ID is required."),_)for(const t of _.config_fields){if("sample_id"===t.name)continue;if(!t.required)continue;const s=g[t.name];void 0!==s&&""!==s&&null!==s||e.push(`Required field "${labelOf(t)}" is empty.`)}return e})(),t=a.state.lastStartError?.trim()??"";let s;s=0!==e.length||t?_jsxs("div",{children:[e.length>0&&_jsxs(_Fragment,{children:[_jsx("p",{style:{margin:"0 0 0.5rem 0"},children:"The form is incomplete:"}),_jsx("ul",{style:{margin:"0 0 1rem 1.25rem"},children:e.map((e,t)=>_jsx("li",{children:e},t))})]}),t&&_jsxs(_Fragment,{children:[_jsx("p",{style:{margin:"0 0 0.25rem 0",fontWeight:600},children:"Last start_test error from the server:"}),_jsx("pre",{style:{margin:0,padding:"0.5rem",background:"rgba(0,0,0,0.25)",borderRadius:"4px",whiteSpace:"pre-wrap",fontSize:"0.875rem"},children:t})]})]}):_jsx("p",{style:{margin:0},children:"All required fields are complete. The test is staged and ready to start."}),C({open:!0,title:"Test Setup Status",body:s})}}),_jsxs("span",{style:{fontSize:"0.85em",color:"var(--text-secondary-color)",fontWeight:"normal",marginLeft:"0.25rem"},children:["project: ",_jsx("strong",{children:d})]})]}),_jsx("span",{className:"ac-form-label",children:"Sample ID"}),_jsx(TextInput,{label:void 0,value:f,onValueChanged:e=>{h(e)},className:f.trim()?"":"p-invalid"}),_jsx("span",{"aria-hidden":"true"}),_jsx("span",{style:{color:f.trim()?"var(--green-500)":"var(--red-500)",display:"flex",alignItems:"center"},children:_jsx("i",{className:f.trim()?"pi pi-check":"pi pi-times"})}),c.length>0&&_jsxs(_Fragment,{children:[_jsx("span",{className:"ac-form-label",children:"Test Method"}),_jsxs("div",{className:"p-inputgroup",style:{flex:1},children:[_jsx(InputText,{value:methodLabelOf(p,_),readOnly:!0,style:{flex:1},tabIndex:-1}),_jsx(Button,{icon:"pi pi-pencil",type:"button",onClick:()=>b(!0),tooltip:c.length>1?"Change test method":"View test method details",tooltipOptions:{position:"top"}})]}),_jsx("span",{"aria-hidden":"true"}),_jsx("span",{style:{color:p?"var(--green-500)":"var(--red-500)",display:"flex",alignItems:"center"},children:_jsx("i",{className:p?"pi pi-check":"pi pi-times"})})]}),_jsx("h3",{className:"ac-form-section",style:{marginTop:"1rem"},children:"Test Configuration"}),_.config_fields.map(e=>{if("sample_id"===e.name)return null;const t=(e=>{if(!e.required)return!0;const t=g[e.name];return void 0!==t&&""!==t&&null!==t})(e),s=(e=>{const t=_?.asset_refs??[],s=`config.${e.name}`,i=t.find(e=>"by_id_field"===e.select&&e.from===s);return i?i.asset_type:null})(e),i=!s&&"string"!==e.type&&"bool"!==e.type;return _jsxs(React.Fragment,{children:[_jsx("span",{className:"ac-form-label",children:labelOf(e)}),s?_jsx(AssetIdPicker,{assetType:s,value:null!=g[e.name]?String(g[e.name]):"",onChange:t=>T(e,t),invalid:!t}):i?_jsx(ValueInput,{label:void 0,value:null!=g[e.name]?Number(g[e.name]):null,onValueChanged:t=>T(e,t),className:t?"":"p-invalid"}):_jsx(TextInput,{label:void 0,value:null!=g[e.name]?String(g[e.name]):"",onValueChanged:t=>T(e,t),className:t?"":"p-invalid"}),hasDescription(e)?_jsx(Button,{icon:"pi pi-info-circle",text:!0,rounded:!0,"aria-label":`About ${labelOf(e)}`,onClick:()=>C({open:!0,title:labelOf(e),body:_jsx("p",{style:{margin:0,whiteSpace:"pre-wrap"},children:e.description})})}):_jsx("span",{"aria-hidden":"true"}),_jsx("span",{style:{color:t?"var(--green-500)":"var(--red-500)",display:"flex",alignItems:"center"},children:_jsx("i",{className:t?"pi pi-check":"pi pi-times"})})]},e.name)}),_jsx(TestMethodDialog,{visible:y,onHide:()=>b(!1),currentMethodId:p,onSelected:e=>u(e)}),_jsx(Dialog,{header:I.title,visible:I.open,onHide:()=>C({open:!1,title:"",body:null}),style:{width:"32rem",maxWidth:"90vw"},modal:!0,dismissableMask:!0,children:I.body})]})};
1
+ import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import React,{useState,useEffect,useContext,useMemo,useRef}from"react";import{Button}from"primereact/button";import{InputText}from"primereact/inputtext";import{Dropdown}from"primereact/dropdown";import{Dialog}from"primereact/dialog";import{EventEmitterContext}from"../../core/EventEmitterContext";import{AutoCoreTagContext}from"../../core/AutoCoreTagContext";import{MessageType}from"../../hub/CommandMessage";import{ValueInput}from"../ValueInput";import{TextInput}from"../TextInput";import{useTis}from"./TisProvider";import{useAmsAssets,useAmsRoles}from"../ams/AmsProvider";import{TestMethodDialog}from"./TestMethodDialog";const labelOf=e=>{const t=e.label&&e.label.length>0?e.label:e.name;return e.units?`${t} [${e.units}]`:t},hasDescription=e=>"string"==typeof e.description&&e.description.length>0,methodLabelOf=(e,t)=>t?.label&&t.label.length>0?t.label:e,AssetIdPicker=({assetType:e,value:t,onChange:s,invalid:i})=>{const a=useAmsAssets(),n=useAmsRoles(),r=useMemo(()=>a.filter(t=>t.asset_type===e&&"active"===t.status).map(e=>{const t=n[e.asset_type]?.find(t=>t.location===e.location)?.label,s=[e.asset_id];return t?s.push(`— ${t}`):e.location&&s.push(`— ${e.location}`),e.serial&&s.push(`(s/n ${e.serial})`),{label:s.join(" "),value:e.asset_id}}),[a,n,e]);return _jsx(Dropdown,{value:t,options:r,onChange:e=>s(e.value??""),placeholder:0===r.length?`No active ${e} assets registered — add one in Settings → Assets`:`Select ${e}…`,className:i?"p-invalid":"",filter:!0,showClear:!0,disabled:0===r.length})};export const TestSetupForm=({schema:e,defaultMethodId:t,onMethodChange:s,onValidationChange:i})=>{const a=useTis(),{invoke:n,write:r}=useContext(EventEmitterContext),{rawValues:o,findTagByFqdn:l}=useContext(AutoCoreTagContext),c=useMemo(()=>Object.keys(a.schemas),[a.schemas]),d=a.selection.projectId,m=""!==d.trim()&&a.projectKnown(d.trim()),[p,u]=useState(a.selection.methodId||t||a.defaultMethodId||""),[f,h]=useState(a.selection.sampleId||""),g=a.stagedConfig,x=e=>{const t="function"==typeof e?e(a.stagedConfig):e;t!==a.stagedConfig&&a.setStagedConfig(t)},_=e??(p?a.schemas[p]:void 0);useEffect(()=>{a.selection.methodId!==p&&p&&a.setSelection({methodId:p}),s&&s(p)},[p]),useEffect(()=>{a.selection.sampleId!==f&&a.setSelection({sampleId:f})},[f]),useEffect(()=>{a.state.stagedSampleId&&a.state.stagedSampleId!==f&&h(a.state.stagedSampleId)},[a.state.stagedSampleId]),useEffect(()=>{a.selection.methodId&&a.selection.methodId!==p&&u(a.selection.methodId)},[a.selection.methodId]);const[j,y]=useState(!1),[v,b]=useState(!1),[I,C]=useState({open:!1,title:"",body:null}),S=useRef("");useEffect(()=>{_&&p&&S.current!==p&&(S.current=p,x(e=>{let t=e;for(const s of _.config_fields)"sample_id"!==s.name&&void 0!==s.default&&null!==s.default&&(t===e&&(t={...e}),t[s.name]=s.default,s.source&&Promise.resolve().then(()=>r(s.source,s.default)).catch(e=>{}));return t}))},[_,p,r]),useEffect(()=>{_&&x(e=>{let t=e;for(const s of _.config_fields){if("sample_id"===s.name)continue;if(!s.source)continue;const i=l(s.source);if(!i)continue;const a=o[i.tagName];null!=a&&(t[s.name]!==a&&(t===e&&(t={...e}),t[s.name]=a))}return t})},[_,o,l]),useEffect(()=>{if(!_)return void y(!1);let e=!0;m||(e=!1),p.trim()||(e=!1),f.trim()||(e=!1),e&&!a.projectFieldsLoaded&&(e=!1);for(const t of _.config_fields)if("sample_id"!==t.name&&t.required){const s=g[t.name];if(void 0===s||""===s||null===s){e=!1;break}}if(y(e),i&&i(e,g),e){const{sample_id:e,...t}=g??{},s={...a.projectFields,...t};n("tis.stage_test",MessageType.Request,{project_id:d,method_id:p,sample_id:f,config:s}).catch(e=>{})}},[g,_,d,p,f,m,a.projectFields,a.projectFieldsLoaded,i,n]);const T=async(e,t)=>{if(x({...g,[e.name]:t}),e.source)try{await r(e.source,t)}catch(e){}};if(!_)return _jsx("div",{className:"ac-form-grid",style:{padding:"1.25rem"},children:_jsx("h3",{className:"ac-form-section",children:a.schemasLoaded?"No Test Method Selected":"Loading test methods…"})});if(!m)return _jsxs("div",{style:{padding:"1.25rem",maxWidth:"600px"},children:[_jsx("h3",{className:"ac-form-section",children:"No project selected"}),_jsxs("p",{style:{color:"var(--text-secondary-color)",marginTop:"0.5rem"},children:["Pick a project on the ",_jsx("strong",{children:"Project"})," tab first",""!==d.trim()&&` (or click + there to create "${d.trim()}")`,"."]})]});const N=j&&!a.state.lastStartError;return _jsxs("div",{className:"ac-form-grid",style:{padding:"1.25rem",gridTemplateColumns:"auto 1fr 1.75rem 1.75rem"},children:[_jsxs("h3",{className:"ac-form-section",style:{display:"flex",alignItems:"center",gap:"10px"},children:["Test Setup",_jsx(Button,{icon:N?"pi pi-check-circle":"pi pi-exclamation-circle",severity:N?"success":"danger",text:!0,rounded:!0,"aria-label":"Test Setup status",onClick:()=>{const e=(()=>{const e=[];if(m||e.push("No project is selected. Pick or create one on the Project tab."),a.projectFieldsLoaded||e.push("Project fields are still loading."),p.trim()||e.push("No test method selected."),f.trim()||e.push("Sample ID is required."),_)for(const t of _.config_fields){if("sample_id"===t.name)continue;if(!t.required)continue;const s=g[t.name];void 0!==s&&""!==s&&null!==s||e.push(`Required field "${labelOf(t)}" is empty.`)}return e})(),t=a.state.lastStartError?.trim()??"";let s;s=0!==e.length||t?_jsxs("div",{children:[e.length>0&&_jsxs(_Fragment,{children:[_jsx("p",{style:{margin:"0 0 0.5rem 0"},children:"The form is incomplete:"}),_jsx("ul",{style:{margin:"0 0 1rem 1.25rem"},children:e.map((e,t)=>_jsx("li",{children:e},t))})]}),t&&_jsxs(_Fragment,{children:[_jsx("p",{style:{margin:"0 0 0.25rem 0",fontWeight:600},children:"Last start_test error from the server:"}),_jsx("pre",{style:{margin:0,padding:"0.5rem",background:"rgba(0,0,0,0.25)",borderRadius:"4px",whiteSpace:"pre-wrap",fontSize:"0.875rem"},children:t})]})]}):_jsx("p",{style:{margin:0},children:"All required fields are complete. The test is staged and ready to start."}),C({open:!0,title:"Test Setup Status",body:s})}}),_jsxs("span",{style:{fontSize:"0.85em",color:"var(--text-secondary-color)",fontWeight:"normal",marginLeft:"0.25rem"},children:["project: ",_jsx("strong",{children:d})]})]}),_jsx("span",{className:"ac-form-label",children:"Sample ID"}),_jsx(TextInput,{label:void 0,value:f,onValueChanged:e=>{h(e)},className:f.trim()?"":"p-invalid"}),_jsx("span",{"aria-hidden":"true"}),_jsx("span",{style:{color:f.trim()?"var(--green-500)":"var(--red-500)",display:"flex",alignItems:"center"},children:_jsx("i",{className:f.trim()?"pi pi-check":"pi pi-times"})}),c.length>0&&_jsxs(_Fragment,{children:[_jsx("span",{className:"ac-form-label",children:"Test Method"}),_jsxs("div",{className:"p-inputgroup",style:{flex:1},children:[_jsx(InputText,{value:methodLabelOf(p,_),readOnly:!0,style:{flex:1},tabIndex:-1}),_jsx(Button,{icon:"pi pi-pencil",type:"button",onClick:()=>b(!0),tooltip:c.length>1?"Change test method":"View test method details",tooltipOptions:{position:"top"}})]}),_jsx("span",{"aria-hidden":"true"}),_jsx("span",{style:{color:p?"var(--green-500)":"var(--red-500)",display:"flex",alignItems:"center"},children:_jsx("i",{className:p?"pi pi-check":"pi pi-times"})})]}),_jsx("h3",{className:"ac-form-section",style:{marginTop:"1rem"},children:"Test Configuration"}),_.config_fields.map(e=>{if("sample_id"===e.name)return null;const t=(e=>{if(!e.required)return!0;const t=g[e.name];return void 0!==t&&""!==t&&null!==t})(e),s=(e=>{const t=_?.asset_refs??[],s=a.projectAssetRefs??[],i=`config.${e.name}`,n=t.find(e=>"by_id_field"===e.select&&e.from===i);if(n)return n.asset_type;const r=s.find(e=>"by_id_field"===e.select&&e.from===i);return r?r.asset_type:null})(e),i=!s&&"string"!==e.type&&"bool"!==e.type;return _jsxs(React.Fragment,{children:[_jsx("span",{className:"ac-form-label",children:labelOf(e)}),s?_jsx(AssetIdPicker,{assetType:s,value:null!=g[e.name]?String(g[e.name]):"",onChange:t=>T(e,t),invalid:!t}):i?_jsx(ValueInput,{label:void 0,value:null!=g[e.name]?Number(g[e.name]):null,onValueChanged:t=>T(e,t),className:t?"":"p-invalid"}):_jsx(TextInput,{label:void 0,value:null!=g[e.name]?String(g[e.name]):"",onValueChanged:t=>T(e,t),className:t?"":"p-invalid"}),hasDescription(e)?_jsx(Button,{icon:"pi pi-info-circle",text:!0,rounded:!0,"aria-label":`About ${labelOf(e)}`,onClick:()=>C({open:!0,title:labelOf(e),body:_jsx("p",{style:{margin:0,whiteSpace:"pre-wrap"},children:e.description})})}):_jsx("span",{"aria-hidden":"true"}),_jsx("span",{style:{color:t?"var(--green-500)":"var(--red-500)",display:"flex",alignItems:"center"},children:_jsx("i",{className:t?"pi pi-check":"pi pi-times"})})]},e.name)}),_jsx(TestMethodDialog,{visible:v,onHide:()=>b(!1),currentMethodId:p,onSelected:e=>u(e)}),_jsx(Dialog,{header:I.title,visible:I.open,onHide:()=>C({open:!1,title:"",body:null}),style:{width:"32rem",maxWidth:"90vw"},modal:!0,dismissableMask:!0,children:I.body})]})};
@@ -52,8 +52,32 @@ export interface TisRunCacheEntry {
52
52
  [blobName: string]: any;
53
53
  };
54
54
  }
55
+ /**
56
+ * One project-level asset_ref entry, in the wire shape returned by
57
+ * `tis.list_schemas`. Mirrors `Project.asset_refs` on the server.
58
+ * Carries only the fields the form's by_id_field lookup needs;
59
+ * other fields (label, description, calibration_required) are
60
+ * ignored but pass through untouched.
61
+ */
62
+ export interface TisProjectAssetRef {
63
+ field: string;
64
+ asset_type: string;
65
+ select: 'by_location' | 'by_id_field';
66
+ /** Set when `select=by_id_field` — the dotted config path
67
+ * (`config.<field_name>`) whose value picks the asset. */
68
+ from?: string;
69
+ /** Set when `select=by_location` — the role/location key. */
70
+ location?: string;
71
+ }
55
72
  export interface TisContextValue {
56
73
  schemas: SchemaRegistry;
74
+ /** Project-level asset_refs from `tis.list_schemas`. Empty array
75
+ * when the project declares none. The HMI form merges these with
76
+ * the active method's own `asset_refs` before deciding whether to
77
+ * render a config field as a dropdown (by_id_field) or a free-form
78
+ * input. Method-level refs win on `field`-name collision, mirroring
79
+ * the server resolver. */
80
+ projectAssetRefs: TisProjectAssetRef[];
57
81
  defaultMethodId: string;
58
82
  schemasLoaded: boolean;
59
83
  state: TisLiveState;
@@ -1 +1 @@
1
- {"version":3,"file":"TisProvider.d.ts","sourceRoot":"","sources":["../../../src/components/tis/TisProvider.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TisProvider.d.ts","sourceRoot":"","sources":["../../../src/components/tis/TisProvider.tsx"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- import{jsx as _jsx}from"react/jsx-runtime";import React,{createContext,useCallback,useContext,useEffect,useMemo,useReducer,useRef,useState}from"react";import{EventEmitterContext}from"../../core/EventEmitterContext";import{MessageType}from"../../hub/CommandMessage";const EMPTY_STATE={staged:!1,stagedProjectId:"",stagedMethodId:"",stagedSampleId:"",active:!1,activeProjectId:"",activeMethodId:"",activeSampleId:"",activeRunId:"",lastStartError:""},EMPTY_SELECTION={projectId:"",methodId:"",sampleId:"",runId:""},TisContext=createContext({schemas:{},defaultMethodId:"",schemasLoaded:!1,state:EMPTY_STATE,selection:EMPTY_SELECTION,setSelection:()=>{},existingProjects:[],projectKnown:()=>!1,refreshProjects:async()=>{},markProjectJustCreated:()=>{},projectFields:{},projectFieldsLoaded:!1,loadProjectFields:async()=>null,setProjectFields:()=>{},stagedConfig:{},setStagedConfig:()=>{},clearStagedConfig:()=>{},fetchRuns:async()=>[],fetchRun:async()=>null,runCache:{}});function liveReducer(e,t){switch(t.kind){case"staged":return{...e,staged:t.value};case"staged_project_id":return{...e,stagedProjectId:t.value};case"staged_method_id":return{...e,stagedMethodId:t.value};case"staged_sample_id":return{...e,stagedSampleId:t.value};case"active":return{...e,active:t.value};case"active_project_id":return{...e,activeProjectId:t.value};case"active_method_id":return{...e,activeMethodId:t.value};case"active_sample_id":return{...e,activeSampleId:t.value};case"active_run_id":return{...e,activeRunId:t.value};case"last_start_error":return{...e,lastStartError:t.value}}}export const TisProvider=({children:e,defaultMethodId:t})=>{const{invoke:s,subscribe:a,unsubscribe:c}=useContext(EventEmitterContext),[r,d]=useState({}),[n,u]=useState(t??""),[o,i]=useState(!1),[l,p]=useReducer(liveReducer,EMPTY_STATE),[_,m]=useState({projectId:null,methodId:null,sampleId:null,runId:null});useEffect(()=>{let e=!1;return(async()=>{try{const a=await s("tis.list_schemas",MessageType.Request,{});if(e)return;if(a?.success&&a.data){const e=a.data.test_methods??{},s=a.data.default_method_id??"";d(e),!t&&s&&u(s),i(!0)}}catch(e){}})(),()=>{e=!0}},[]),useEffect(()=>{let e=!1;return(async()=>{try{const t=await s("gnv.ux.selected_project_id",MessageType.Read,{});if(e)return;const a=t?.success?t.data??"":"";"string"==typeof a&&a.length>0&&m(e=>null===e.projectId?{...e,projectId:a}:e)}catch{}})(),()=>{e=!0}},[]),useEffect(()=>{const e=[a("tis.staged",e=>p({kind:"staged",value:!!e})),a("tis.staged_project_id",e=>p({kind:"staged_project_id",value:String(e??"")})),a("tis.staged_method_id",e=>p({kind:"staged_method_id",value:String(e??"")})),a("tis.staged_sample_id",e=>p({kind:"staged_sample_id",value:String(e??"")})),a("tis.active",e=>p({kind:"active",value:!!e})),a("tis.active_project_id",e=>p({kind:"active_project_id",value:String(e??"")})),a("tis.active_method_id",e=>p({kind:"active_method_id",value:String(e??"")})),a("tis.active_sample_id",e=>p({kind:"active_sample_id",value:String(e??"")})),a("tis.active_run_id",e=>p({kind:"active_run_id",value:String(e??"")})),a("tis.last_start_error",e=>p({kind:"last_start_error",value:String(e??"")}))];return()=>{e.forEach(c)}},[a,c]);const I=useRef({}),[f,v]=useState(0),j=useCallback(()=>v(e=>e+1),[]),h=useCallback((e,t)=>{if(!e)return;const s=I.current[e]??{meta:null,cycles:[],results:{},rawData:{}};I.current[e]={...s,cycles:[...s.cycles,t]},j()},[j]),g=useCallback((e,t)=>{if(!e)return;const s=I.current[e]??{meta:null,cycles:[],results:{},rawData:{}};I.current[e]={...s,results:t},j()},[j]);useEffect(()=>{const e=a("tis.cycle_added",e=>{e?.run_id&&e.cycle&&h(e.run_id,e.cycle)}),t=a("tis.results_updated",e=>{e?.run_id&&g(e.run_id,e.results??{})});return()=>{c(e),c(t)}},[a,c,h,g]);const C=useMemo(()=>({projectId:_.projectId??l.activeProjectId,methodId:_.methodId??(l.activeMethodId||n),sampleId:_.sampleId??l.activeSampleId,runId:_.runId??l.activeRunId}),[_,l,n]),S=useCallback(e=>{m(t=>({projectId:void 0===e.projectId?t.projectId:e.projectId,methodId:void 0===e.methodId?t.methodId:e.methodId,sampleId:void 0===e.sampleId?t.sampleId:e.sampleId,runId:void 0===e.runId?t.runId:e.runId})),void 0!==e.projectId&&s("gnv.ux.selected_project_id",MessageType.Write,e.projectId??"").catch(e=>{})},[s]),y=useRef("");useEffect(()=>{const e=l.activeRunId;e&&e!==y.current&&(y.current=e,m({projectId:null,methodId:null,sampleId:null,runId:null}))},[l.activeRunId]);const x=useCallback(async(e,t)=>{if(!e)return[];const a={project_id:e};t&&(a.method_id=t);try{const e=await s("tis.list_tests",MessageType.Request,a);if(e?.success&&e.data?.tests)return e.data.tests}catch(e){}return[]},[s]),T=useCallback(async(e,t,a)=>{if(!e||!t||!a)return null;try{const c=await s("tis.read_test",MessageType.Request,{project_id:e,method_id:t,run_id:a}),r=await s("tis.read_cycles",MessageType.Request,{project_id:e,method_id:t,run_id:a,offset:0,limit:1e3,order:"asc"});if(!c?.success)return null;const d={meta:c.data??null,cycles:r?.success?r.data?.cycles??[]:[],results:c.data?.results??{},rawData:I.current[a]?.rawData??{}};return I.current[a]=d,j(),d}catch(e){return null}},[s,j]),E=useMemo(()=>({...I.current}),[f]),[k,R]=useState([]),M=useRef(new Set),[P,b]=useState(0),[w,F]=useState({}),q=useCallback(async()=>{try{const e=await s("tis.list_projects",MessageType.Request,{});e?.success&&e.data?.projects&&R(e.data.projects)}catch(e){}},[s]),D=useCallback(e=>{e&&(M.current.has(e)||(M.current.add(e),b(e=>e+1)))},[]),L=useCallback(e=>!!e&&(!!M.current.has(e)||k.includes(e)),[k,P]),Y=useCallback((e,t)=>{e&&F(s=>({...s,[e]:t}))},[]),A=useCallback(async e=>{if(!e)return null;try{const t=await s("tis.read_project",MessageType.Request,{project_id:e});if(t?.success){const s=t.data?.project_fields??{};return F(t=>({...t,[e]:s})),s}}catch(e){}return F(t=>({...t,[e]:{}})),{}},[s]);useEffect(()=>{q()},[q]),useEffect(()=>{const e=a("tis.project_created",()=>{q()}),t=a("tis.project_updated",e=>{const t="string"==typeof e?.project_id?e.project_id:"";t&&A(t)});return()=>{c(e),c(t)}},[a,c,q,A]),useEffect(()=>{const e=C.projectId;e&&L(e)&&void 0===w[e]&&A(e)},[C.projectId,L,w,A]);const J=w[C.projectId]??{},K=void 0!==w[C.projectId],[N,O]=useState({}),W=useCallback(e=>{O(t=>({...t,...e}))},[]),z=useCallback(()=>{O({})},[]),B=useMemo(()=>({schemas:r,defaultMethodId:n,schemasLoaded:o,state:l,selection:C,setSelection:S,existingProjects:k,projectKnown:L,refreshProjects:q,markProjectJustCreated:D,projectFields:J,projectFieldsLoaded:K,loadProjectFields:A,setProjectFields:Y,stagedConfig:N,setStagedConfig:W,clearStagedConfig:z,fetchRuns:x,fetchRun:T,runCache:E}),[r,n,o,l,C,S,k,L,q,D,J,K,A,Y,N,W,z,x,T,E]);return _jsx(TisContext.Provider,{value:B,children:e})};export const useTis=()=>useContext(TisContext);export const useTisSchemas=()=>useContext(TisContext).schemas;export const useTisState=()=>useContext(TisContext).state;export const useTisSelection=()=>{const{selection:e,setSelection:t}=useContext(TisContext);return[e,t]};export const useTisRuns=(e,t)=>{const{fetchRuns:s}=useContext(TisContext),[a,c]=useState([]),[r,d]=useState(!1),n=useCallback(async()=>{if(e){d(!0);try{c(await s(e,t))}finally{d(!1)}}else c([])},[e,t,s]);return useEffect(()=>{n()},[n]),{runs:a,loading:r,refresh:n}};export const useTisRun=e=>{const{selection:t,fetchRun:s,runCache:a}=useContext(TisContext),[c,r]=useState(!1),d=e??t.runId;useEffect(()=>{if(!d)return;if(a[d]?.meta)return;const e=t.projectId,c=t.methodId;e&&c&&(r(!0),s(e,c,d).finally(()=>r(!1)))},[d,t.projectId,t.methodId,s,a]);const n=d?a[d]:null;return{meta:n?.meta??null,cycles:n?.cycles??[],results:n?.results??{},rawData:n?.rawData??{},loading:c}};export{TisContext};
1
+ import{jsx as _jsx}from"react/jsx-runtime";import React,{createContext,useCallback,useContext,useEffect,useMemo,useReducer,useRef,useState}from"react";import{EventEmitterContext}from"../../core/EventEmitterContext";import{MessageType}from"../../hub/CommandMessage";const EMPTY_STATE={staged:!1,stagedProjectId:"",stagedMethodId:"",stagedSampleId:"",active:!1,activeProjectId:"",activeMethodId:"",activeSampleId:"",activeRunId:"",lastStartError:""},EMPTY_SELECTION={projectId:"",methodId:"",sampleId:"",runId:""},TisContext=createContext({schemas:{},projectAssetRefs:[],defaultMethodId:"",schemasLoaded:!1,state:EMPTY_STATE,selection:EMPTY_SELECTION,setSelection:()=>{},existingProjects:[],projectKnown:()=>!1,refreshProjects:async()=>{},markProjectJustCreated:()=>{},projectFields:{},projectFieldsLoaded:!1,loadProjectFields:async()=>null,setProjectFields:()=>{},stagedConfig:{},setStagedConfig:()=>{},clearStagedConfig:()=>{},fetchRuns:async()=>[],fetchRun:async()=>null,runCache:{}});function liveReducer(e,t){switch(t.kind){case"staged":return{...e,staged:t.value};case"staged_project_id":return{...e,stagedProjectId:t.value};case"staged_method_id":return{...e,stagedMethodId:t.value};case"staged_sample_id":return{...e,stagedSampleId:t.value};case"active":return{...e,active:t.value};case"active_project_id":return{...e,activeProjectId:t.value};case"active_method_id":return{...e,activeMethodId:t.value};case"active_sample_id":return{...e,activeSampleId:t.value};case"active_run_id":return{...e,activeRunId:t.value};case"last_start_error":return{...e,lastStartError:t.value}}}export const TisProvider=({children:e,defaultMethodId:t})=>{const{invoke:s,subscribe:a,unsubscribe:r}=useContext(EventEmitterContext),[c,d]=useState({}),[n,u]=useState([]),[o,i]=useState(t??""),[l,p]=useState(!1),[_,f]=useReducer(liveReducer,EMPTY_STATE),[m,I]=useState({projectId:null,methodId:null,sampleId:null,runId:null});useEffect(()=>{let e=!1;return(async()=>{try{const a=await s("tis.list_schemas",MessageType.Request,{});if(e)return;if(a?.success&&a.data){const e=a.data.test_methods??{},s=a.data.default_method_id??"",r=Array.isArray(a.data.asset_refs)?a.data.asset_refs:[];d(e),u(r),!t&&s&&i(s),p(!0)}}catch(e){}})(),()=>{e=!0}},[]),useEffect(()=>{let e=!1;return(async()=>{try{const t=await s("gnv.ux.selected_project_id",MessageType.Read,{});if(e)return;const a=t?.success?t.data??"":"";"string"==typeof a&&a.length>0&&I(e=>null===e.projectId?{...e,projectId:a}:e)}catch{}})(),()=>{e=!0}},[]),useEffect(()=>{const e=[a("tis.staged",e=>f({kind:"staged",value:!!e})),a("tis.staged_project_id",e=>f({kind:"staged_project_id",value:String(e??"")})),a("tis.staged_method_id",e=>f({kind:"staged_method_id",value:String(e??"")})),a("tis.staged_sample_id",e=>f({kind:"staged_sample_id",value:String(e??"")})),a("tis.active",e=>f({kind:"active",value:!!e})),a("tis.active_project_id",e=>f({kind:"active_project_id",value:String(e??"")})),a("tis.active_method_id",e=>f({kind:"active_method_id",value:String(e??"")})),a("tis.active_sample_id",e=>f({kind:"active_sample_id",value:String(e??"")})),a("tis.active_run_id",e=>f({kind:"active_run_id",value:String(e??"")})),a("tis.last_start_error",e=>f({kind:"last_start_error",value:String(e??"")}))];return()=>{e.forEach(r)}},[a,r]);const v=useRef({}),[j,h]=useState(0),g=useCallback(()=>h(e=>e+1),[]),C=useCallback((e,t)=>{if(!e)return;const s=v.current[e]??{meta:null,cycles:[],results:{},rawData:{}};v.current[e]={...s,cycles:[...s.cycles,t]},g()},[g]),y=useCallback((e,t)=>{if(!e)return;const s=v.current[e]??{meta:null,cycles:[],results:{},rawData:{}};v.current[e]={...s,results:t},g()},[g]);useEffect(()=>{const e=a("tis.cycle_added",e=>{e?.run_id&&e.cycle&&C(e.run_id,e.cycle)}),t=a("tis.results_updated",e=>{e?.run_id&&y(e.run_id,e.results??{})});return()=>{r(e),r(t)}},[a,r,C,y]);const S=useMemo(()=>({projectId:m.projectId??_.activeProjectId,methodId:m.methodId??(_.activeMethodId||o),sampleId:m.sampleId??_.activeSampleId,runId:m.runId??_.activeRunId}),[m,_,o]),x=useCallback(e=>{I(t=>({projectId:void 0===e.projectId?t.projectId:e.projectId,methodId:void 0===e.methodId?t.methodId:e.methodId,sampleId:void 0===e.sampleId?t.sampleId:e.sampleId,runId:void 0===e.runId?t.runId:e.runId})),void 0!==e.projectId&&s("gnv.ux.selected_project_id",MessageType.Write,e.projectId??"").catch(e=>{})},[s]),T=useRef("");useEffect(()=>{const e=_.activeRunId;e&&e!==T.current&&(T.current=e,I({projectId:null,methodId:null,sampleId:null,runId:null}))},[_.activeRunId]);const E=useCallback(async(e,t)=>{if(!e)return[];const a={project_id:e};t&&(a.method_id=t);try{const e=await s("tis.list_tests",MessageType.Request,a);if(e?.success&&e.data?.tests)return e.data.tests}catch(e){}return[]},[s]),R=useCallback(async(e,t,a)=>{if(!e||!t||!a)return null;try{const r=await s("tis.read_test",MessageType.Request,{project_id:e,method_id:t,run_id:a}),c=await s("tis.read_cycles",MessageType.Request,{project_id:e,method_id:t,run_id:a,offset:0,limit:1e3,order:"asc"});if(!r?.success)return null;const d={meta:r.data??null,cycles:c?.success?c.data?.cycles??[]:[],results:r.data?.results??{},rawData:v.current[a]?.rawData??{}};return v.current[a]=d,g(),d}catch(e){return null}},[s,g]),k=useMemo(()=>({...v.current}),[j]),[M,P]=useState([]),b=useRef(new Set),[w,F]=useState(0),[A,q]=useState({}),D=useCallback(async()=>{try{const e=await s("tis.list_projects",MessageType.Request,{});e?.success&&e.data?.projects&&P(e.data.projects)}catch(e){}},[s]),L=useCallback(e=>{e&&(b.current.has(e)||(b.current.add(e),F(e=>e+1)))},[]),Y=useCallback(e=>!!e&&(!!b.current.has(e)||M.includes(e)),[M,w]),J=useCallback((e,t)=>{e&&q(s=>({...s,[e]:t}))},[]),K=useCallback(async e=>{if(!e)return null;try{const t=await s("tis.read_project",MessageType.Request,{project_id:e});if(t?.success){const s=t.data?.project_fields??{};return q(t=>({...t,[e]:s})),s}}catch(e){}return q(t=>({...t,[e]:{}})),{}},[s]);useEffect(()=>{D()},[D]),useEffect(()=>{const e=a("tis.project_created",()=>{D()}),t=a("tis.project_updated",e=>{const t="string"==typeof e?.project_id?e.project_id:"";t&&K(t)});return()=>{r(e),r(t)}},[a,r,D,K]),useEffect(()=>{const e=S.projectId;e&&Y(e)&&void 0===A[e]&&K(e)},[S.projectId,Y,A,K]);const N=A[S.projectId]??{},O=void 0!==A[S.projectId],[W,z]=useState({}),B=useCallback(e=>{z(t=>({...t,...e}))},[]),G=useCallback(()=>{z({})},[]),H=useMemo(()=>({schemas:c,projectAssetRefs:n,defaultMethodId:o,schemasLoaded:l,state:_,selection:S,setSelection:x,existingProjects:M,projectKnown:Y,refreshProjects:D,markProjectJustCreated:L,projectFields:N,projectFieldsLoaded:O,loadProjectFields:K,setProjectFields:J,stagedConfig:W,setStagedConfig:B,clearStagedConfig:G,fetchRuns:E,fetchRun:R,runCache:k}),[c,n,o,l,_,S,x,M,Y,D,L,N,O,K,J,W,B,G,E,R,k]);return _jsx(TisContext.Provider,{value:H,children:e})};export const useTis=()=>useContext(TisContext);export const useTisSchemas=()=>useContext(TisContext).schemas;export const useTisState=()=>useContext(TisContext).state;export const useTisSelection=()=>{const{selection:e,setSelection:t}=useContext(TisContext);return[e,t]};export const useTisRuns=(e,t)=>{const{fetchRuns:s}=useContext(TisContext),[a,r]=useState([]),[c,d]=useState(!1),n=useCallback(async()=>{if(e){d(!0);try{r(await s(e,t))}finally{d(!1)}}else r([])},[e,t,s]);return useEffect(()=>{n()},[n]),{runs:a,loading:c,refresh:n}};export const useTisRun=e=>{const{selection:t,fetchRun:s,runCache:a}=useContext(TisContext),[r,c]=useState(!1),d=e??t.runId;useEffect(()=>{if(!d)return;if(a[d]?.meta)return;const e=t.projectId,r=t.methodId;e&&r&&(c(!0),s(e,r,d).finally(()=>c(!1)))},[d,t.projectId,t.methodId,s,a]);const n=d?a[d]:null;return{meta:n?.meta??null,cycles:n?.cycles??[],results:n?.results??{},rawData:n?.rawData??{},loading:r}};export{TisContext};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adcops/autocore-react",
3
- "version": "3.3.77",
3
+ "version": "3.3.82",
4
4
  "description": "A React component library for industrial user interfaces.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -134,7 +134,7 @@ export const Indicator: React.FC<IndicatorProps> = ({
134
134
  const displayValue = value !== undefined ? value : subscribedValue;
135
135
  const color = pickColor(displayValue, onColor, offColor, invalidColor);
136
136
 
137
- // Children mode: square, filled, inset look. Sized by the caller's
137
+ // Children mode: square, filled, sunken look. Sized by the caller's
138
138
  // className (e.g. `ac-toolbar-icon-btn`) so it lines up with sibling
139
139
  // IndicatorButtons in the same toolbar.
140
140
  if (children !== undefined && children !== null) {
@@ -147,10 +147,17 @@ export const Indicator: React.FC<IndicatorProps> = ({
147
147
  // Square corners distinguish a passive indicator from an
148
148
  // interactive button (PrimeReact buttons round to ~6px).
149
149
  borderRadius: 0,
150
- // Subtle inset shadow reinforces "this is a readout, not a
151
- // control." Light enough to stay readable against any of the
152
- // IndicatorColor palette.
153
- boxShadow: 'inset 0 1px 3px rgba(0, 0, 0, 0.45)',
150
+ // Classic Win95-style chiseled-in bevel: dark shadow on
151
+ // the top + left (the "wall" above the recess casts a
152
+ // shadow into it) plus a lighter highlight on the bottom +
153
+ // right (light bouncing back out). The previous single
154
+ // top-only shadow read as raised because the bottom edge
155
+ // had nothing to contrast it. The shadow opacities are
156
+ // chosen to remain legible against every IndicatorColor
157
+ // — green, red, orange, blue, gray, black.
158
+ boxShadow:
159
+ 'inset 2px 2px 3px rgba(0, 0, 0, 0.55), ' +
160
+ 'inset -1px -1px 2px rgba(255, 255, 255, 0.20)',
154
161
  boxSizing: 'border-box',
155
162
  ...style,
156
163
  };
@@ -180,7 +187,11 @@ export const Indicator: React.FC<IndicatorProps> = ({
180
187
  backgroundColor: color,
181
188
  width: '22px',
182
189
  borderRadius: 0,
183
- boxShadow: 'inset 0 1px 2px rgba(0, 0, 0, 0.4)',
190
+ // Same Win95-sunken treatment as the children-mode box, dialed
191
+ // down a touch since the swatch is only 22px wide.
192
+ boxShadow:
193
+ 'inset 1px 1px 2px rgba(0, 0, 0, 0.5), ' +
194
+ 'inset -1px -1px 1px rgba(255, 255, 255, 0.18)',
184
195
  };
185
196
 
186
197
  return (
@@ -7,7 +7,7 @@
7
7
  * 1. Schema registry (loaded once via `ams.list_schemas`).
8
8
  * 2. Live alert scalars (`ams.asset_count`, `ams.alert_*`).
9
9
  * 3. Asset registry cache, refreshed on `ams.asset_changed` /
10
- * `ams.calibration_added` broadcasts.
10
+ * `ams.calibration_added` / `ams.calibration_updated` broadcasts.
11
11
  * 4. Selection state (assetType, assetId) — pinned by user click.
12
12
  *
13
13
  * Drop once at the top of the HMI; the AMS components below it read
@@ -201,8 +201,9 @@ export const AmsProvider: React.FC<AmsProviderProps> = ({ children }) => {
201
201
 
202
202
  useEffect(() => {
203
203
  const subs = [
204
- subscribe('ams.asset_changed', () => { refreshAssets(); }),
205
- subscribe('ams.calibration_added', () => { refreshAssets(); }),
204
+ subscribe('ams.asset_changed', () => { refreshAssets(); }),
205
+ subscribe('ams.calibration_added', () => { refreshAssets(); }),
206
+ subscribe('ams.calibration_updated', () => { refreshAssets(); }),
206
207
  subscribe('ams.asset_count', (v: any) => setAlerts(a => ({ ...a, assetCount: Number(v) || 0 }))),
207
208
  subscribe('ams.alert_calibration_overdue', (v: any) => setAlerts(a => ({ ...a, calibrationOverdue: Number(v) || 0 }))),
208
209
  subscribe('ams.alert_lane_unavailable', (v: any) => setAlerts(a => ({ ...a, laneUnavailable: Number(v) || 0 }))),
@@ -24,6 +24,11 @@ export const AssetDetailView: React.FC = () => {
24
24
  const [cals, setCals] = useState<any[]>([]);
25
25
  const [usage, setUsage] = useState<any | null>(null);
26
26
  const [calDialogOpen, setCalDialogOpen] = useState(false);
27
+ /** When non-null, the dialog opens in edit mode pre-seeded from this
28
+ * Calibration record. Only the asset's current calibration is
29
+ * editable (server enforces); the Edit button only renders on that
30
+ * row, so this is always either null or the current cal. */
31
+ const [editingCal, setEditingCal] = useState<any | null>(null);
27
32
  const [deleting, setDeleting] = useState(false);
28
33
 
29
34
  /** Two-step asset retirement: flip status to retired via update_asset.
@@ -234,7 +239,7 @@ export const AssetDetailView: React.FC = () => {
234
239
  />
235
240
  )}
236
241
  <Button label="+ Calibration" icon="pi pi-plus"
237
- onClick={() => setCalDialogOpen(true)} />
242
+ onClick={() => { setEditingCal(null); setCalDialogOpen(true); }} />
238
243
  </div>
239
244
  </div>
240
245
  <ConfirmDialog />
@@ -253,13 +258,30 @@ export const AssetDetailView: React.FC = () => {
253
258
  <Column header="Values"
254
259
  body={(r) => <code style={{ fontSize: '0.75rem' }}>{JSON.stringify(r.values)}</code>}
255
260
  />
261
+ <Column header="" style={{ width: '5rem' }}
262
+ body={(r) => (
263
+ // Edit is only offered for the asset's current
264
+ // calibration — historical records are frozen
265
+ // (server enforces too). Customers asked for
266
+ // this so typos can be fixed without minting a
267
+ // new cal_id every time.
268
+ r.cal_id === asset.current_calibration_id ? (
269
+ <Button icon="pi pi-pencil" text rounded size="small"
270
+ tooltip="Edit this calibration (fixes a typo in place)."
271
+ tooltipOptions={{ position: 'left' }}
272
+ onClick={() => { setEditingCal(r); setCalDialogOpen(true); }}
273
+ />
274
+ ) : null
275
+ )}
276
+ />
256
277
  </DataTable>
257
278
 
258
279
  <CalibrationEntryDialog
259
280
  visible={calDialogOpen}
260
281
  assetId={asset.asset_id}
261
282
  assetType={asset.asset_type}
262
- onHide={() => setCalDialogOpen(false)}
283
+ editing={editingCal}
284
+ onHide={() => { setCalDialogOpen(false); setEditingCal(null); }}
263
285
  onAdded={() => { refresh(); }}
264
286
  />
265
287
  </div>
@@ -1,11 +1,17 @@
1
1
  /*
2
- * <CalibrationEntryDialog> — form for adding a calibration record to
3
- * an asset. Renders a dynamic field set built from the asset_type's
2
+ * <CalibrationEntryDialog> — form for adding *or editing* a calibration
3
+ * record. Renders a dynamic field set built from the asset_type's
4
4
  * `calibration_fields` schema, plus a few standard meta fields.
5
5
  *
6
- * Triggered by <AssetDetailView>'s "+ Calibration" button. Submits via
7
- * `ams.add_calibration`; on success the AmsProvider's
8
- * `ams.calibration_added` subscription refreshes the registry.
6
+ * Two modes:
7
+ * - Add: `editing` prop absent. Submits via `ams.add_calibration`,
8
+ * which mints a new cal_id and bumps the asset's current_calibration_id.
9
+ * - Edit: `editing` prop carries the existing Calibration record. Form
10
+ * fields are pre-seeded from it; submit hits `ams.update_calibration`
11
+ * which overwrites the file in place (cal_id and the rest of the
12
+ * history are preserved). The server enforces that only the asset's
13
+ * *current* calibration is editable, so the parent should only open
14
+ * the dialog in edit mode for the current row.
9
15
  */
10
16
 
11
17
  import React, { useContext, useEffect, useState } from 'react';
@@ -24,7 +30,22 @@ export interface CalibrationEntryDialogProps {
24
30
  assetId: string;
25
31
  assetType: string;
26
32
  onHide: () => void;
33
+ /** Fires after a successful add OR edit. The cal_id is the same as
34
+ * the editing record on edit, or a freshly minted id on add. */
27
35
  onAdded?: (calId: string) => void;
36
+ /** When set, the dialog opens in edit mode pre-seeded from this
37
+ * Calibration record. cal_id is preserved through the round-trip.
38
+ * Caller is responsible for only passing the asset's *current*
39
+ * calibration — the server rejects edits to historical records. */
40
+ editing?: {
41
+ cal_id: string;
42
+ performed_at?: string;
43
+ performed_by?: string;
44
+ expires_at?: string | null;
45
+ cert_ref?: string;
46
+ notes?: string;
47
+ values: any;
48
+ } | null;
28
49
  }
29
50
 
30
51
  interface FieldSpec {
@@ -50,8 +71,9 @@ interface SubLocationsSchema {
50
71
  }
51
72
 
52
73
  export const CalibrationEntryDialog: React.FC<CalibrationEntryDialogProps> = ({
53
- visible, assetId, assetType, onHide, onAdded,
74
+ visible, assetId, assetType, onHide, onAdded, editing,
54
75
  }) => {
76
+ const isEdit = !!editing;
55
77
  const schemas = useAmsSchemas();
56
78
  const { invoke } = useContext(EventEmitterContext);
57
79
 
@@ -81,17 +103,46 @@ export const CalibrationEntryDialog: React.FC<CalibrationEntryDialogProps> = ({
81
103
  const [submitting, setSubmitting] = useState(false);
82
104
  const [error, setError] = useState<string | null>(null);
83
105
 
106
+ // Reset / pre-seed when the dialog opens. In edit mode the form
107
+ // mirrors the existing record so the operator only has to change
108
+ // what's wrong; in add mode the form starts blank.
84
109
  useEffect(() => {
85
- if (visible) {
110
+ if (!visible) return;
111
+ setError(null);
112
+ if (editing) {
113
+ // The values payload shape mirrors what the server stores:
114
+ // per-axis types use `{ <key>: { <field>: ... } }`; flat
115
+ // types use `{ <field>: ... }`. Route into the right slot
116
+ // based on the schema, not the payload, so a corrupt or
117
+ // legacy shape doesn't crosstalk into the wrong UI mode.
118
+ if (isPerAxis) {
119
+ setValues({});
120
+ setPerAxisValues(
121
+ (editing.values && typeof editing.values === 'object')
122
+ ? editing.values as { [k: string]: { [f: string]: any } }
123
+ : {}
124
+ );
125
+ } else {
126
+ setValues(
127
+ (editing.values && typeof editing.values === 'object')
128
+ ? editing.values as { [k: string]: any }
129
+ : {}
130
+ );
131
+ setPerAxisValues({});
132
+ }
133
+ setPerformedBy(editing.performed_by ?? '');
134
+ setExpiresAt(editing.expires_at ? new Date(editing.expires_at) : null);
135
+ setCertRef(editing.cert_ref ?? '');
136
+ setNotes(editing.notes ?? '');
137
+ } else {
86
138
  setValues({});
87
139
  setPerAxisValues({});
88
140
  setPerformedBy('');
89
141
  setExpiresAt(null);
90
142
  setCertRef('');
91
143
  setNotes('');
92
- setError(null);
93
144
  }
94
- }, [visible]);
145
+ }, [visible, editing, isPerAxis]);
95
146
 
96
147
  const renderField = (f: FieldSpec) => {
97
148
  const labelText = `${f.label ?? f.name}${f.units ? ` [${f.units}]` : ''}${f.required ? ' *' : ''}`;
@@ -176,19 +227,28 @@ export const CalibrationEntryDialog: React.FC<CalibrationEntryDialogProps> = ({
176
227
  setSubmitting(true);
177
228
  setError(null);
178
229
  try {
179
- const resp: any = await invoke('ams.add_calibration' as any, MessageType.Request, {
230
+ // Edit and add share the same payload shape; the topic
231
+ // differentiates them. On edit we also pin the cal_id so
232
+ // the server overwrites the right record rather than
233
+ // minting a new one.
234
+ const topic = isEdit ? 'ams.update_calibration' : 'ams.add_calibration';
235
+ const payload: any = {
180
236
  asset_id: assetId,
181
237
  performed_by: performedBy,
182
238
  expires_at: expiresAt ? expiresAt.toISOString() : null,
183
239
  cert_ref: certRef,
184
240
  notes,
185
241
  values: valuesPayload,
186
- } as any);
242
+ };
243
+ if (isEdit && editing) {
244
+ payload.cal_id = editing.cal_id;
245
+ }
246
+ const resp: any = await invoke(topic as any, MessageType.Request, payload);
187
247
  if (resp?.success) {
188
248
  onAdded?.(resp.data.cal_id);
189
249
  onHide();
190
250
  } else {
191
- setError(resp?.error_message ?? 'add_calibration failed');
251
+ setError(resp?.error_message ?? `${topic} failed`);
192
252
  }
193
253
  } catch (e: any) {
194
254
  setError(String(e?.message ?? e));
@@ -199,7 +259,9 @@ export const CalibrationEntryDialog: React.FC<CalibrationEntryDialogProps> = ({
199
259
 
200
260
  return (
201
261
  <Dialog
202
- header={`Add Calibration — ${assetId}`}
262
+ header={isEdit
263
+ ? `Edit Calibration ${editing!.cal_id} — ${assetId}`
264
+ : `Add Calibration — ${assetId}`}
203
265
  visible={visible}
204
266
  onHide={onHide}
205
267
  style={{ width: '40rem' }}
@@ -13,13 +13,15 @@
13
13
  * Mounts under the operator-facing Project tab, alongside <ProjectSelector>.
14
14
  * Reads `selection.projectId` from <TisProvider> so it follows whatever
15
15
  * project the operator has picked.
16
+ *
17
+ * Requires that a <ConfirmDialog> instance be registered in web app somewhere.
16
18
  */
17
19
 
18
20
  import React, { useCallback, useContext, useEffect, useState } from 'react';
19
21
  import { Button } from 'primereact/button';
20
22
  import { DataTable } from 'primereact/datatable';
21
23
  import { Column } from 'primereact/column';
22
- import { ConfirmDialog, confirmDialog } from 'primereact/confirmdialog';
24
+ import { confirmDialog } from 'primereact/confirmdialog';
23
25
  import { ProgressBar } from 'primereact/progressbar';
24
26
  import { EventEmitterContext } from '../../core/EventEmitterContext';
25
27
  import { MessageType } from '../../hub/CommandMessage';
@@ -256,7 +258,6 @@ export const ProjectManager: React.FC<ProjectManagerProps> = (props) => {
256
258
 
257
259
  return (
258
260
  <div style={{ width: '100%', maxWidth: '100%', boxSizing: 'border-box' }}>
259
- <ConfirmDialog />
260
261
 
261
262
  <div style={{
262
263
  display: 'flex',
@@ -368,19 +368,35 @@ export const TestSetupForm: React.FC<TestSetupFormProps> = ({
368
368
  };
369
369
 
370
370
  /**
371
- * If the test method has an `asset_ref` whose `select=by_id_field`
372
- * pulls from this config field, return the asset_type the field
373
- * should pick from. The form renders that field as a dropdown of
374
- * AMS assets instead of a free-form text input.
371
+ * If any `asset_ref` declares `select=by_id_field` with
372
+ * `from: "config.<field_name>"` for this field, return the
373
+ * asset_type the field should pick from. The form renders that
374
+ * field as a dropdown of AMS assets instead of a free-form text
375
+ * input.
375
376
  *
376
- * The schema already encodes the relationship via `from:
377
- * "config.<field_name>"` no project.json change required.
377
+ * Refs are sourced from two places, matching what the server's
378
+ * resolver does at stage time:
379
+ * 1. Method-level (`schema.asset_refs`) — method-specific
380
+ * accessories.
381
+ * 2. Project-level (`tis.projectAssetRefs`) — system hardware
382
+ * that applies to every test method (e.g. the test surface
383
+ * picked per-test by id).
384
+ * Method-level wins on `field`-name collision, so a method can
385
+ * override the project default.
378
386
  */
379
387
  const assetTypeForField = (field: TestFieldDef): string | null => {
380
- const refs = (schema?.asset_refs ?? []) as TisAssetRef[];
388
+ const methodRefs = (schema?.asset_refs ?? []) as TisAssetRef[];
389
+ const projectRefs = (tis.projectAssetRefs ?? []) as TisAssetRef[];
381
390
  const expectedFrom = `config.${field.name}`;
382
- const hit = refs.find(r => r.select === 'by_id_field' && r.from === expectedFrom);
383
- return hit ? hit.asset_type : null;
391
+ // Method wins on collision iterate method refs first.
392
+ const methodHit = methodRefs.find(
393
+ r => r.select === 'by_id_field' && r.from === expectedFrom,
394
+ );
395
+ if (methodHit) return methodHit.asset_type;
396
+ const projectHit = projectRefs.find(
397
+ r => r.select === 'by_id_field' && r.from === expectedFrom,
398
+ );
399
+ return projectHit ? projectHit.asset_type : null;
384
400
  };
385
401
 
386
402
  const renderConfigField = (field: TestFieldDef) => {
@@ -91,8 +91,33 @@ export interface TisRunCacheEntry {
91
91
  rawData: { [blobName: string]: any };
92
92
  }
93
93
 
94
+ /**
95
+ * One project-level asset_ref entry, in the wire shape returned by
96
+ * `tis.list_schemas`. Mirrors `Project.asset_refs` on the server.
97
+ * Carries only the fields the form's by_id_field lookup needs;
98
+ * other fields (label, description, calibration_required) are
99
+ * ignored but pass through untouched.
100
+ */
101
+ export interface TisProjectAssetRef {
102
+ field: string;
103
+ asset_type: string;
104
+ select: 'by_location' | 'by_id_field';
105
+ /** Set when `select=by_id_field` — the dotted config path
106
+ * (`config.<field_name>`) whose value picks the asset. */
107
+ from?: string;
108
+ /** Set when `select=by_location` — the role/location key. */
109
+ location?: string;
110
+ }
111
+
94
112
  export interface TisContextValue {
95
113
  schemas: SchemaRegistry;
114
+ /** Project-level asset_refs from `tis.list_schemas`. Empty array
115
+ * when the project declares none. The HMI form merges these with
116
+ * the active method's own `asset_refs` before deciding whether to
117
+ * render a config field as a dropdown (by_id_field) or a free-form
118
+ * input. Method-level refs win on `field`-name collision, mirroring
119
+ * the server resolver. */
120
+ projectAssetRefs: TisProjectAssetRef[];
96
121
  defaultMethodId: string;
97
122
  schemasLoaded: boolean;
98
123
 
@@ -182,6 +207,7 @@ const EMPTY_SELECTION: TisSelection = {
182
207
 
183
208
  const TisContext = createContext<TisContextValue>({
184
209
  schemas: {},
210
+ projectAssetRefs: [],
185
211
  defaultMethodId: '',
186
212
  schemasLoaded: false,
187
213
  state: EMPTY_STATE,
@@ -252,6 +278,7 @@ export const TisProvider: React.FC<TisProviderProps> = ({ children, defaultMetho
252
278
  const { invoke, subscribe, unsubscribe } = useContext(EventEmitterContext);
253
279
 
254
280
  const [schemas, setSchemas] = useState<SchemaRegistry>({});
281
+ const [projectAssetRefs, setProjectAssetRefs] = useState<TisProjectAssetRef[]>([]);
255
282
  const [defaultMethodId, setDefaultMethodId] = useState<string>(initialDefault ?? '');
256
283
  const [schemasLoaded, setSchemasLoaded] = useState(false);
257
284
 
@@ -284,7 +311,11 @@ export const TisProvider: React.FC<TisProviderProps> = ({ children, defaultMetho
284
311
  if (resp?.success && resp.data) {
285
312
  const methods = (resp.data.test_methods ?? {}) as SchemaRegistry;
286
313
  const dflt = (resp.data.default_method_id ?? '') as string;
314
+ const refs = Array.isArray(resp.data.asset_refs)
315
+ ? (resp.data.asset_refs as TisProjectAssetRef[])
316
+ : [];
287
317
  setSchemas(methods);
318
+ setProjectAssetRefs(refs);
288
319
  if (!initialDefault && dflt) setDefaultMethodId(dflt);
289
320
  setSchemasLoaded(true);
290
321
  } else {
@@ -620,14 +651,14 @@ export const TisProvider: React.FC<TisProviderProps> = ({ children, defaultMetho
620
651
  }, []);
621
652
 
622
653
  const value: TisContextValue = useMemo(() => ({
623
- schemas, defaultMethodId, schemasLoaded,
654
+ schemas, projectAssetRefs, defaultMethodId, schemasLoaded,
624
655
  state, selection, setSelection,
625
656
  existingProjects, projectKnown, refreshProjects, markProjectJustCreated,
626
657
  projectFields, projectFieldsLoaded, loadProjectFields, setProjectFields,
627
658
  stagedConfig, setStagedConfig, clearStagedConfig,
628
659
  fetchRuns, fetchRun, runCache,
629
660
  }), [
630
- schemas, defaultMethodId, schemasLoaded,
661
+ schemas, projectAssetRefs, defaultMethodId, schemasLoaded,
631
662
  state, selection, setSelection,
632
663
  existingProjects, projectKnown, refreshProjects, markProjectJustCreated,
633
664
  projectFields, projectFieldsLoaded, loadProjectFields, setProjectFields,