@adcops/autocore-react 3.3.112 → 3.3.115
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/ams/AmsProvider.d.ts.map +1 -1
- package/dist/components/ams/AmsProvider.js +1 -1
- package/dist/components/ams-editor/AssetFieldArray.d.ts +21 -0
- package/dist/components/ams-editor/AssetFieldArray.d.ts.map +1 -0
- package/dist/components/ams-editor/AssetFieldArray.js +1 -0
- package/dist/components/ams-editor/AssetTypeEditor.css +122 -0
- package/dist/components/ams-editor/AssetTypeEditor.d.ts +26 -0
- package/dist/components/ams-editor/AssetTypeEditor.d.ts.map +1 -0
- package/dist/components/ams-editor/AssetTypeEditor.js +1 -0
- package/dist/components/ams-editor/AssetTypeFormEditor.d.ts +21 -0
- package/dist/components/ams-editor/AssetTypeFormEditor.d.ts.map +1 -0
- package/dist/components/ams-editor/AssetTypeFormEditor.js +1 -0
- package/dist/components/ams-editor/SubLocationsEditor.d.ts +17 -0
- package/dist/components/ams-editor/SubLocationsEditor.d.ts.map +1 -0
- package/dist/components/ams-editor/SubLocationsEditor.js +1 -0
- package/dist/components/ams-editor/index.d.ts +7 -0
- package/dist/components/ams-editor/index.d.ts.map +1 -0
- package/dist/components/ams-editor/index.js +1 -0
- package/dist/components/ams-editor/types.d.ts +34 -0
- package/dist/components/ams-editor/types.d.ts.map +1 -0
- package/dist/components/ams-editor/types.js +1 -0
- package/dist/components/tis/ResultHistoryTable.d.ts.map +1 -1
- package/dist/components/tis/ResultHistoryTable.js +1 -1
- package/dist/components/tis/ScienceTable.d.ts +15 -0
- package/dist/components/tis/ScienceTable.d.ts.map +1 -1
- package/dist/components/tis/ScienceTable.js +1 -1
- package/dist/components/tis/TestDataView.d.ts +10 -4
- package/dist/components/tis/TestDataView.d.ts.map +1 -1
- package/dist/components/tis/TestDataView.js +1 -1
- package/dist/components/tis-editor/TisConfigEditor.d.ts +1 -1
- package/dist/components/tis-editor/editor/SaveDiffDialog.d.ts.map +1 -1
- package/dist/components/tis-editor/editor/SaveDiffDialog.js +1 -1
- package/dist/hooks/useAmsSchemaConfig.d.ts +39 -0
- package/dist/hooks/useAmsSchemaConfig.d.ts.map +1 -0
- package/dist/hooks/useAmsSchemaConfig.js +1 -0
- package/dist/hooks/useTisConfig.d.ts +1 -1
- package/package.json +110 -110
- package/src/components/ams/AmsProvider.tsx +20 -15
- package/src/components/ams-editor/AssetFieldArray.tsx +103 -0
- package/src/components/ams-editor/AssetTypeEditor.css +122 -0
- package/src/components/ams-editor/AssetTypeEditor.tsx +295 -0
- package/src/components/ams-editor/AssetTypeFormEditor.tsx +178 -0
- package/src/components/ams-editor/SubLocationsEditor.tsx +151 -0
- package/src/components/ams-editor/index.ts +16 -0
- package/src/components/ams-editor/types.ts +40 -0
- package/src/components/tis/ResultHistoryTable.tsx +141 -1
- package/src/components/tis/ScienceTable.tsx +71 -12
- package/src/components/tis/TestDataView.tsx +65 -6
- package/src/components/tis-editor/TisConfigEditor.tsx +1 -1
- package/src/components/tis-editor/editor/SaveDiffDialog.tsx +4 -3
- package/src/hooks/useAmsSchemaConfig.ts +142 -0
- package/src/hooks/useTisConfig.ts +1 -1
|
@@ -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;IAC1B;;;;;;;;uCAQmC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAClC;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,
|
|
1
|
+
{"version":3,"file":"AmsProvider.d.ts","sourceRoot":"","sources":["../../../src/components/ams/AmsProvider.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,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,
|
|
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,c]=useState({}),[r,o]=useState(!1),[l,u]=useState({}),[i,m]=useState(!1),[d,C]=useState(EMPTY_ALERTS),[x,b]=useState([]),[y,_]=useState({assetType:null,assetId:null}),A=useCallback(e=>{_(s=>({...s,...e}))},[]),h=useCallback(async()=>{try{const e=await s("ams.list_schemas",MessageType.Request,{});e?.success&&e.data&&(c(e.data.asset_types??{}),o(!0))}catch(e){}},[s]);useEffect(()=>{let e=!1;return h(),(async()=>{try{const t=await s("ams.list_roles",MessageType.Request,{});if(e)return;t?.success&&t.data?(u(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&&b(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.schema_changed",()=>{h()}),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,h]);const E=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]),S=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]),T=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]),g=useMemo(()=>({schemas:n,schemasLoaded:r,roles:l,rolesLoaded:i,alerts:d,assets:x,refreshAssets:p,readAsset:E,listCalibrations:f,readCalibration:S,readUsage:T,selection:y,setSelection:A}),[n,r,l,i,d,x,p,E,f,S,T,y,A]);return _jsx(AmsContext.Provider,{value:g,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]};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AssetFieldArray — add/remove/reorder editor for a plain `TestField[]`.
|
|
3
|
+
*
|
|
4
|
+
* A decoupled sibling of the TIS `FieldArrayEditor` (which is bound to a
|
|
5
|
+
* `TestMethod` keyed by `FieldArrayKey`). Asset types carry bare field
|
|
6
|
+
* lists (`fields`, `calibration_fields`, and the per-key lists inside a
|
|
7
|
+
* keyed `sub_locations`), so this operates directly on an array + onChange.
|
|
8
|
+
*
|
|
9
|
+
* Reuses the TIS `TestFieldDialog` for the per-field modal — asset fields
|
|
10
|
+
* have no cross-test aggregate concept, so `isResultsField` is left false.
|
|
11
|
+
*/
|
|
12
|
+
import type { TestField } from '../tis-editor/types';
|
|
13
|
+
export interface AssetFieldArrayProps {
|
|
14
|
+
title: string;
|
|
15
|
+
description?: string;
|
|
16
|
+
fields: TestField[];
|
|
17
|
+
onChange: (next: TestField[]) => void;
|
|
18
|
+
}
|
|
19
|
+
export declare const AssetFieldArray: React.FC<AssetFieldArrayProps>;
|
|
20
|
+
export default AssetFieldArray;
|
|
21
|
+
//# sourceMappingURL=AssetFieldArray.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AssetFieldArray.d.ts","sourceRoot":"","sources":["../../../src/components/ams-editor/AssetFieldArray.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAQH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAErD,MAAM,WAAW,oBAAoB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,QAAQ,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,IAAI,CAAC;CACzC;AAED,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAyE1D,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import{useState}from"react";import{DataTable}from"primereact/datatable";import{Column}from"primereact/column";import{Button}from"primereact/button";import{FormSection}from"../forms/FormSection";import{TestFieldDialog}from"../tis-editor/editor/TestFieldDialog";export const AssetFieldArray=({title:e,description:t,fields:i,onChange:o})=>{const[l,n]=useState(!1),[s,a]=useState(null),r=(e,t)=>{const l=e+t;if(l<0||l>=i.length)return;const n=[...i];[n[e],n[l]]=[n[l],n[e]],o(n)};return _jsxs(_Fragment,{children:[_jsx(FormSection,{title:e,description:t,actions:_jsx(Button,{label:"Add field",icon:"pi pi-plus",size:"small",onClick:()=>{a(null),n(!0)}}),children:_jsxs(DataTable,{value:i,dataKey:"name",emptyMessage:"No fields defined.",children:[_jsx(Column,{field:"name",header:"Name"}),_jsx(Column,{field:"type",header:"Type",style:{width:"6rem"}}),_jsx(Column,{field:"units",header:"Units",style:{width:"6rem"}}),_jsx(Column,{header:"Req",body:e=>e.required?"✓":"",style:{width:"4rem"}}),_jsx(Column,{field:"label",header:"Label"}),_jsx(Column,{header:"",body:(e,t)=>_jsxs("div",{style:{display:"flex",gap:"0.25rem"},children:[_jsx(Button,{icon:"pi pi-arrow-up",className:"p-button-text p-button-sm",disabled:0===t.rowIndex,onClick:()=>r(t.rowIndex,-1),"aria-label":"Move up"}),_jsx(Button,{icon:"pi pi-arrow-down",className:"p-button-text p-button-sm",disabled:t.rowIndex===i.length-1,onClick:()=>r(t.rowIndex,1),"aria-label":"Move down"}),_jsx(Button,{icon:"pi pi-pencil",className:"p-button-text p-button-sm",onClick:()=>{return e=t.rowIndex,a(e),void n(!0);var e},"aria-label":"Edit"}),_jsx(Button,{icon:"pi pi-trash",className:"p-button-text p-button-danger p-button-sm",onClick:()=>(e=>{const t=i[e];t&&window.confirm(`Remove field "${t.name}"?`)&&o(i.filter((t,i)=>i!==e))})(t.rowIndex),"aria-label":"Remove"})]}),style:{width:"9rem"}})]})}),_jsx(TestFieldDialog,{visible:l,initial:null!==s?i[s]??null:null,siblingNames:i.map(e=>e.name),isResultsField:!1,onCancel:()=>n(!1),onSave:e=>{const t=[...i];null===s?t.push(e):t[s]=e,o(t),n(!1)}})]})};export default AssetFieldArray;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
.ams-typeeditor {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
height: 100%;
|
|
5
|
+
min-height: 0;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.ams-typeeditor__header {
|
|
9
|
+
display: flex;
|
|
10
|
+
align-items: center;
|
|
11
|
+
justify-content: space-between;
|
|
12
|
+
padding: 0.75rem 1rem;
|
|
13
|
+
border-bottom: 1px solid var(--surface-d, #e2e8f0);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.ams-typeeditor__header h2 {
|
|
17
|
+
margin: 0;
|
|
18
|
+
font-size: 1.125rem;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.ams-typeeditor__header-actions {
|
|
22
|
+
display: flex;
|
|
23
|
+
gap: 0.5rem;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.ams-typeeditor__dirty-pill {
|
|
27
|
+
display: inline-block;
|
|
28
|
+
background: #ea580c;
|
|
29
|
+
color: white;
|
|
30
|
+
font-size: 0.7rem;
|
|
31
|
+
font-weight: 600;
|
|
32
|
+
text-transform: uppercase;
|
|
33
|
+
letter-spacing: 0.05em;
|
|
34
|
+
padding: 0.15rem 0.5rem;
|
|
35
|
+
border-radius: 999px;
|
|
36
|
+
margin-left: 0.5rem;
|
|
37
|
+
vertical-align: middle;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.ams-typeeditor__body {
|
|
41
|
+
flex: 1;
|
|
42
|
+
display: flex;
|
|
43
|
+
min-height: 0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.ams-typeeditor__sidebar {
|
|
47
|
+
flex: 0 0 320px;
|
|
48
|
+
border-right: 1px solid var(--surface-d, #e2e8f0);
|
|
49
|
+
display: flex;
|
|
50
|
+
flex-direction: column;
|
|
51
|
+
min-height: 0;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.ams-typeeditor__sidebar-actions {
|
|
55
|
+
display: flex;
|
|
56
|
+
gap: 0.25rem;
|
|
57
|
+
padding: 0.5rem;
|
|
58
|
+
border-bottom: 1px solid var(--surface-d, #e2e8f0);
|
|
59
|
+
flex-wrap: wrap;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.ams-typeeditor__sidebar-actions .p-button {
|
|
63
|
+
flex: 1 1 auto;
|
|
64
|
+
min-width: 0;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.ams-typeeditor__builtins {
|
|
68
|
+
padding: 0.5rem;
|
|
69
|
+
border-top: 1px solid var(--surface-d, #e2e8f0);
|
|
70
|
+
color: var(--text-color-secondary, #64748b);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.ams-typeeditor__detail {
|
|
74
|
+
flex: 1;
|
|
75
|
+
display: flex;
|
|
76
|
+
flex-direction: column;
|
|
77
|
+
min-height: 0;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.ams-typeeditor__error {
|
|
81
|
+
background: #fef2f2;
|
|
82
|
+
color: #991b1b;
|
|
83
|
+
border-left: 3px solid #dc2626;
|
|
84
|
+
padding: 0.5rem 1rem;
|
|
85
|
+
margin: 0.5rem 1rem;
|
|
86
|
+
font-size: 0.875rem;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.ams-typeeditor__error pre {
|
|
90
|
+
white-space: pre-wrap;
|
|
91
|
+
margin: 0.25rem 0 0 0;
|
|
92
|
+
font-family: ui-monospace, monospace;
|
|
93
|
+
font-size: 0.8rem;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.ams-typeeditor__empty {
|
|
97
|
+
flex: 1;
|
|
98
|
+
display: flex;
|
|
99
|
+
align-items: center;
|
|
100
|
+
justify-content: center;
|
|
101
|
+
color: var(--text-color-secondary, #64748b);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.ams-typeeditor__new-label {
|
|
105
|
+
display: flex;
|
|
106
|
+
flex-direction: column;
|
|
107
|
+
gap: 0.25rem;
|
|
108
|
+
margin-bottom: 0.25rem;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/* Portrait HMIs: stack the panes (see TisConfigEditor.css rationale). */
|
|
112
|
+
@media (orientation: portrait) {
|
|
113
|
+
.ams-typeeditor__body {
|
|
114
|
+
flex-direction: column;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.ams-typeeditor__sidebar {
|
|
118
|
+
flex: 0 1 35%;
|
|
119
|
+
border-right: none;
|
|
120
|
+
border-bottom: 1px solid var(--surface-d, #e2e8f0);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AssetTypeEditor — master-detail UI for authoring AMS custom asset TYPES
|
|
3
|
+
* from the operator HMI (the Instron-style "define your own asset type"
|
|
4
|
+
* capability). The instance-level UI (AssetRegistryTable / AssetEditDialog)
|
|
5
|
+
* edits asset records; this edits the type *schemas* those records conform
|
|
6
|
+
* to.
|
|
7
|
+
*
|
|
8
|
+
* Left: custom types (editable). Right: tabbed AssetTypeFormEditor.
|
|
9
|
+
* Action bar: New / Duplicate / Delete / Save / Revert.
|
|
10
|
+
*
|
|
11
|
+
* Staged-then-saved, mirroring the TIS test-method editor: New/Apply/Delete
|
|
12
|
+
* stage into the AMS module's in-memory buffer (dirty); Save persists to the
|
|
13
|
+
* `asset_management.json` sidecar (ams.save_schema_config) and broadcasts
|
|
14
|
+
* ams.schema_changed so open pickers/forms refresh. Built-in types
|
|
15
|
+
* (load_cell/linear_encoder/spring) are code-defined and shown read-only for
|
|
16
|
+
* reference — they can't be edited here.
|
|
17
|
+
*/
|
|
18
|
+
import type { TisIpcInvoker } from '../../hooks/useTisConfig';
|
|
19
|
+
import './AssetTypeEditor.css';
|
|
20
|
+
export interface AssetTypeEditorProps {
|
|
21
|
+
/** Optional invoker override — primarily for the playground / tests. */
|
|
22
|
+
invoker?: TisIpcInvoker;
|
|
23
|
+
}
|
|
24
|
+
export declare const AssetTypeEditor: React.FC<AssetTypeEditorProps>;
|
|
25
|
+
export default AssetTypeEditor;
|
|
26
|
+
//# sourceMappingURL=AssetTypeEditor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AssetTypeEditor.d.ts","sourceRoot":"","sources":["../../../src/components/ams-editor/AssetTypeEditor.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAaH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAI9D,OAAO,uBAAuB,CAAC;AAE/B,MAAM,WAAW,oBAAoB;IACjC,wEAAwE;IACxE,OAAO,CAAC,EAAE,aAAa,CAAC;CAC3B;AAcD,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAgP1D,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import{useEffect,useMemo,useState}from"react";import{useContext}from"react";import{DataTable}from"primereact/datatable";import{Column}from"primereact/column";import{Button}from"primereact/button";import{InputText}from"primereact/inputtext";import{Dialog}from"primereact/dialog";import{EventEmitterContext}from"../../core/EventEmitterContext";import{MessageType}from"../../hub/CommandMessage";import{useAmsSchemaConfig}from"../../hooks/useAmsSchemaConfig";import{useAmsAssetTypes}from"../../hooks/useAmsAssetTypes";import{AssetTypeFormEditor}from"./AssetTypeFormEditor";import"./AssetTypeEditor.css";const EMPTY_TYPE={label:"",description:"",fields:[],calibration_fields:[]};export const AssetTypeEditor=({invoker:e})=>{const s=useContext(EventEmitterContext),t=useMemo(()=>e??(async(e,t)=>await s.invoke(e,MessageType.Request,t)),[e,s]),i=useAmsSchemaConfig({invoker:t}),a=useAmsAssetTypes({invoker:t}),[n,o]=useState(null),[r,l]=useState(null),[c,d]=useState(!1),[m,p]=useState(!1),[y,u]=useState(""),f=useMemo(()=>Object.keys(i.config?.assetTypes??{}),[i.config]),_=useMemo(()=>a.types.filter(e=>!f.includes(e)),[a.types,f]),g=useMemo(()=>i.config?Object.entries(i.config.assetTypes).map(([e,s])=>({id:e,label:s?.label??""})):[],[i.config]);useEffect(()=>{!n&&i.config&&o(Object.keys(i.config.assetTypes)[0]??null)},[i.config,n]),useEffect(()=>{l(null)},[n]);return _jsxs("div",{className:"ams-typeeditor",children:[_jsxs("header",{className:"ams-typeeditor__header",children:[_jsxs("h2",{children:["Asset Types"," ",i.config?.dirty&&_jsx("span",{className:"ams-typeeditor__dirty-pill",children:"unsaved"})]}),_jsxs("div",{className:"ams-typeeditor__header-actions",children:[_jsx(Button,{label:"Save…",icon:"pi pi-save",disabled:c||!i.config?.dirty,onClick:async()=>{if(window.confirm("Save asset-type changes to disk?")){d(!0);try{await i.save()}catch(e){l(String(e?.message??e))}finally{d(!1)}}}}),_jsx(Button,{label:"Revert",icon:"pi pi-undo",className:"p-button-secondary",disabled:c||!i.config?.dirty,onClick:async()=>{if(window.confirm("Discard all in-progress edits? This cannot be undone.")){d(!0);try{await i.revert()}catch(e){l(String(e?.message??e))}finally{d(!1)}}}})]})]}),i.error&&_jsxs("div",{className:"ams-typeeditor__error",children:[_jsx("strong",{children:"Error:"})," ",_jsx("pre",{children:i.error})]}),_jsxs("div",{className:"ams-typeeditor__body",children:[_jsxs("aside",{className:"ams-typeeditor__sidebar",children:[_jsxs("div",{className:"ams-typeeditor__sidebar-actions",children:[_jsx(Button,{label:"New",icon:"pi pi-plus",disabled:c,onClick:()=>p(!0)}),_jsx(Button,{label:"Duplicate",icon:"pi pi-clone",className:"p-button-secondary",disabled:c||!n,onClick:async()=>{if(!n||!i.config)return;const e=i.config.assetTypes[n];if(!e)return;let s=`${n}_copy`,t=2;for(;i.config.assetTypes[s];)s=`${n}_copy_${t++}`;d(!0);try{await i.putType(s,JSON.parse(JSON.stringify(e))),o(s)}catch(e){l(String(e?.message??e))}finally{d(!1)}}}),_jsx(Button,{label:"Delete",icon:"pi pi-trash",className:"p-button-danger",disabled:c||!n,onClick:async()=>{if(n&&window.confirm(`Remove type "${n}"? This is staged — Save persists it.`)){d(!0);try{await i.removeType(n),o(null)}catch(e){l(String(e?.message??e))}finally{d(!1)}}}})]}),_jsxs(DataTable,{value:g,selection:g.find(e=>e.id===n)??null,onSelectionChange:e=>o(e.value?.id??null),selectionMode:"single",dataKey:"id",scrollable:!0,scrollHeight:"flex",emptyMessage:i.loading?"Loading…":"No custom asset types defined.",children:[_jsx(Column,{field:"id",header:"Type ID"}),_jsx(Column,{field:"label",header:"Label"})]}),_.length>0&&_jsx("div",{className:"ams-typeeditor__builtins",children:_jsxs("small",{children:["Built-in (read-only): ",_.join(", ")]})})]}),_jsx("section",{className:"ams-typeeditor__detail",children:n&&i.config?.assetTypes[n]?_jsxs(_Fragment,{children:[r&&_jsx("div",{className:"ams-typeeditor__error",children:_jsx("pre",{children:r})}),_jsx(AssetTypeFormEditor,{typeId:n,def:i.config.assetTypes[n],onApply:async e=>{if(n){d(!0);try{await i.putType(n,e),l(null)}catch(e){l(String(e?.message??e))}finally{d(!1)}}},busy:c,builtinTypes:_})]}):_jsx("div",{className:"ams-typeeditor__empty",children:"Select a custom asset type on the left, or create a new one."})})]}),_jsxs(Dialog,{header:"New Asset Type",visible:m,onHide:()=>p(!1),style:{width:"24rem"},children:[_jsxs("label",{className:"ams-typeeditor__new-label",children:["Type ID",_jsx(InputText,{value:y,onChange:e=>u(e.target.value),placeholder:"e.g. triaxial_transducer",autoFocus:!0})]}),_jsx("small",{children:"Canonical key — appears in wire payloads, on-disk paths, and generated code."}),_jsxs("div",{style:{display:"flex",gap:"0.5rem",justifyContent:"flex-end",marginTop:"1rem"},children:[_jsx(Button,{label:"Cancel",className:"p-button-text",onClick:()=>p(!1)}),_jsx(Button,{label:"Create",disabled:!y.trim()||c,onClick:async()=>{const e=y.trim();if(e)if(i.config?.assetTypes[e])l(`A custom type named "${e}" already exists.`);else if(!_.includes(e)||window.confirm(`"${e}" is a built-in type. Creating a custom type with this id overrides/extends the built-in. Continue?`)){d(!0);try{await i.putType(e,EMPTY_TYPE),o(e),p(!1),u("")}catch(e){l(String(e?.message??e))}finally{d(!1)}}}})]})]})]})};export default AssetTypeEditor;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AssetTypeFormEditor — tabbed shell for a single custom asset type,
|
|
3
|
+
* mirroring the TIS MethodFormEditor. Tabs: Identity, Fields, Calibration
|
|
4
|
+
* Fields, Sub-locations, and an always-available JSON escape hatch.
|
|
5
|
+
*
|
|
6
|
+
* Owns the local working copy; hands the changed copy back via onApply —
|
|
7
|
+
* the parent decides when to call ams.put_asset_type.
|
|
8
|
+
*/
|
|
9
|
+
import type { AssetTypeDef } from './types';
|
|
10
|
+
export interface AssetTypeFormEditorProps {
|
|
11
|
+
typeId: string;
|
|
12
|
+
def: AssetTypeDef;
|
|
13
|
+
/** Called on Apply with the working copy — parent forwards to put_asset_type. */
|
|
14
|
+
onApply: (next: AssetTypeDef) => Promise<void> | void;
|
|
15
|
+
/** Built-in type names, for the `extends` dropdown. */
|
|
16
|
+
builtinTypes?: string[];
|
|
17
|
+
busy?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export declare const AssetTypeFormEditor: React.FC<AssetTypeFormEditorProps>;
|
|
20
|
+
export default AssetTypeFormEditor;
|
|
21
|
+
//# sourceMappingURL=AssetTypeFormEditor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AssetTypeFormEditor.d.ts","sourceRoot":"","sources":["../../../src/components/ams-editor/AssetTypeFormEditor.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAaH,OAAO,KAAK,EAAE,YAAY,EAAa,MAAM,SAAS,CAAC;AAEvD,MAAM,WAAW,wBAAwB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,YAAY,CAAC;IAClB,iFAAiF;IACjF,OAAO,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACtD,uDAAuD;IACvD,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,IAAI,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CA+IlE,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import{useEffect,useMemo,useState}from"react";import{TabView,TabPanel}from"primereact/tabview";import{Button}from"primereact/button";import{InputText}from"primereact/inputtext";import{InputTextarea}from"primereact/inputtextarea";import{Dropdown}from"primereact/dropdown";import{CodeEditor}from"../CodeEditor";import{FormSection}from"../forms/FormSection";import{FormRow}from"../forms/FormRow";import{AssetFieldArray}from"./AssetFieldArray";import{SubLocationsEditor}from"./SubLocationsEditor";export const AssetTypeFormEditor=({typeId:e,def:t,onApply:i,builtinTypes:r=[],busy:s})=>{const[a,o]=useState(t),[n,l]=useState(""),[d,c]=useState(null),[p,m]=useState(0);useEffect(()=>{o(t),l(JSON.stringify(t,null,2)),c(null)},[t,e]);const u=useMemo(()=>{try{return JSON.stringify(a)!==JSON.stringify(t)}catch{return!0}},[a,t]),h=e=>{o(e),l(JSON.stringify(e,null,2))},f=[{label:"— none —",value:""},...r.map(e=>({label:`builtin: ${e}`,value:e}))];return _jsxs("div",{style:{display:"flex",flexDirection:"column",height:"100%",minHeight:0},children:[_jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",padding:"0.5rem 1rem",borderBottom:"1px solid var(--surface-d, #e2e8f0)",background:"var(--surface-b, #f8fafc)"},children:[_jsxs("strong",{children:[e,u&&_jsx("span",{style:{marginLeft:"0.5rem",color:"#ea580c"},children:"•"})]}),_jsx(Button,{label:"Apply",icon:"pi pi-check",disabled:s||!u||!!d,onClick:async()=>{d||await i(a)}})]}),_jsx("div",{style:{flex:1,minHeight:0,overflow:"auto"},children:_jsxs(TabView,{activeIndex:p,onTabChange:e=>m(e.index),children:[_jsx(TabPanel,{header:"Identity",children:_jsxs(FormSection,{title:"Identity",description:"How this type appears in the Add-Asset picker and how its asset IDs are prefixed.",children:[_jsx(FormRow,{label:"Label",hint:"Pretty name in the asset picker. Falls back to the type id.",children:_jsx(InputText,{value:a.label??"",onChange:e=>h({...a,label:e.target.value||void 0})})}),_jsx(FormRow,{label:"Description",children:_jsx(InputTextarea,{rows:2,value:a.description??"",onChange:e=>h({...a,description:e.target.value||void 0})})}),_jsx(FormRow,{label:"ID prefix",hint:"Asset IDs are minted as <prefix>001, 002, … Defaults to A- when blank.",children:_jsx(InputText,{value:a.id_prefix??"",placeholder:"e.g. TSDR-",onChange:e=>h({...a,id_prefix:e.target.value||void 0})})}),_jsx(FormRow,{label:"Extends",hint:"Optionally build on a built-in type's schema (merges its fields under yours).",children:_jsx(Dropdown,{value:a.extends??"",options:f,onChange:e=>h({...a,extends:e.value||void 0}),editable:!0})})]})}),_jsx(TabPanel,{header:"Fields",children:_jsx(AssetFieldArray,{title:"Nameplate Fields",description:"Per-asset fields captured when the asset is registered (e.g. capacity, material).",fields:a.fields??[],onChange:e=>h({...a,fields:e})})}),_jsx(TabPanel,{header:"Calibration Fields",children:_jsx(AssetFieldArray,{title:"Calibration Fields",description:"The calibration-record schema (e.g. scale, offset). Leave empty for types that don't calibrate.",fields:a.calibration_fields??[],onChange:e=>h({...a,calibration_fields:e})})}),_jsx(TabPanel,{header:"Sub-locations",children:_jsx(SubLocationsEditor,{def:a,onChange:h})}),_jsxs(TabPanel,{header:"JSON",children:[d&&_jsx("div",{style:{color:"#dc2626",marginBottom:"0.5rem",fontFamily:"monospace"},children:d}),_jsx("div",{style:{height:"60vh"},children:_jsx(CodeEditor,{code:n,language:"json",theme:"vs-dark",readOnly:!1,cursorStyle:"line",onCodeChanged:e=>{const t=e??"";l(t);try{o(JSON.parse(t)),c(null)}catch(e){c(String(e?.message??e))}}})})]})]})})]})};export default AssetTypeFormEditor;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SubLocationsEditor — edits the keyed-fields (multi-axis) `sub_locations`
|
|
3
|
+
* shape of an asset type: a fixed set of keys (e.g. x/y/z axes) plus
|
|
4
|
+
* per-key nameplate and calibration fields.
|
|
5
|
+
*
|
|
6
|
+
* The positional (surface-lanes) shape — `count` + `per_location_state` —
|
|
7
|
+
* is not editable here; it's left to the form's JSON tab. Assets without
|
|
8
|
+
* any sub_locations can add a keyed schema with one click.
|
|
9
|
+
*/
|
|
10
|
+
import { type AssetTypeDef } from './types';
|
|
11
|
+
export interface SubLocationsEditorProps {
|
|
12
|
+
def: AssetTypeDef;
|
|
13
|
+
onChange: (next: AssetTypeDef) => void;
|
|
14
|
+
}
|
|
15
|
+
export declare const SubLocationsEditor: React.FC<SubLocationsEditorProps>;
|
|
16
|
+
export default SubLocationsEditor;
|
|
17
|
+
//# sourceMappingURL=SubLocationsEditor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SubLocationsEditor.d.ts","sourceRoot":"","sources":["../../../src/components/ams-editor/SubLocationsEditor.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,OAAO,EAAuB,KAAK,YAAY,EAA0C,MAAM,SAAS,CAAC;AAEzG,MAAM,WAAW,uBAAuB;IACpC,GAAG,EAAE,YAAY,CAAC;IAClB,QAAQ,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;CAC1C;AAID,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CA4HhE,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import{Button}from"primereact/button";import{InputText}from"primereact/inputtext";import{FormSection}from"../forms/FormSection";import{FormRow}from"../forms/FormRow";import{AssetFieldArray}from"./AssetFieldArray";import{isKeyedSubLocations}from"./types";const EMPTY_KEYED={keys:[],fields:[],calibration_fields:[]};export const SubLocationsEditor=({def:e,onChange:t})=>{const s=e.sub_locations;if(null==s)return _jsx(FormSection,{title:"Sub-locations",description:"Optional. For multi-axis assets (e.g. a triaxial transducer), declare a fixed set of keys with per-key fields and calibration.",children:_jsx(Button,{label:"Add multi-axis sub-locations",icon:"pi pi-plus",size:"small",onClick:()=>t({...e,sub_locations:{...EMPTY_KEYED}})})});if(!isKeyedSubLocations(s))return _jsx(FormSection,{title:"Sub-locations",children:_jsxs("p",{style:{color:"var(--text-color-secondary, #64748b)"},children:["This type uses the positional (surface-lanes) sub-locations shape, which isn't editable in the form. Use the ",_jsx("strong",{children:"JSON"})," tab to edit it."]})});const o=s,i=s=>t({...e,sub_locations:s}),a=(e,t)=>{const s=e+t;if(s<0||s>=o.keys.length)return;const a=[...o.keys];[a[e],a[s]]=[a[s],a[e]],i({...o,keys:a})};return _jsxs(_Fragment,{children:[_jsxs(FormSection,{title:"Sub-locations (multi-axis)",description:"A fixed, ordered set of keys. Each asset carries per-key values; calibration records carry a per-key sub-object.",actions:_jsx(Button,{label:"Remove sub-locations",icon:"pi pi-trash",className:"p-button-text p-button-danger",size:"small",onClick:()=>{if(window.confirm("Remove the sub-locations schema from this type?")){const s={...e};delete s.sub_locations,t(s)}}}),children:[_jsx(FormRow,{label:"Group label",hint:"Pretty label for the set (e.g. Axes).",children:_jsx(InputText,{value:o.label??"",onChange:e=>i({...o,label:e.target.value||void 0})})}),_jsx(FormRow,{label:"Key label",hint:"Pretty label for one key (e.g. Axis).",children:_jsx(InputText,{value:o.key_label??"",onChange:e=>i({...o,key_label:e.target.value||void 0})})}),_jsx(FormRow,{label:"Keys",hint:"Ordered. Each becomes a per-key column on assets & calibrations.",children:_jsxs("div",{style:{display:"flex",flexDirection:"column",gap:"0.35rem"},children:[o.keys.map((e,t)=>_jsxs("div",{style:{display:"flex",gap:"0.25rem",alignItems:"center"},children:[_jsx(InputText,{value:e,placeholder:"e.g. x",onChange:e=>((e,t)=>{const s=[...o.keys];s[e]=t,i({...o,keys:s})})(t,e.target.value),style:{flex:1}}),_jsx(Button,{icon:"pi pi-arrow-up",className:"p-button-text p-button-sm",disabled:0===t,onClick:()=>a(t,-1),"aria-label":"Move up"}),_jsx(Button,{icon:"pi pi-arrow-down",className:"p-button-text p-button-sm",disabled:t===o.keys.length-1,onClick:()=>a(t,1),"aria-label":"Move down"}),_jsx(Button,{icon:"pi pi-trash",className:"p-button-text p-button-danger p-button-sm",onClick:()=>{return e=t,i({...o,keys:o.keys.filter((t,s)=>s!==e)});var e},"aria-label":"Remove key"})]},t)),_jsx("div",{children:_jsx(Button,{label:"Add key",icon:"pi pi-plus",size:"small",className:"p-button-secondary",onClick:()=>i({...o,keys:[...o.keys,""]})})})]})})]}),_jsx(AssetFieldArray,{title:"Per-key fields",description:"Nameplate fields recorded once per key on each asset.",fields:o.fields??[],onChange:e=>i({...o,fields:e})}),_jsx(AssetFieldArray,{title:"Per-key calibration fields",description:"Calibration values captured per key. When present, each calibration record must carry a per-key sub-object.",fields:o.calibration_fields??[],onChange:e=>i({...o,calibration_fields:e})})]})};export default SubLocationsEditor;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { AssetTypeEditor } from './AssetTypeEditor';
|
|
2
|
+
export type { AssetTypeEditorProps } from './AssetTypeEditor';
|
|
3
|
+
export { AssetTypeFormEditor } from './AssetTypeFormEditor';
|
|
4
|
+
export { AssetFieldArray } from './AssetFieldArray';
|
|
5
|
+
export { SubLocationsEditor } from './SubLocationsEditor';
|
|
6
|
+
export type { AssetTypeDef, KeyedSubLocations, TestField } from './types';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/ams-editor/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,YAAY,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{AssetTypeEditor}from"./AssetTypeEditor";export{AssetTypeFormEditor}from"./AssetTypeFormEditor";export{AssetFieldArray}from"./AssetFieldArray";export{SubLocationsEditor}from"./SubLocationsEditor";
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side mirror of the autocore-ams `AssetTypeConfig` (see
|
|
3
|
+
* autocore-ams/src/config.rs). Kept loose so unknown server-side
|
|
4
|
+
* extensions don't trip the editor at parse time. Reuses the shared
|
|
5
|
+
* `TestField` shape from the TIS editor — the server reuses the same
|
|
6
|
+
* Rust `TestField` for both test methods and asset/calibration fields.
|
|
7
|
+
*/
|
|
8
|
+
import type { TestField } from '../tis-editor/types';
|
|
9
|
+
export type { TestField };
|
|
10
|
+
/** One custom asset type. `sub_locations` is deliberately untyped: two
|
|
11
|
+
* shapes exist (keyed-fields multi-axis, discriminated by a `keys` array;
|
|
12
|
+
* and positional surface-lanes). The form edits the keyed shape; the
|
|
13
|
+
* positional shape is left to the JSON tab. */
|
|
14
|
+
export interface AssetTypeDef {
|
|
15
|
+
extends?: string;
|
|
16
|
+
id_prefix?: string;
|
|
17
|
+
label?: string;
|
|
18
|
+
description?: string;
|
|
19
|
+
fields?: TestField[];
|
|
20
|
+
calibration_fields?: TestField[];
|
|
21
|
+
sub_locations?: unknown;
|
|
22
|
+
}
|
|
23
|
+
/** The keyed-fields (multi-axis) `sub_locations` shape. */
|
|
24
|
+
export interface KeyedSubLocations {
|
|
25
|
+
label?: string;
|
|
26
|
+
key_label?: string;
|
|
27
|
+
keys: string[];
|
|
28
|
+
fields?: TestField[];
|
|
29
|
+
calibration_fields?: TestField[];
|
|
30
|
+
}
|
|
31
|
+
/** True when a `sub_locations` value is the keyed-fields (multi-axis)
|
|
32
|
+
* shape the form can edit — discriminated by a `keys` array. */
|
|
33
|
+
export declare function isKeyedSubLocations(v: unknown): v is KeyedSubLocations;
|
|
34
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/ams-editor/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAErD,YAAY,EAAE,SAAS,EAAE,CAAC;AAE1B;;;gDAGgD;AAChD,MAAM,WAAW,YAAY;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC;IACrB,kBAAkB,CAAC,EAAE,SAAS,EAAE,CAAC;IACjC,aAAa,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,2DAA2D;AAC3D,MAAM,WAAW,iBAAiB;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC;IACrB,kBAAkB,CAAC,EAAE,SAAS,EAAE,CAAC;CACpC;AAED;iEACiE;AACjE,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,iBAAiB,CAEtE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function isKeyedSubLocations(e){return!!e&&"object"==typeof e&&Array.isArray(e.keys)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ResultHistoryTable.d.ts","sourceRoot":"","sources":["../../../src/components/tis/ResultHistoryTable.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"ResultHistoryTable.d.ts","sourceRoot":"","sources":["../../../src/components/tis/ResultHistoryTable.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkD,MAAM,OAAO,CAAC;AAWvE,OAAO,0BAA0B,CAAC;AAElC,MAAM,WAAW,uBAAuB;IACpC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAyCD,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CAogBhE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React,{useState,useEffect,useContext}from"react";import{DataTable}from"primereact/datatable";import{Column}from"primereact/column";import{Button}from"primereact/button";import{Badge}from"primereact/badge";import{EventEmitterContext}from"../../core/EventEmitterContext";import{MessageType}from"../../hub/CommandMessage";import{useTis}from"./TisProvider";import{SampleSummaryPanel}from"./SampleSummaryPanel";import"./ResultHistoryTable.css";const downloadCsvBlob=(e,t)=>{const o=new Blob([t],{type:"text/csv;charset=utf-8;"}),
|
|
1
|
+
import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React,{useState,useEffect,useContext,useRef}from"react";import{DataTable}from"primereact/datatable";import{Column}from"primereact/column";import{Button}from"primereact/button";import{Badge}from"primereact/badge";import{Menu}from"primereact/menu";import{confirmDialog}from"primereact/confirmdialog";import{EventEmitterContext}from"../../core/EventEmitterContext";import{MessageType}from"../../hub/CommandMessage";import{useTis}from"./TisProvider";import{SampleSummaryPanel}from"./SampleSummaryPanel";import"./ResultHistoryTable.css";const downloadCsvBlob=(e,t)=>{const o=new Blob([t],{type:"text/csv;charset=utf-8;"}),i=URL.createObjectURL(o),s=document.createElement("a");s.href=i,s.download=e,document.body.appendChild(s),s.click(),s.remove(),URL.revokeObjectURL(i)},downloadViaUrl=(e,t)=>{const o=document.createElement("a");o.href=e,o.download=t,document.body.appendChild(o),o.click(),o.remove()};export const ResultHistoryTable=e=>{const t=useTis(),o=e.projectId??t.selection.projectId,i=e.methodId,[s,r]=useState([]),[a,n]=useState(!1),[l,d]=useState(null),[c,p]=useState(null),[u,m]=useState(null),f=useRef(null),[_,h]=useState(null),[y,b]=useState(null),{invoke:g}=useContext(EventEmitterContext),x=async()=>{if(o){n(!0);try{const e={project_id:o};i&&(e.method_id=i);const t=await g("tis.list_tests",MessageType.Request,e);t.success&&t.data&&t.data.tests&&r(t.data.tests)}catch(e){}n(!1)}else r([])};useEffect(()=>{x()},[o,i,t.state.activeRunId,t.state.active]);const v=async(e,t)=>{const s=e?.run_id,r=e?.method_id??i;if(!s||!r||!o)return;const a="report"===t?"tis.export_test_csv":"tis.export_test_data_csv",n="report"===t?"test report":"test data";d({runId:s,kind:t});try{const e=await g(a,MessageType.Request,{project_id:o,method_id:r,run_id:s});if(!e?.success)return void alert(`Failed to build ${n} for ${s}`+(e?.error_message?`: ${e.error_message}`:""));const i="string"==typeof e.data?.filename&&e.data.filename?e.data.filename:`${o}_${r}_${s}_${t}.csv`;if("report"===t){const t="string"==typeof e.data?.csv?e.data.csv:"";if(!t)return void alert(`${n} for ${s} is empty.`);downloadCsvBlob(i,t)}else{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 ${n}.`);downloadViaUrl(t,i)}}catch(e){alert(`Download failed: ${e instanceof Error?e.message:String(e)}`)}finally{d(null)}},w=async(e,t)=>{const s=e?.run_id,r=e?.method_id??i;if(!s||!r||!o)return;const a="complete"===t?"tis.finish_test":"abandon"===t?"tis.reset_test":"tis.resume_test";b(s);try{const e=await g(a,MessageType.Request,{project_id:o,method_id:r,run_id:s});if(!e?.success)return void alert(`Could not ${t} ${s}`+(e?.error_message?`:\n\n${e.error_message}`:""));await x()}catch(e){alert(`${t} failed: ${e instanceof Error?e.message:String(e)}`)}finally{b(null)}},j=async e=>{if(!o)return;const t="report"===e?"tis.export_project_csv":"tis.export_project_zip",i="report"===e?"project report":"project archive";p(e);try{const s=await g(t,MessageType.Request,{project_id:o});if(!s?.success)return void alert(`Failed to build ${i}`+(s?.error_message?`: ${s.error_message}`:""));const r="string"==typeof s.data?.download_url?s.data.download_url:"";if(!r)return void alert(`Server did not return a download URL for ${i}.`);const a="report"===e?`${o}_project_report.csv`:`${o}_project_archive.zip`,n="string"==typeof s.data?.filename&&s.data.filename?s.data.filename:a;downloadViaUrl(r,n)}catch(e){alert(`Download failed: ${e instanceof Error?e.message:String(e)}`)}finally{p(null)}},C=e=>{const t="string"==typeof e?.sample_id?e.sample_id:"";if(t)return t;const o=e?.config;return o&&"object"==typeof o&&"string"==typeof o.sample_id?o.sample_id:""};return _jsxs("div",{style:{width:"100%",maxWidth:"100%",overflow:"hidden",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:o?`Test History: ${o}${i?` / ${i}`:""}`:"Test History (no project selected)"}),_jsxs("div",{style:{display:"flex",gap:"0.4rem",alignItems:"center"},children:[_jsx(Button,{icon:"report"===c?"pi pi-spin pi-spinner":"pi pi-file",label:"Download Report",size:"small",outlined:!0,disabled:!o||null!==c,onClick:()=>j("report"),tooltip:"Download a CSV report of every test in this project",tooltipOptions:{position:"bottom"}}),_jsx(Button,{icon:"archive"===c?"pi pi-spin pi-spinner":"pi pi-box",label:"Download Archive",size:"small",outlined:!0,disabled:!o||null!==c,onClick:()=>j("archive"),tooltip:"Download a ZIP of the entire project directory (all tests, raw data, configs)",tooltipOptions:{position:"bottom"}}),_jsx(Button,{icon:"pi pi-refresh",label:"Refresh",size:"small",onClick:x,disabled:a})]})]}),_jsx(SampleSummaryPanel,{projectId:o,methodId:i}),_jsxs(DataTable,{value:s,loading:a,paginator:!0,rows:10,emptyMessage:"No tests found.",scrollable:!0,scrollHeight:"flex",tableStyle:{minWidth:0},style:{width:"100%"},rowClassName:e=>!0===e?.excluded?"tis-row-excluded":"",selectionMode:"single",onSelectionChange:e=>{const o=e.value;o?.run_id&&t.setSelection({projectId:o.project_id??null,methodId:o.method_id??null,runId:o.run_id})},children:[_jsx(Column,{header:"Sample ID",sortable:!0,body:C,sortFunction:e=>{const t=[...e.data];return t.sort((t,o)=>C(t).localeCompare(C(o))*(e.order??1)),t},style:{minWidth:"8rem"}}),_jsx(Column,{field:"start_time",header:"Date/Time",sortable:!0,body:e=>{return(t=e.start_time)?new Date(t).toLocaleString():"";var t},style:{minWidth:"12rem"}}),_jsx(Column,{field:"method_id",header:"Test Method",sortable:!0,style:{minWidth:"10rem"}}),_jsx(Column,{header:"Status",field:"status",sortable:!0,body:e=>{const t=(e=>{if(!0===e?.finalized)return{label:"Abandoned",severity:"danger"};const t="string"==typeof e?.status?e.status:"completed";switch(t){case"in_progress":return{label:"In Progress",severity:"info"};case"paused":return{label:"Paused",severity:"warning"};case"completed":return{label:"Completed",severity:"success"};default:return{label:t,severity:void 0}}})(e);return _jsx(Badge,{value:t.label,severity:t.severity})},style:{minWidth:"6rem"}}),_jsx(Column,{header:"Incl.",align:"center",alignHeader:"center",style:{width:"4.5rem"},body:e=>{const t=!0===e?.excluded,s=u===e.run_id;return _jsx(Button,{icon:s?"pi pi-spin pi-spinner":t?"pi pi-eye-slash":"pi pi-check",rounded:!0,text:!0,size:"small",severity:t?"warning":"success",disabled:null!==u,onClick:()=>(async e=>{const t=e?.run_id,s=e?.method_id??i;if(!t||!s||!o)return;const r=!0!==e?.excluded;m(t);try{const e=await g("tis.set_test_excluded",MessageType.Request,{project_id:o,method_id:s,run_id:t,excluded:r});if(!e?.success)return void alert(`Failed to ${r?"exclude":"include"} ${t}`+(e?.error_message?`: ${e.error_message}`:""));await x()}catch(e){alert(`Exclude toggle failed: ${e instanceof Error?e.message:String(e)}`)}finally{m(null)}})(e),"aria-label":t?"Excluded — click to include":"Included — click to exclude",tooltip:t?"Excluded from cross-test results — click to include":"Included in cross-test results — click to exclude",tooltipOptions:{position:"left"}})}}),_jsx(Column,{header:"Download",style:{width:"14rem"},body:e=>{const t=l?.runId===e.run_id&&"data"===l?.kind,o=l?.runId===e.run_id&&"report"===l?.kind,i=null!==l;return _jsxs("div",{style:{display:"flex",gap:"0.4rem"},children:[_jsx(Button,{icon:t?"pi pi-spin pi-spinner":"pi pi-download",label:"Raw",size:"small",outlined:!0,disabled:i,onClick:()=>v(e,"data"),tooltip:"Download raw + filtered trace data as one CSV",tooltipOptions:{position:"left"}}),_jsx(Button,{icon:o?"pi pi-spin pi-spinner":"pi pi-file",label:"Results",size:"small",outlined:!0,disabled:i,onClick:()=>v(e,"report"),tooltip:"Download a CSV report (metadata + cycles + results) for this test",tooltipOptions:{position:"left"}})]})}}),_jsx(Column,{header:"",style:{width:"3rem"},body:e=>_jsx(Button,{icon:y===e.run_id?"pi pi-spin pi-spinner":"pi pi-ellipsis-v",text:!0,rounded:!0,size:"small",disabled:null!==y,"aria-label":"Test actions",tooltip:"Complete / abandon / reopen this test",tooltipOptions:{position:"left"},onClick:t=>{h(e),f.current?.toggle(t)}})})]}),_jsx(Menu,{model:_?(e=>{const t=e?.status,o=!0===e?.finalized,i=[];return"in_progress"===t||"paused"===t?(i.push({label:"Complete Test",icon:"pi pi-check-circle",command:()=>w(e,"complete")}),i.push({label:"Abandon Test",icon:"pi pi-ban",command:()=>confirmDialog({header:"Abandon Test",message:`Mark ${e?.sample_id||e?.run_id} as abandoned? Recorded data is kept, but the test can no longer be reopened.`,icon:"pi pi-exclamation-triangle",acceptClassName:"p-button-danger",acceptLabel:"Abandon",accept:()=>w(e,"abandon")})})):"completed"!==t||o?i.push({label:o?"Abandoned — cannot reopen":"No actions available",icon:"pi pi-info-circle",disabled:!0}):i.push({label:"Reopen Test",icon:"pi pi-replay",command:()=>confirmDialog({header:"Reopen Test",message:`Reopen ${e?.sample_id||e?.run_id} so new cycles are added to it? Cycle numbering continues from where it stopped. This changes where data is recorded — it does not start the machine.`,icon:"pi pi-replay",acceptLabel:"Reopen",accept:()=>w(e,"reopen")})}),i})(_):[],popup:!0,ref:f})]})};
|
|
@@ -13,6 +13,14 @@ export interface ScienceColumn {
|
|
|
13
13
|
body?: (row: any) => React.ReactNode;
|
|
14
14
|
/** Optional per-column style (e.g. minWidth). */
|
|
15
15
|
style?: React.CSSProperties;
|
|
16
|
+
/**
|
|
17
|
+
* Operator-editable cell. Requires the table's `onCellEdit`. Intended for
|
|
18
|
+
* ANNOTATION columns only (a specimen or lot identifier noted against an
|
|
19
|
+
* automatically-captured row) — never for measured values, which the server
|
|
20
|
+
* refuses to rewrite anyway (`tis.update_cycle` only accepts cycle_fields
|
|
21
|
+
* declared `editable: true`).
|
|
22
|
+
*/
|
|
23
|
+
editable?: boolean;
|
|
16
24
|
}
|
|
17
25
|
export interface ScienceTableProps {
|
|
18
26
|
/** Title shown in the dark bar above the table. Omit for no bar. */
|
|
@@ -29,6 +37,13 @@ export interface ScienceTableProps {
|
|
|
29
37
|
scrollHeight?: string;
|
|
30
38
|
/** Virtual-scroll row height in px. Default 38. */
|
|
31
39
|
virtualItemSize?: number;
|
|
40
|
+
/**
|
|
41
|
+
* Commit handler for cells in columns marked `editable`. Called with the
|
|
42
|
+
* edited row, the column field and the new value. Without it, `editable`
|
|
43
|
+
* columns stay read-only — there is no local-only edit mode, because a value
|
|
44
|
+
* that looks saved but isn't is worse than one that can't be typed.
|
|
45
|
+
*/
|
|
46
|
+
onCellEdit?: (row: any, field: string, value: any) => void | Promise<void>;
|
|
32
47
|
}
|
|
33
48
|
export declare const ScienceTable: React.FC<ScienceTableProps>;
|
|
34
49
|
export default ScienceTable;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScienceTable.d.ts","sourceRoot":"","sources":["../../../src/components/tis/ScienceTable.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"ScienceTable.d.ts","sourceRoot":"","sources":["../../../src/components/tis/ScienceTable.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,MAAM,OAAO,CAAC;AAK1B,OAAO,oBAAoB,CAAC;AAE5B,MAAM,WAAW,aAAa;IAC1B,4BAA4B;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,KAAK,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IACpC,+DAA+D;IAC/D,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,KAAK,CAAC,SAAS,CAAC;IACrC,iDAAiD;IACjD,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAC9B,oEAAoE;IACpE,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,6EAA6E;IAC7E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gDAAgD;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yEAAyE;IACzE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mDAAmD;IACnD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9E;AASD,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CA8FpD,CAAC;AAEF,eAAe,YAAY,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React from"react";import{DataTable}from"primereact/datatable";import{Column}from"primereact/column";import"./ScienceTable.css";const HeaderCell=({column:e})=>_jsxs("div",{className:"ac-sci-th",children:[_jsx("span",{className:"ac-sci-th-name",children:e.label}),e.units?_jsxs("span",{className:"ac-sci-th-unit",children:["[",e.units,"]"]}):null]});export const ScienceTable=({title:e,columns:a,rows:l,showIndex:s=!0,indexHeader:
|
|
1
|
+
import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React from"react";import{DataTable}from"primereact/datatable";import{Column}from"primereact/column";import{InputText}from"primereact/inputtext";import"./ScienceTable.css";const HeaderCell=({column:e})=>_jsxs("div",{className:"ac-sci-th",children:[_jsx("span",{className:"ac-sci-th-name",children:e.label}),e.units?_jsxs("span",{className:"ac-sci-th-unit",children:["[",e.units,"]"]}):null]});export const ScienceTable=({title:e,columns:a,rows:l,showIndex:s=!0,indexHeader:t="#",emptyMessage:i="No data.",scrollable:c=!1,scrollHeight:r,virtualItemSize:n=38,onCellEdit:o})=>{const d=c&&!!r,m=!!o&&a.some(e=>e.editable);return _jsxs("div",{className:"ac-science-table-wrap",children:[null!=e&&_jsx("div",{className:"ac-science-table-title",children:e}),_jsx("div",{className:"ac-science-table-scroll",children:_jsxs(DataTable,{className:"ac-science-table",value:l,scrollable:c,scrollHeight:r,virtualScrollerOptions:d?{itemSize:n}:void 0,emptyMessage:i,editMode:m?"cell":void 0,children:[s?_jsx(Column,{header:t,headerClassName:"ac-sci-index",bodyClassName:"ac-sci-index",align:"center",alignHeader:"center",style:{width:"3.5rem",maxWidth:"3.5rem"},body:(e,a)=>a.rowIndex+1}):null,a.map(e=>{const a=!!o&&!!e.editable;return _jsx(Column,{field:e.field,header:_jsx(HeaderCell,{column:e}),align:e.align??"center",alignHeader:"center",style:e.style,bodyClassName:a?"ac-sci-cell ac-sci-cell-editable":"ac-sci-cell",body:e.body?a=>e.body(a):void 0,editor:a?e=>_jsx(InputText,{value:e.value??"",autoFocus:!0,style:{width:"100%"},onChange:a=>e.editorCallback?.(a.target.value),onKeyDown:e=>e.stopPropagation()}):void 0,onCellEditComplete:a?a=>{const l=a.rowData?.[e.field];let s=a.newValue;if("number"==typeof l&&""!==s&&null!=s){const e=Number(s);Number.isNaN(e)||(s=e)}s!==l&&o(a.rowData,e.field,s)}:void 0},e.field)})]})})]})};export default ScienceTable;
|
|
@@ -17,6 +17,12 @@ export interface TestFieldDef {
|
|
|
17
17
|
label: string;
|
|
18
18
|
value: any;
|
|
19
19
|
}>;
|
|
20
|
+
/** Operator-editable after recording — annotation columns only (a specimen
|
|
21
|
+
* or lot id noted against a captured row). Meaningful on `cycle_fields`;
|
|
22
|
+
* the server refuses `tis.update_cycle` for any field without it, so
|
|
23
|
+
* measured columns can never be typed over. Mirrors Rust
|
|
24
|
+
* `TestField::editable`. */
|
|
25
|
+
editable?: boolean;
|
|
20
26
|
}
|
|
21
27
|
export interface ChartAxis {
|
|
22
28
|
field?: string;
|
|
@@ -116,10 +122,10 @@ export interface TestConfiguration {
|
|
|
116
122
|
};
|
|
117
123
|
}
|
|
118
124
|
export interface TestMethod {
|
|
119
|
-
project_fields
|
|
120
|
-
config_fields
|
|
121
|
-
cycle_fields
|
|
122
|
-
results_fields
|
|
125
|
+
project_fields?: TestFieldDef[];
|
|
126
|
+
config_fields?: TestFieldDef[];
|
|
127
|
+
cycle_fields?: TestFieldDef[];
|
|
128
|
+
results_fields?: TestFieldDef[];
|
|
123
129
|
raw_data?: RawDataShape | null;
|
|
124
130
|
views?: {
|
|
125
131
|
[name: string]: ChartView;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TestDataView.d.ts","sourceRoot":"","sources":["../../../src/components/tis/TestDataView.tsx"],"names":[],"mappings":"AA0BA,OAAO,KAAwE,MAAM,OAAO,CAAC;AAiC7F,MAAM,WAAW,YAAY;IACzB,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;;;uEAGmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;sEAEkE;IAClE,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,GAAG,CAAA;KAAE,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"TestDataView.d.ts","sourceRoot":"","sources":["../../../src/components/tis/TestDataView.tsx"],"names":[],"mappings":"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"}
|