@adcops/autocore-react 3.3.113 → 3.3.116

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/dist/components/index.d.ts +10 -2
  2. package/dist/components/index.d.ts.map +1 -1
  3. package/dist/components/index.js +1 -1
  4. package/dist/components/tis/CycleConfigDialog.d.ts +39 -0
  5. package/dist/components/tis/CycleConfigDialog.d.ts.map +1 -0
  6. package/dist/components/tis/CycleConfigDialog.js +1 -0
  7. package/dist/components/tis/CycleConfigForm.d.ts +22 -0
  8. package/dist/components/tis/CycleConfigForm.d.ts.map +1 -0
  9. package/dist/components/tis/CycleConfigForm.js +1 -0
  10. package/dist/components/tis/CycleStatusStrip.d.ts +10 -0
  11. package/dist/components/tis/CycleStatusStrip.d.ts.map +1 -0
  12. package/dist/components/tis/CycleStatusStrip.js +1 -0
  13. package/dist/components/tis/ResultHistoryTable.d.ts.map +1 -1
  14. package/dist/components/tis/ResultHistoryTable.js +1 -1
  15. package/dist/components/tis/ScienceTable.d.ts +15 -0
  16. package/dist/components/tis/ScienceTable.d.ts.map +1 -1
  17. package/dist/components/tis/ScienceTable.js +1 -1
  18. package/dist/components/tis/TestDataView.d.ts +14 -4
  19. package/dist/components/tis/TestDataView.d.ts.map +1 -1
  20. package/dist/components/tis/TestDataView.js +1 -1
  21. package/dist/components/tis/TestFieldRow.d.ts +151 -0
  22. package/dist/components/tis/TestFieldRow.d.ts.map +1 -0
  23. package/dist/components/tis/TestFieldRow.js +1 -0
  24. package/dist/components/tis/TestSetupForm.d.ts +15 -51
  25. package/dist/components/tis/TestSetupForm.d.ts.map +1 -1
  26. package/dist/components/tis/TestSetupForm.js +1 -1
  27. package/dist/components/tis/TestSetupView.d.ts.map +1 -1
  28. package/dist/components/tis/TestSetupView.js +1 -1
  29. package/dist/components/tis/TisProvider.d.ts +80 -0
  30. package/dist/components/tis/TisProvider.d.ts.map +1 -1
  31. package/dist/components/tis/TisProvider.js +1 -1
  32. package/dist/components/tis-editor/TisConfigEditor.d.ts.map +1 -1
  33. package/dist/components/tis-editor/TisConfigEditor.js +1 -1
  34. package/dist/components/tis-editor/editor/CycleConfigSection.d.ts +19 -0
  35. package/dist/components/tis-editor/editor/CycleConfigSection.d.ts.map +1 -0
  36. package/dist/components/tis-editor/editor/CycleConfigSection.js +1 -0
  37. package/dist/components/tis-editor/editor/FieldArrayEditor.d.ts.map +1 -1
  38. package/dist/components/tis-editor/editor/FieldArrayEditor.js +1 -1
  39. package/dist/components/tis-editor/editor/MethodFormEditor.d.ts.map +1 -1
  40. package/dist/components/tis-editor/editor/MethodFormEditor.js +1 -1
  41. package/dist/components/tis-editor/editor/TestFieldDialog.d.ts +3 -0
  42. package/dist/components/tis-editor/editor/TestFieldDialog.d.ts.map +1 -1
  43. package/dist/components/tis-editor/editor/TestFieldDialog.js +1 -1
  44. package/dist/components/tis-editor/editor/ViewsEditor.d.ts.map +1 -1
  45. package/dist/components/tis-editor/editor/ViewsEditor.js +1 -1
  46. package/dist/components/tis-editor/types.d.ts +28 -1
  47. package/dist/components/tis-editor/types.d.ts.map +1 -1
  48. package/dist/components/tis-editor/validation.d.ts.map +1 -1
  49. package/dist/components/tis-editor/validation.js +1 -1
  50. package/package.json +110 -110
  51. package/src/components/index.ts +14 -0
  52. package/src/components/tis/CycleConfigDialog.tsx +173 -0
  53. package/src/components/tis/CycleConfigForm.tsx +192 -0
  54. package/src/components/tis/CycleStatusStrip.tsx +84 -0
  55. package/src/components/tis/ResultHistoryTable.tsx +141 -1
  56. package/src/components/tis/ScienceTable.tsx +71 -12
  57. package/src/components/tis/TestDataView.tsx +82 -7
  58. package/src/components/tis/TestFieldRow.tsx +297 -0
  59. package/src/components/tis/TestSetupForm.tsx +52 -212
  60. package/src/components/tis/TestSetupView.tsx +60 -3
  61. package/src/components/tis/TisProvider.tsx +191 -0
  62. package/src/components/tis-editor/TisConfigEditor.tsx +1 -0
  63. package/src/components/tis-editor/editor/CycleConfigSection.tsx +93 -0
  64. package/src/components/tis-editor/editor/FieldArrayEditor.tsx +10 -0
  65. package/src/components/tis-editor/editor/MethodFormEditor.tsx +10 -4
  66. package/src/components/tis-editor/editor/TestFieldDialog.tsx +22 -2
  67. package/src/components/tis-editor/editor/ViewsEditor.tsx +3 -0
  68. package/src/components/tis-editor/types.ts +34 -1
  69. package/src/components/tis-editor/validation.ts +20 -2
@@ -1,11 +1,19 @@
1
- export { TisProvider, TisContext, useTis, useTisSchemas, useTisState, useTisSelection, useTisRuns, useTisRun, } from './tis/TisProvider';
2
- export type { TisProviderProps, TisContextValue, TisLiveState, TisSelection, TisSelectionPatch, TisRunCacheEntry, SchemaRegistry, TisMethodSchema, } from './tis/TisProvider';
1
+ export { TisProvider, TisContext, useTis, useTisSchemas, useTisState, useTisSelection, useTisRuns, useTisRun, useTisCycleConfig, } from './tis/TisProvider';
2
+ export type { TisProviderProps, TisContextValue, TisLiveState, TisSelection, TisSelectionPatch, TisRunCacheEntry, SchemaRegistry, TisMethodSchema, TisCycleConfigState, } from './tis/TisProvider';
3
3
  export { ProjectSelector } from './tis/ProjectSelector';
4
4
  export type { ProjectSelectorProps } from './tis/ProjectSelector';
5
5
  export { TestSetupForm } from './tis/TestSetupForm';
6
6
  export type { TestSetupFormProps } from './tis/TestSetupForm';
7
7
  export { TestSetupView } from './tis/TestSetupView';
8
8
  export type { TestSetupViewProps } from './tis/TestSetupView';
9
+ export { TestFieldRow } from './tis/TestFieldRow';
10
+ export type { TestFieldRowProps, CycleConfigScope } from './tis/TestFieldRow';
11
+ export { CycleConfigForm, cycleConfigSummary } from './tis/CycleConfigForm';
12
+ export type { CycleConfigFormProps } from './tis/CycleConfigForm';
13
+ export { CycleConfigDialog, useCycleConfigGate } from './tis/CycleConfigDialog';
14
+ export type { CycleConfigDialogProps, CycleConfigGate } from './tis/CycleConfigDialog';
15
+ export { CycleStatusStrip } from './tis/CycleStatusStrip';
16
+ export type { CycleStatusStripProps } from './tis/CycleStatusStrip';
9
17
  export { ProjectInfoDialog } from './tis/ProjectInfoDialog';
10
18
  export type { ProjectInfoDialogProps, ProjectInfoMode } from './tis/ProjectInfoDialog';
11
19
  export { TestMethodDialog } from './tis/TestMethodDialog';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAQA,OAAO,EACH,WAAW,EACX,UAAU,EACV,MAAM,EACN,aAAa,EACb,WAAW,EACX,eAAe,EACf,UAAU,EACV,SAAS,GACZ,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACR,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,eAAe,GAClB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,eAAe,EAAE,MAAU,uBAAuB,CAAC;AAC5D,YAAY,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAElE,OAAO,EAAE,aAAa,EAAE,MAAY,qBAAqB,CAAC;AAC1D,YAAY,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAE9D,OAAO,EAAE,aAAa,EAAE,MAAY,qBAAqB,CAAC;AAC1D,YAAY,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAE9D,OAAO,EAAE,iBAAiB,EAAE,MAAQ,yBAAyB,CAAC;AAC9D,YAAY,EAAE,sBAAsB,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAEvF,OAAO,EAAE,gBAAgB,EAAE,MAAS,wBAAwB,CAAC;AAC7D,YAAY,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAEpE,OAAO,EAAE,kBAAkB,EAAE,MAAO,0BAA0B,CAAC;AAC/D,YAAY,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAExE,OAAO,EAAE,kBAAkB,EAAE,MAAO,0BAA0B,CAAC;AAC/D,YAAY,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAExE,OAAO,EAAE,YAAY,EAAE,MAAa,oBAAoB,CAAC;AACzD,YAAY,EAAE,iBAAiB,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE7G,OAAO,EAAE,eAAe,EAAE,MAAU,uBAAuB,CAAC;AAC5D,YAAY,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAElE,OAAO,EAAE,cAAc,EAAE,MAAW,sBAAsB,CAAC;AAC3D,YAAY,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAMhE,OAAO,EACH,WAAW,EACX,MAAM,EACN,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,eAAe,GAClB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACR,gBAAgB,EAChB,eAAe,EACf,SAAS,EACT,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,aAAa,GAChB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,MAAS,0BAA0B,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAY,uBAAuB,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AACtE,YAAY,EAAE,2BAA2B,EAAE,MAAM,8BAA8B,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAE,MAAU,yBAAyB,CAAC;AAShE,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACxE,YAAY,EACR,oBAAoB,EACpB,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,MAAM,EACN,YAAY,GACf,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,YAAY,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,YAAY,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- export{TisProvider,TisContext,useTis,useTisSchemas,useTisState,useTisSelection,useTisRuns,useTisRun}from"./tis/TisProvider";export{ProjectSelector}from"./tis/ProjectSelector";export{TestSetupForm}from"./tis/TestSetupForm";export{TestSetupView}from"./tis/TestSetupView";export{ProjectInfoDialog}from"./tis/ProjectInfoDialog";export{TestMethodDialog}from"./tis/TestMethodDialog";export{ResultHistoryTable}from"./tis/ResultHistoryTable";export{SampleSummaryPanel}from"./tis/SampleSummaryPanel";export{TestDataView}from"./tis/TestDataView";export{TestRawDataView}from"./tis/TestRawDataView";export{ProjectManager}from"./tis/ProjectManager";export{AmsProvider,useAms,useAmsSchemas,useAmsAlerts,useAmsAssets,useAmsSelection}from"./ams/AmsProvider";export{AssetRegistryTable}from"./ams/AssetRegistryTable";export{AssetDetailView}from"./ams/AssetDetailView";export{CalibrationEntryDialog}from"./ams/CalibrationEntryDialog";export{SubLocationPicker}from"./ams/SubLocationPicker";export{NetworkProvider,useNetwork}from"./network/NetworkProvider";export{NetworkPanel}from"./network/NetworkPanel";export{StagedChangeBanner}from"./network/StagedChangeBanner";
1
+ export{TisProvider,TisContext,useTis,useTisSchemas,useTisState,useTisSelection,useTisRuns,useTisRun,useTisCycleConfig}from"./tis/TisProvider";export{ProjectSelector}from"./tis/ProjectSelector";export{TestSetupForm}from"./tis/TestSetupForm";export{TestSetupView}from"./tis/TestSetupView";export{TestFieldRow}from"./tis/TestFieldRow";export{CycleConfigForm,cycleConfigSummary}from"./tis/CycleConfigForm";export{CycleConfigDialog,useCycleConfigGate}from"./tis/CycleConfigDialog";export{CycleStatusStrip}from"./tis/CycleStatusStrip";export{ProjectInfoDialog}from"./tis/ProjectInfoDialog";export{TestMethodDialog}from"./tis/TestMethodDialog";export{ResultHistoryTable}from"./tis/ResultHistoryTable";export{SampleSummaryPanel}from"./tis/SampleSummaryPanel";export{TestDataView}from"./tis/TestDataView";export{TestRawDataView}from"./tis/TestRawDataView";export{ProjectManager}from"./tis/ProjectManager";export{AmsProvider,useAms,useAmsSchemas,useAmsAlerts,useAmsAssets,useAmsSelection}from"./ams/AmsProvider";export{AssetRegistryTable}from"./ams/AssetRegistryTable";export{AssetDetailView}from"./ams/AssetDetailView";export{CalibrationEntryDialog}from"./ams/CalibrationEntryDialog";export{SubLocationPicker}from"./ams/SubLocationPicker";export{NetworkProvider,useNetwork}from"./network/NetworkProvider";export{NetworkPanel}from"./network/NetworkPanel";export{StagedChangeBanner}from"./network/StagedChangeBanner";
@@ -0,0 +1,39 @@
1
+ import React from 'react';
2
+ /** Handle returned by [`useCycleConfigGate`]. */
3
+ export interface CycleConfigGate {
4
+ /** True while the dialog should be open. */
5
+ open: boolean;
6
+ setOpen: (open: boolean) => void;
7
+ /**
8
+ * Gate an action on the annotation being complete. When the entry is
9
+ * ready, `action` runs immediately. When it isn't, the dialog opens
10
+ * instead and `action` is held until the operator completes the fields
11
+ * and confirms — so a Start press is deferred, never dropped.
12
+ */
13
+ run: (action: () => void) => void;
14
+ /** Run the held action and close. Called by the dialog's confirm. */
15
+ confirm: () => void;
16
+ /** Drop the held action and close. */
17
+ cancel: () => void;
18
+ /** True when the gate is blocking (required fields empty). */
19
+ blocked: boolean;
20
+ }
21
+ /**
22
+ * Wire a Start affordance to the Cycle Configuration gate.
23
+ *
24
+ * Deliberately does NOT return a `disabled` flag for Start. A greyed-out
25
+ * Start in the corner of a touchscreen reads as "the machine is broken"
26
+ * and the operator's next move is a phone call; a press that opens a
27
+ * dialog naming the missing field teaches the workflow in one go.
28
+ */
29
+ export declare const useCycleConfigGate: () => CycleConfigGate;
30
+ export interface CycleConfigDialogProps {
31
+ /** Gate handle from [`useCycleConfigGate`]. Omit to let the dialog
32
+ * open itself on the server's `prompt_due` edge. */
33
+ controller?: CycleConfigGate;
34
+ /** Label on the confirm button. Default "Continue". Set it to
35
+ * "Start" when the dialog is gating a Start press. */
36
+ confirmLabel?: string;
37
+ }
38
+ export declare const CycleConfigDialog: React.FC<CycleConfigDialogProps>;
39
+ //# sourceMappingURL=CycleConfigDialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CycleConfigDialog.d.ts","sourceRoot":"","sources":["../../../src/components/tis/CycleConfigDialog.tsx"],"names":[],"mappings":"AA+BA,OAAO,KAAmD,MAAM,OAAO,CAAC;AAOxE,iDAAiD;AACjD,MAAM,WAAW,eAAe;IAC5B,4CAA4C;IAC5C,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACjC;;;;;OAKG;IACH,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;IAClC,qEAAqE;IACrE,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,sCAAsC;IACtC,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,8DAA8D;IAC9D,OAAO,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,QAAO,eA8BrC,CAAC;AAEF,MAAM,WAAW,sBAAsB;IACnC;yDACqD;IACrD,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B;2DACuD;IACvD,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC,sBAAsB,CAiE9D,CAAC"}
@@ -0,0 +1 @@
1
+ import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React,{useCallback,useEffect,useRef,useState}from"react";import{Button}from"primereact/button";import{Dialog}from"primereact/dialog";import{useTis}from"./TisProvider";import{CycleConfigForm}from"./CycleConfigForm";import{labelOf}from"./TestFieldRow";export const useCycleConfigGate=()=>{const e=useTis(),[t,o]=useState(!1),l=useRef(null),r=e.cycleConfigFields.length>0&&!e.cycleConfig.ready,n=useCallback(t=>{e.cycleConfigFields.length>0&&(!e.cycleConfig.ready||e.cycleConfig.promptDue)?(l.current=t,o(!0)):t()},[e.cycleConfigFields.length,e.cycleConfig.ready,e.cycleConfig.promptDue]),c=useCallback(()=>{const e=l.current;l.current=null,o(!1),e?.()},[]),i=useCallback(()=>{l.current=null,o(!1)},[]);return{open:t,setOpen:o,run:n,confirm:c,cancel:i,blocked:r}};export const CycleConfigDialog=({controller:e,confirmLabel:t="Continue"})=>{const o=useTis(),l=o.cycleConfig,r=o.cycleConfigFields,[n,c]=useState(!1),i=e?e.open:n,s=useRef(!1);useEffect(()=>{if(e)return;const t=l.promptBeforeCycle&&l.promptDue&&r.length>0;t&&!s.current&&c(!0),s.current=t},[e,l.promptBeforeCycle,l.promptDue,r.length]);const a=()=>e?e.cancel():c(!1),f=l.missing.map(e=>r.find(t=>t.name===e)).filter(e=>!!e).map(labelOf);return _jsx(Dialog,{header:"Cycle Configuration",visible:i,onHide:a,style:{width:"34rem",maxWidth:"95vw"},modal:!0,footer:_jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",gap:"1rem"},children:[_jsx("span",{style:{color:"var(--text-secondary-color)",textAlign:"left"},children:l.ready?"Recorded on the next cycle.":`Still required: ${f.join(", ")}`}),_jsxs("span",{children:[_jsx(Button,{label:"Cancel",text:!0,onClick:a}),_jsx(Button,{label:t,icon:"pi pi-check",disabled:!l.ready,onClick:()=>e?e.confirm():c(!1)})]})]}),children:_jsx(CycleConfigForm,{compact:!0})})};
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+ import { type TestFieldDef } from './TestFieldRow';
3
+ export interface CycleConfigFormProps {
4
+ /** Extra class names applied to the root element. */
5
+ className?: string;
6
+ /** Inline style merged onto the root element. */
7
+ style?: React.CSSProperties;
8
+ /** Hide the explanatory header (used inside the prompt dialog, where
9
+ * the dialog title already says what this is). */
10
+ compact?: boolean;
11
+ /** Called after each accepted edit — the dialog uses it to know the
12
+ * operator has engaged with the form. */
13
+ onValueCommitted?: (field: TestFieldDef, raw: any) => void;
14
+ }
15
+ /**
16
+ * One-line summary of what the next recorded row will be labelled with.
17
+ * Shared by the Cycle tab header and <CycleStatusStrip> so the two can't
18
+ * describe the same state differently.
19
+ */
20
+ export declare const cycleConfigSummary: (fields: TestFieldDef[], values: Record<string, any>) => string;
21
+ export declare const CycleConfigForm: React.FC<CycleConfigFormProps>;
22
+ //# sourceMappingURL=CycleConfigForm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CycleConfigForm.d.ts","sourceRoot":"","sources":["../../../src/components/tis/CycleConfigForm.tsx"],"names":[],"mappings":"AAsBA,OAAO,KAA+B,MAAM,OAAO,CAAC;AAKpD,OAAO,EAAyB,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG1E,MAAM,WAAW,oBAAoB;IACjC,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iDAAiD;IACjD,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B;uDACmD;IACnD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;8CAC0C;IAC1C,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,GAAG,KAAK,IAAI,CAAC;CAC9D;AAED;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAC3B,QAAQ,YAAY,EAAE,EACtB,QAAQ,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAC5B,MASF,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAiI1D,CAAC"}
@@ -0,0 +1 @@
1
+ import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React,{useContext,useState}from"react";import{Button}from"primereact/button";import{Dialog}from"primereact/dialog";import{Message}from"primereact/message";import{useTis}from"./TisProvider";import{TestFieldRow,labelOf}from"./TestFieldRow";import{EventEmitterContext}from"../../core/EventEmitterContext";export const cycleConfigSummary=(e,t)=>0===e.length?"":e.map(e=>{const r=t?.[e.name],i=null==r||""===r?"—":String(r);return`${e.label??e.name}: ${i}`}).join(" ");export const CycleConfigForm=({className:e,style:t,compact:r,onValueCommitted:i})=>{const l=useTis(),{write:s}=useContext(EventEmitterContext),a=l.cycleConfig,n=l.cycleConfigFields,[o,c]=useState(null),m=null!==a.latched;if(0===n.length)return _jsxs("div",{className:e,style:{padding:"1.25rem",...t},children:[_jsx("h3",{className:"ac-form-section",children:"No Cycle Configuration"}),_jsx("p",{style:{color:"var(--text-secondary-color)",marginTop:"0.5rem"},children:"This test method records no operator-entered columns. Cycle rows are written entirely from measured values."})]});return _jsxs("div",{className:e,style:t,children:[!r&&_jsxs("div",{style:{padding:"1.25rem 1.25rem 0"},children:[_jsxs("h3",{className:"ac-form-section",style:{display:"flex",alignItems:"center",gap:"10px"},children:["Cycle Configuration",_jsx("i",{className:a.ready?"pi pi-check-circle":"pi pi-exclamation-circle",style:{color:a.ready?"var(--green-500)":"var(--red-500)"},"aria-label":a.ready?"Cycle Configuration complete":"Cycle Configuration incomplete"})]}),_jsx("p",{style:{color:"var(--text-secondary-color)",margin:"0.25rem 0 0"},children:"cycle"===a.scope?"Recorded on the next cycle. Entered again for every cycle.":"Recorded on every cycle of this run."})]}),m&&_jsx("div",{style:{padding:"0.75rem 1.25rem 0"},children:_jsx(Message,{severity:"info",text:"A cycle is running with these values. Edits apply to the next cycle."})}),!a.ready&&!m&&_jsx("div",{style:{padding:"0.75rem 1.25rem 0"},children:_jsx(Message,{severity:"warn",text:"Required: "+a.missing.map(e=>n.find(t=>t.name===e)).map((e,t)=>e?labelOf(e):a.missing[t]).join(", ")+". The machine will not start until these are filled in."})}),_jsx("div",{className:"ac-form-grid",style:{padding:"1.25rem",gridTemplateColumns:"auto 1fr 1.75rem 1.75rem"},children:n.map(e=>_jsx(TestFieldRow,{field:e,value:m?a.latched?.[e.name]:a.values?.[e.name],disabled:m,onChange:t=>{(async(e,t)=>{if(await l.setCycleConfigValues({[e.name]:t??null}),e.source)try{await s(e.source,t)}catch(e){}i?.(e,t)})(e,t)},onInfo:e=>c(e)},e.name))}),!r&&_jsx("div",{style:{padding:"0 1.25rem 1.25rem"},children:_jsx(Button,{label:"Clear",icon:"pi pi-eraser",text:!0,disabled:m,onClick:()=>{l.clearCycleConfig()},tooltip:"Clear every entry, including fields that don't autoclear",tooltipOptions:{position:"top"}})}),_jsx(Dialog,{header:o?labelOf(o):"",visible:null!==o,onHide:()=>c(null),style:{width:"32rem",maxWidth:"90vw"},modal:!0,dismissableMask:!0,children:_jsx("p",{style:{margin:0,whiteSpace:"pre-wrap"},children:o?.description})})]})};
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ export interface CycleStatusStripProps {
3
+ className?: string;
4
+ style?: React.CSSProperties;
5
+ /** Render nothing when the method declares no annotation columns.
6
+ * Default true — an empty chip beside Start is just noise. */
7
+ hideWhenUnused?: boolean;
8
+ }
9
+ export declare const CycleStatusStrip: React.FC<CycleStatusStripProps>;
10
+ //# sourceMappingURL=CycleStatusStrip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CycleStatusStrip.d.ts","sourceRoot":"","sources":["../../../src/components/tis/CycleStatusStrip.tsx"],"names":[],"mappings":"AAwBA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAMxC,MAAM,WAAW,qBAAqB;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B;mEAC+D;IAC/D,cAAc,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CA6C5D,CAAC"}
@@ -0,0 +1 @@
1
+ import{jsx as _jsx,Fragment as _Fragment,jsxs as _jsxs}from"react/jsx-runtime";import React,{useState}from"react";import{Button}from"primereact/button";import{Dialog}from"primereact/dialog";import{useTis}from"./TisProvider";import{CycleConfigForm,cycleConfigSummary}from"./CycleConfigForm";export const CycleStatusStrip=({className:e,style:i,hideWhenUnused:t=!0})=>{const r=useTis(),[o,a]=useState(!1),s=r.cycleConfig,l=r.cycleConfigFields;if(0===l.length&&t)return null;const n=s.latched??s.values,m=cycleConfigSummary(l,n),c=!s.ready;return _jsxs(_Fragment,{children:[_jsx(Button,{className:e,style:i,text:!0,severity:c?"danger":void 0,icon:c?"pi pi-exclamation-triangle":"pi pi-tag",label:c?`${m} — entry required`:m,"aria-label":"Cycle Configuration",onClick:()=>a(!0)}),_jsx(Dialog,{header:"Cycle Configuration",visible:o,onHide:()=>a(!1),style:{width:"34rem",maxWidth:"95vw"},modal:!0,dismissableMask:!0,children:_jsx(CycleConfigForm,{})})]})};
@@ -1 +1 @@
1
- {"version":3,"file":"ResultHistoryTable.d.ts","sourceRoot":"","sources":["../../../src/components/tis/ResultHistoryTable.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA0C,MAAM,OAAO,CAAC;AAS/D,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,CA0XhE,CAAC"}
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;"}),r=URL.createObjectURL(o),s=document.createElement("a");s.href=r,s.download=e,document.body.appendChild(s),s.click(),s.remove(),URL.revokeObjectURL(r)},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,r=e.methodId,[s,i]=useState([]),[a,l]=useState(!1),[n,d]=useState(null),[c,p]=useState(null),[u,m]=useState(null),{invoke:f}=useContext(EventEmitterContext),_=async()=>{if(o){l(!0);try{const e={project_id:o};r&&(e.method_id=r);const t=await f("tis.list_tests",MessageType.Request,e);t.success&&t.data&&t.data.tests&&i(t.data.tests)}catch(e){}l(!1)}else i([])};useEffect(()=>{_()},[o,r,t.state.activeRunId,t.state.active]);const y=async(e,t)=>{const s=e?.run_id,i=e?.method_id??r;if(!s||!i||!o)return;const a="report"===t?"tis.export_test_csv":"tis.export_test_data_csv",l="report"===t?"test report":"test data";d({runId:s,kind:t});try{const e=await f(a,MessageType.Request,{project_id:o,method_id:i,run_id:s});if(!e?.success)return void alert(`Failed to build ${l} for ${s}`+(e?.error_message?`: ${e.error_message}`:""));const r="string"==typeof e.data?.filename&&e.data.filename?e.data.filename:`${o}_${i}_${s}_${t}.csv`;if("report"===t){const t="string"==typeof e.data?.csv?e.data.csv:"";if(!t)return void alert(`${l} for ${s} is empty.`);downloadCsvBlob(r,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 ${l}.`);downloadViaUrl(t,r)}}catch(e){alert(`Download failed: ${e instanceof Error?e.message:String(e)}`)}finally{d(null)}},h=async e=>{if(!o)return;const t="report"===e?"tis.export_project_csv":"tis.export_project_zip",r="report"===e?"project report":"project archive";p(e);try{const s=await f(t,MessageType.Request,{project_id:o});if(!s?.success)return void alert(`Failed to build ${r}`+(s?.error_message?`: ${s.error_message}`:""));const i="string"==typeof s.data?.download_url?s.data.download_url:"";if(!i)return void alert(`Server did not return a download URL for ${r}.`);const a="report"===e?`${o}_project_report.csv`:`${o}_project_archive.zip`,l="string"==typeof s.data?.filename&&s.data.filename?s.data.filename:a;downloadViaUrl(i,l)}catch(e){alert(`Download failed: ${e instanceof Error?e.message:String(e)}`)}finally{p(null)}},x=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}${r?` / ${r}`:""}`:"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:()=>h("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:()=>h("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:_,disabled:a})]})]}),_jsx(SampleSummaryPanel,{projectId:o,methodId:r}),_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:x,sortFunction:e=>{const t=[...e.data];return t.sort((t,o)=>x(t).localeCompare(x(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??r;if(!t||!s||!o)return;const i=!0!==e?.excluded;m(t);try{const e=await f("tis.set_test_excluded",MessageType.Request,{project_id:o,method_id:s,run_id:t,excluded:i});if(!e?.success)return void alert(`Failed to ${i?"exclude":"include"} ${t}`+(e?.error_message?`: ${e.error_message}`:""));await _()}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=n?.runId===e.run_id&&"data"===n?.kind,o=n?.runId===e.run_id&&"report"===n?.kind,r=null!==n;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:r,onClick:()=>y(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:r,onClick:()=>y(e,"report"),tooltip:"Download a CSV report (metadata + cycles + results) for this test",tooltipOptions:{position:"left"}})]})}})]})]})};
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;AAI1B,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;CAC/B;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;CAC5B;AASD,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAmDpD,CAAC;AAEF,eAAe,YAAY,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:c="#",emptyMessage:i="No data.",scrollable:t=!1,scrollHeight:r,virtualItemSize:n=38})=>{const d=t&&!!r;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:t,scrollHeight:r,virtualScrollerOptions:d?{itemSize:n}:void 0,emptyMessage:i,children:[s?_jsx(Column,{header:c,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=>_jsx(Column,{field:e.field,header:_jsx(HeaderCell,{column:e}),align:e.align??"center",alignHeader:"center",style:e.style,bodyClassName:"ac-sci-cell",body:e.body?a=>e.body(a):void 0},e.field))]})})]})};export default ScienceTable;
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,14 @@ export interface TestConfiguration {
116
122
  };
117
123
  }
118
124
  export interface TestMethod {
119
- project_fields: TestFieldDef[];
120
- config_fields: TestFieldDef[];
121
- cycle_fields: TestFieldDef[];
122
- results_fields: TestFieldDef[];
125
+ project_fields?: TestFieldDef[];
126
+ config_fields?: TestFieldDef[];
127
+ /** Operator-entered per-row annotation. Recorded onto each cycle row
128
+ * by the server and rendered as the first Cycle Data columns after
129
+ * the row index, in declared order. */
130
+ cycle_config_fields?: TestFieldDef[];
131
+ cycle_fields?: TestFieldDef[];
132
+ results_fields?: TestFieldDef[];
123
133
  raw_data?: RawDataShape | null;
124
134
  views?: {
125
135
  [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;CAC9E;AAED,MAAM,WAAW,SAAS;IAAI,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CAAE;AAChF,MAAM,WAAW,WAAW;IAAG,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAAE;AAC5G;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IACxB,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,4DAA4D;IAC5D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AACD,MAAM,WAAW,SAAS;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,eAAe,GAAG,WAAW,CAAC;IACpC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,KAAK,GAAG,UAAU,CAAC;IAC5B,CAAC,EAAE,SAAS,CAAC;IACb,CAAC,EAAE,WAAW,EAAE,CAAC;IACjB;;;;;;;;;;OAUG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;CAC3B;AACD,MAAM,WAAW,SAAS;IAAG,MAAM,EAAE,MAAM,CAAC;CAAE;AAC9C,MAAM,WAAW,YAAY;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB;;8CAE0C;IAC1C,OAAO,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC;IACtC,KAAK,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;CACrC;AACD;oDACoD;AACpD,MAAM,WAAW,iBAAiB;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uEAAuE;IACvE,QAAQ,CAAC,EAAE;QAAE,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,CAAC;CACvC;AACD,MAAM,WAAW,UAAU;IACvB,cAAc,EAAG,YAAY,EAAE,CAAC;IAChC,aAAa,EAAI,YAAY,EAAE,CAAC;IAChC,YAAY,EAAK,YAAY,EAAE,CAAC;IAChC,cAAc,EAAG,YAAY,EAAE,CAAC;IAChC,QAAQ,CAAC,EAAQ,YAAY,GAAG,IAAI,CAAC;IACrC,KAAK,CAAC,EAAW;QAAE,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC;IAC/C,wDAAwD;IACxD,KAAK,CAAC,EAAW,MAAM,CAAC;IACxB,qDAAqD;IACrD,WAAW,CAAC,EAAK,MAAM,CAAC;IACxB,oEAAoE;IACpE,cAAc,CAAC,EAAE,iBAAiB,EAAE,CAAC;CACxC;AAED,MAAM,WAAW,iBAAiB;IAC9B,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,QAAQ,CAAC,EAAG,MAAM,CAAC;IACnB,gEAAgE;IAChE,KAAK,CAAC,EAAM,MAAM,CAAC;IACnB,kEAAkE;IAClE,MAAM,CAAC,EAAK,UAAU,CAAC;IACvB,8EAA8E;IAC9E,UAAU,CAAC,EAAG,MAAM,CAAC;IACrB,wDAAwD;IACxD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;uEACmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAID,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAkpBpD,CAAC"}
1
+ {"version":3,"file":"TestDataView.d.ts","sourceRoot":"","sources":["../../../src/components/tis/TestDataView.tsx"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import React,{useCallback,useContext,useEffect,useMemo,useRef,useState}from"react";import{Button}from"primereact/button";import{Column}from"primereact/column";import{DataTable}from"primereact/datatable";import{Dialog}from"primereact/dialog";import{Dropdown}from"primereact/dropdown";import{TabView,TabPanel}from"primereact/tabview";import{Chart as ChartJS,CategoryScale,LinearScale,PointElement,LineElement,Title,Tooltip,Legend}from"chart.js";import zoomPlugin from"chartjs-plugin-zoom";import annotationPlugin from"chartjs-plugin-annotation";import{Line}from"react-chartjs-2";import{EventEmitterContext}from"../../core/EventEmitterContext";import{MessageType}from"../../hub/CommandMessage";import{useTis}from"./TisProvider";import{useRawCycleData}from"./useRawCycleData";import{ScienceTable}from"./ScienceTable";ChartJS.register(CategoryScale,LinearScale,PointElement,LineElement,Title,Tooltip,Legend,zoomPlugin,annotationPlugin);export const TestDataView=e=>{const t=useTis(),r=e.projectId??t.selection.projectId,a=e.methodId??t.selection.methodId,n=e.runId??t.selection.runId,l=e.schema??(a?t.schemas[a]:void 0),{throttleMs:o=100,cycleTableHeight:s="400px",chartHeight:i="320px"}=e,{invoke:c,subscribe:d,unsubscribe:u}=useContext(EventEmitterContext),[m,p]=useState(null),[y,f]=useState([]),[h,g]=useState({}),[_,x]=useState({}),[b,j]=useState(!1),[v,w]=useState(!1),C=useRef(null),[S,T]=useState(null),[R,M]=useState(null),[L,I]=useState(!1),[E,O]=useState(null),[A,D]=useState(null),[N,k]=useState(!1),[F,H]=useState([]),[z,P]=useState(null),B=useMemo(()=>{const e=[];for(const[t,r]of Object.entries(l?.views??{}))e.push({name:t,view:r});return e},[l]),[V,$]=useState(B.length>0?B[0].name:null);useEffect(()=>{if(0===B.length)return;null!==V&&B.some(e=>e.name===V)||$(B[0].name)},[B,V]);const G=B.find(e=>e.name===V)?.view,W="raw_trace"===G?.type,q=useRef([]),U=useRef(null),J=useRef(null),Y=()=>{J.current||(J.current=setTimeout(()=>{if(J.current=null,q.current.length>0){const e=q.current;q.current=[],f(t=>[...e.slice().reverse(),...t])}U.current&&(g(U.current),U.current=null)},o))};useEffect(()=>{if(!r||!a||!n)return p(null),f([]),void g({});let e=!1;return(async()=>{try{const t=await c("tis.read_test",MessageType.Request,{project_id:r,method_id:a,run_id:n});!e&&t?.success&&(p(t.data),g(t.data.results??{}));const l=await c("tis.read_cycles",MessageType.Request,{project_id:r,method_id:a,run_id:n,offset:0,limit:200,order:"desc"});!e&&l?.success&&f(l.data.cycles??[])}catch(e){}})(),()=>{e=!0}},[r,a,n,c]),useEffect(()=>{const e=e=>e?.project_id===r&&e?.method_id===a&&e?.run_id===n,t=d("tis.cycle_added",t=>{e(t)&&t.cycle&&(q.current.push(t.cycle),Y())}),l=d("tis.results_updated",t=>{e(t)&&(U.current=t.results??{},Y())});return()=>{u(t),u(l),J.current&&(clearTimeout(J.current),J.current=null)}},[r,a,n,o]);const Z="string"==typeof m?.sample_id&&m.sample_id?m.sample_id:"string"==typeof m?.config?.sample_id?m.config.sample_id:"";useEffect(()=>{if(!r||!a||!Z)return void x({});let e=!1;(async()=>{try{const t=await c("tis.sample_summary",MessageType.Request,{project_id:r,method_id:a,sample_id:Z});!e&&t?.success&&x(t.data?.summary??{})}catch(e){}})();const t=d("tis.sample_summary_updated",e=>{e?.project_id===r&&e?.method_id===a&&e?.sample_id===Z&&x(e.summary??{})});return()=>{e=!0,u(t)}},[r,a,Z,c,d,u]);const K=useRawCycleData({projectId:r,methodId:a,runId:n,blobName:l?.raw_data?.blob_name??"trace",source:G?.source??"raw",enabled:W}),Q=useMemo(()=>{if(!G)return null;if("cycle_scatter"===G.type){const e=G.x.field;if(!e)return null;const t=[...y].reverse();return{labels:t.map(t=>t[e]),datasets:G.y.map((e,r)=>({label:e.label??e.field,data:t.map(t=>t[e.field]),yAxisID:"right"===e.y_axis?"y1":"y",borderColor:palette(r),backgroundColor:palette(r),tension:.1,pointRadius:2}))}}if("raw_trace"===G.type){if(!K.raw)return null;const e=G.x.column;if(!e)return null;const t=K.raw[e]??[],r=!1!==G.smooth;return{datasets:G.y.map((e,a)=>{const n=K.raw[e.column]??[],l=r?smoothTraceForDisplay(t,n,G.smoothWindow):n.map((e,r)=>({x:t[r],y:e}));return{label:e.label??e.column,data:l,yAxisID:"right"===e.y_axis?"y1":"y",borderColor:palette(a),backgroundColor:palette(a),pointRadius:0,borderWidth:1.5,showLine:!0,...r?{cubicInterpolationMode:"monotone"}:{}}})}}return null},[G,y,K.raw]),X=G?.y.some(e=>"right"===e.y_axis)??!1,ee=useMemo(()=>{if(!W)return[];const e=K.envelope,t=e?.regions??e?.context?.regions;return Array.isArray(t)?t:[]},[W,K.envelope]),te=useMemo(()=>[...G?.regions??[],...ee],[G,ee]),re=useMemo(()=>{const e="raw_trace"===G?.type;return{responsive:!0,maintainAspectRatio:!1,parsing:!e&&void 0,scales:{x:e?{type:"linear",title:{display:!!G?.x.label,text:G?.x.label}}:{title:{display:!!G?.x.label,text:G?.x.label}},y:{position:"left",title:{display:!0,text:leftAxisLabel(G)}},...X?{y1:{position:"right",grid:{drawOnChartArea:!1},title:{display:!0,text:rightAxisLabel(G)}}}:{}},plugins:{legend:{display:!0},zoom:{pan:{enabled:!0,mode:"xy"},zoom:{wheel:{enabled:!0},pinch:{enabled:!0},mode:"xy"}},annotation:{annotations:buildRegionAnnotations(te)}}}},[G,X,te]),ae=l?.raw_data?.blob_name??"trace",ne=useRef(""),le=useCallback(async()=>{if(!r||!a||!n)return[];try{const e=await c("tis.list_raw",MessageType.Request,{project_id:r,method_id:a,run_id:n});if(!e?.success)return[];const t=e.data?.cycles??[];return t.filter(e=>e?.name===ae&&"number"==typeof e?.cycle_index).map(e=>e.cycle_index).sort((e,t)=>e-t)}catch{return[]}},[r,a,n,ae,c]),oe=useCallback(async e=>{if(!r||!a||!n)return;const t=`${r}|${a}|${n}|${ae}|${e??"latest"}`;if(ne.current===t)return;ne.current=t;const l={project_id:r,method_id:a,run_id:n,name:ae};null!=e&&(l.cycle_index=e),I(!0),M(null),T(null);try{const e=await c("tis.read_raw",MessageType.Request,l);e?.success?T(e.data??{}):M(e?.error_message??"No raw data on disk for this run.")}catch(e){M(String(e?.message??e))}finally{I(!1)}k(!0),D(null),O(null);try{const e=await c("tis.read_filtered",MessageType.Request,l);e?.success?O(e.data??{}):D(e?.error_message??"No filtered data on disk for this run.")}catch(e){D(String(e?.message??e))}finally{k(!1)}},[r,a,n,ae,c]);useEffect(()=>{ne.current="",H([]),P(null)},[r,a,n,ae]);return useEffect(()=>{b&&null!=z&&oe(z)},[b,z,oe]),r&&a&&n&&l?_jsxs("div",{className:"vblock",style:{display:"flex",flexDirection:"column",gap:"1rem"},children:[_jsx(Header,{meta:m,config:m?.config,runId:n,projectId:r,methodId:a,canViewRaw:!!l.raw_data,onViewRaw:async()=>{j(!0);let e=F;0===e.length&&(e=await le(),H(e));const t=e.length>0?e[e.length-1]:null,r=z??t;z!==r&&P(r),await oe(r)},onShowConfig:()=>w(!0)}),_jsxs("div",{className:"p-card",style:{padding:"1rem"},children:[_jsxs("div",{className:"flex",style:{gap:"1rem",alignItems:"center",marginBottom:"0.5rem",flexWrap:"wrap"},children:[_jsx(Dropdown,{value:V,options:B.map(e=>({label:e.view.title??e.name,value:e.name})),onChange:e=>$(e.value),placeholder:0===B.length?"No view defined":"Select a view",disabled:0===B.length}),_jsx("h3",{style:{margin:0},children:G?.title??""}),W&&K.cycles.length>1&&_jsxs(_Fragment,{children:[_jsx("label",{htmlFor:"chart-cycle-picker",style:{color:"var(--text-secondary-color)"},children:"Cycle:"}),_jsx(Dropdown,{inputId:"chart-cycle-picker",value:K.selectedCycle,options:K.cycles.map(e=>({label:`Cycle ${e}`,value:e})),onChange:e=>K.setSelectedCycle(Number(e.value)),style:{minWidth:"8rem"}}),_jsxs("span",{style:{color:"var(--text-secondary-color)"},children:["of ",K.cycles.length]})]}),_jsx("div",{style:{flex:1}}),_jsx(Button,{icon:"pi pi-th-large",outlined:!0,rounded:!0,size:"small",onClick:()=>C.current?.resetZoom?.(),disabled:!Q,tooltip:"Reset chart zoom",tooltipOptions:{position:"left"},"aria-label":"Reset chart zoom"})]}),_jsxs("div",{style:{height:i,position:"relative"},children:[W&&K.loading&&_jsx(ChartOverlay,{children:"Loading raw data…"}),W&&K.error&&_jsx(ChartOverlay,{children:K.error}),Q&&_jsx(Line,{ref:C,data:Q,options:re})]})]}),(()=>{const e=y.length>CYCLE_VIRTUAL_THRESHOLD,t=l.cycle_fields.map(e=>({field:e.name,label:e.name,units:e.units,body:t=>formatCell(t[e.name],e.type,e.scale)}));return _jsx(ScienceTable,{title:`Cycle Data (${y.length})`,columns:t,rows:y,scrollable:e,scrollHeight:e?s:void 0,emptyMessage:"No cycles yet."})})(),(()=>{const e={...h,..._},t=Object.keys(e).length>0,r=l.results_fields.map(e=>({field:e.name,label:e.name,units:e.units,body:t=>formatCell(t[e.name],e.type,e.scale)}));return _jsx(ScienceTable,{title:"Results",columns:r,rows:t?[e]:[],emptyMessage:"No results yet."})})(),l.raw_data&&_jsxs(Dialog,{visible:b,onHide:()=>j(!1),header:`Run Data — ${n}`,style:{width:"90vw",height:"80vh"},maximizable:!0,children:[_jsx(CyclePickerBar,{cycles:F,selected:z,onChange:P}),_jsx(RawEnvelopeHeader,{envelope:S}),_jsxs(TabView,{style:{height:"100%"},children:[_jsx(TabPanel,{header:"Raw Data",children:_jsx(DataBlobTable,{blob:unwrapEnvelope(S),loading:L,error:R,rawData:l.raw_data})}),_jsx(TabPanel,{header:"Filtered Data",children:_jsx(DataBlobTable,{blob:unwrapEnvelope(E),loading:N,error:A,rawData:l.raw_data,emptyMessage:"Filtered data is written by post-processing — none on disk for this run yet."})})]})]}),_jsx(Dialog,{visible:v,onHide:()=>w(!1),header:"Test Configuration",style:{width:"min(640px, 90vw)"},modal:!0,children:_jsx(ConfigList,{config:m?.config})})]}):_jsx("div",{className:"p-card",style:{padding:"1rem",color:"var(--text-secondary-color)"},children:"No test selected. Pick a row from the History tab or start a run."})};const Header=({meta:e,config:t,runId:r,projectId:a,methodId:n,canViewRaw:l,onViewRaw:o,onShowConfig:s})=>{const i="string"==typeof e?.sample_id&&e.sample_id||"string"==typeof e?.config?.sample_id&&e.config.sample_id||"",c=t&&"object"==typeof t&&Object.entries(t).some(([e])=>"sample_id"!==e);return _jsx("div",{className:"p-card",style:{padding:"1rem"},children:_jsxs("div",{className:"flex",style:{justifyContent:"space-between",alignItems:"flex-start",gap:"1rem"},children:[_jsxs("div",{children:[_jsxs("h2",{style:{margin:0,display:"flex",alignItems:"center",gap:"0.5rem"},children:[i||r,c&&_jsx(Button,{icon:"pi pi-info-circle",type:"button",rounded:!0,text:!0,onClick:s,tooltip:"Show test configuration",tooltipOptions:{position:"top"},style:{width:"2rem",height:"2rem",padding:0},"aria-label":"Show test configuration"})]}),_jsxs("div",{style:{color:"var(--text-secondary-color)",fontSize:"0.85em"},children:["project: ",a," · method: ",n," · run: ",r,e?.start_time&&_jsxs(_Fragment,{children:[" · started: ",new Date(e.start_time).toLocaleString()]})]})]}),l&&_jsx(Button,{icon:"pi pi-table",label:"View Raw Data",onClick:o,outlined:!0})]})})},ConfigList=({config:e})=>{const t=e&&"object"==typeof e?Object.entries(e).filter(([e])=>"sample_id"!==e):[];return 0===t.length?_jsx("div",{style:{color:"var(--text-secondary-color)"},children:"No configuration recorded for this run."}):_jsx("div",{style:{display:"grid",gridTemplateColumns:"auto 1fr",gap:"0.5rem 1rem",fontSize:"0.95em"},children:t.map(([e,t])=>_jsxs(React.Fragment,{children:[_jsx("div",{style:{color:"var(--text-secondary-color)"},children:e}),_jsx("div",{children:formatCell(t,"string")})]},e))})},unwrapEnvelope=e=>e&&"object"==typeof e&&"data"in e&&e.data&&"object"==typeof e.data&&Object.values(e.data).some(e=>Array.isArray(e))?e.data:e,CyclePickerBar=({cycles:e,selected:t,onChange:r})=>e.length<=1?null:_jsxs("div",{style:{display:"flex",alignItems:"center",gap:"0.5rem",padding:"0.25rem 0.5rem 0.5rem"},children:[_jsx("label",{htmlFor:"raw-cycle-picker",style:{color:"var(--text-secondary-color)"},children:"Cycle:"}),_jsx(Dropdown,{inputId:"raw-cycle-picker",value:t,options:e.map(e=>({label:`Cycle ${e}`,value:e})),onChange:e=>r(Number(e.value)),style:{minWidth:"8rem"}}),_jsxs("span",{style:{color:"var(--text-secondary-color)"},children:["(",e.length," cycles recorded)"]})]}),RawEnvelopeHeader=({envelope:e})=>{if(!e||"object"!=typeof e)return null;const t=e.cycle_index,r=e.cycle_fields,a=e.context;if(null==t&&!r&&!a)return null;const n=e=>{if(!e||"object"!=typeof e)return null;const t=Object.entries(e).filter(([,e])=>null!==e&&"object"!=typeof e);return 0===t.length?null:t.map(([e,t])=>_jsxs("span",{style:{marginRight:"1rem"},children:[_jsxs("span",{style:{color:"var(--text-secondary-color)"},children:[e,": "]}),_jsx("span",{children:String(t)})]},e))};return _jsxs("div",{style:{padding:"0.5rem",borderBottom:"1px solid var(--surface-border)",fontSize:"0.9rem"},children:[null!=t&&_jsx("div",{children:_jsxs("strong",{children:["Cycle ",t]})}),r&&_jsx("div",{style:{marginTop:"0.25rem"},children:n(r)}),a&&_jsx("div",{style:{marginTop:"0.25rem"},children:n(a)})]})},DataBlobTable=({blob:e,loading:t,error:r,rawData:a,emptyMessage:n})=>{if(t)return _jsx("div",{style:{padding:"1rem",color:"var(--text-secondary-color)"},children:"Loading…"});if(r)return _jsx("div",{style:{padding:"1rem",color:"var(--text-secondary-color)"},children:n??r});if(!e||"object"!=typeof e)return _jsx("div",{style:{padding:"1rem",color:"var(--text-secondary-color)"},children:"No data."});const l=Object.keys(a.columns??{}),o=Object.keys(e).filter(t=>Array.isArray(e[t])),s=[];for(const t of l)Array.isArray(e[t])&&s.push(t);for(const e of o)s.includes(e)||s.push(e);if(0===s.length)return _jsx("div",{style:{padding:"1rem",color:"var(--text-secondary-color)"},children:n??"No columnar data in this blob."});const i=s.reduce((t,r)=>Math.min(t,e[r].length),Number.POSITIVE_INFINITY),c=Number.isFinite(i)?i:0,d=Array.from({length:c},(t,r)=>{const a={__i:r};for(const t of s)a[t]=e[t][r];return a}),u=e=>{const t=a.units?.[e];return t?`${e} [${t}]`:e};return _jsxs(DataTable,{value:d,scrollable:!0,scrollHeight:"60vh",virtualScrollerOptions:{itemSize:32},emptyMessage:n??"No data.",size:"small",stripedRows:!0,children:[_jsx(Column,{field:"__i",header:"#",style:{width:"5rem",textAlign:"right"},bodyStyle:{fontVariantNumeric:"tabular-nums",textAlign:"right"}}),s.map(e=>_jsx(Column,{field:e,header:u(e),style:{minWidth:"8rem"},bodyStyle:{fontVariantNumeric:"tabular-nums",textAlign:"right"},body:t=>formatNumeric(t[e])},e))]})},formatNumeric=e=>null==e?"":"number"==typeof e&&Number.isFinite(e)?Number.parseFloat(e.toPrecision(6)).toString():String(e),CYCLE_VIRTUAL_THRESHOLD=30,CHART_COLORS=["#4ea8de","#f59e0b","#22c55e","#a855f7","#ef4444","#14b8a6","#eab308","#ec4899"],palette=e=>CHART_COLORS[e%CHART_COLORS.length],SG_ORDER=3,SMOOTH_TARGET_POINTS=800;function invertMatrix(e){const t=e.length,r=e.map((e,r)=>[...e,...Array.from({length:t},(e,t)=>r===t?1:0)]);for(let e=0;e<t;e++){let a=e;for(let n=e+1;n<t;n++)Math.abs(r[n][e])>Math.abs(r[a][e])&&(a=n);if(Math.abs(r[a][e])<1e-12)return null;[r[e],r[a]]=[r[a],r[e]];const n=r[e][e];for(let a=0;a<2*t;a++)r[e][a]/=n;for(let a=0;a<t;a++){if(a===e)continue;const n=r[a][e];if(0!==n)for(let l=0;l<2*t;l++)r[a][l]-=n*r[e][l]}}return r.map(e=>e.slice(t))}function sgWeights(e,t){const r=2*e+1,a=Math.min(t,r-1),n=[];for(let t=-e;t<=e;t++){const e=[];let r=1;for(let n=0;n<=a;n++)e.push(r),r*=t;n.push(e)}const l=a+1,o=Array.from({length:l},()=>new Array(l).fill(0));for(let e=0;e<l;e++)for(let t=0;t<l;t++){let a=0;for(let l=0;l<r;l++)a+=n[l][e]*n[l][t];o[e][t]=a}const s=invertMatrix(o);if(!s)return new Array(r).fill(1/r);const i=new Array(r);for(let e=0;e<r;e++){let t=0;for(let r=0;r<l;r++)t+=s[0][r]*n[e][r];i[e]=t}return i}function savitzkyGolay(e,t){const r=e.length;if(0===r||t<1)return e.slice();const a=new Map,n=e=>{let t=a.get(e);return t||(t=sgWeights(e,3),a.set(e,t)),t},l=new Array(r);for(let a=0;a<r;a++){const o=Math.min(t,a,r-1-a);if(o<1){l[a]=e[a];continue}const s=n(o);let i=0;for(let t=-o;t<=o;t++)i+=s[t+o]*e[a+t];l[a]=i}return l}function smoothTraceForDisplay(e,t,r){const a=Math.min(e.length,t.length);if(0===a)return[];const n=r&&r>1?Math.max(1,Math.floor((Math.min(r,a)-1)/2)):Math.max(2,Math.min(40,Math.round(a/250))),l=savitzkyGolay(t.slice(0,a),n),o=Math.max(1,Math.ceil(a/SMOOTH_TARGET_POINTS)),s=[];for(let t=0;t<a;t+=o)s.push({x:e[t],y:l[t]});return(a-1)%o!=0&&s.push({x:e[a-1],y:l[a-1]}),s}const DEFAULT_REGION_FILL="rgba(78, 168, 222, 0.15)",REGION_LABEL_COLOR="rgba(226, 232, 240, 0.85)";function buildRegionAnnotations(e){if(!e||0===e.length)return{};const t={};return e.forEach((e,r)=>{const a=!!e.borderColor;t[`region-${r}`]={type:"box",xScaleID:"x",xMin:e.xMin,xMax:e.xMax,backgroundColor:e.color??DEFAULT_REGION_FILL,borderColor:a?e.borderColor:"transparent",borderWidth:a?1:0,drawTime:"beforeDatasetsDraw",...e.label?{label:{display:!0,content:e.label,position:{x:"center",y:"start"},color:REGION_LABEL_COLOR,font:{size:11}}}:{}}}),t}const ChartOverlay=({children:e})=>_jsx("div",{style:{position:"absolute",inset:0,display:"flex",alignItems:"center",justifyContent:"center",color:"var(--text-secondary-color)",pointerEvents:"none"},children:e}),seriesLabel=e=>e.label??e.field??e.column??"",leftAxisLabel=e=>e?.y.filter(e=>"right"!==e.y_axis).map(seriesLabel).join(" / ")??"",rightAxisLabel=e=>e?.y.filter(e=>"right"===e.y_axis).map(seriesLabel).join(" / ")??"",formatCell=(e,t,r)=>null==e?"":(r&&1!==r&&"number"==typeof e&&Number.isFinite(e)&&(e*=r),"f32"===t||"f64"===t?"number"==typeof e?e.toFixed(4):String(e):"object"==typeof e?JSON.stringify(e):String(e));
1
+ import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import React,{useCallback,useContext,useEffect,useMemo,useRef,useState}from"react";import{Button}from"primereact/button";import{Column}from"primereact/column";import{DataTable}from"primereact/datatable";import{Dialog}from"primereact/dialog";import{Dropdown}from"primereact/dropdown";import{TabView,TabPanel}from"primereact/tabview";import{Chart as ChartJS,CategoryScale,LinearScale,PointElement,LineElement,Title,Tooltip,Legend}from"chart.js";import zoomPlugin from"chartjs-plugin-zoom";import annotationPlugin from"chartjs-plugin-annotation";import{Line}from"react-chartjs-2";import{EventEmitterContext}from"../../core/EventEmitterContext";import{MessageType}from"../../hub/CommandMessage";import{useTis}from"./TisProvider";import{useRawCycleData}from"./useRawCycleData";import{ScienceTable}from"./ScienceTable";ChartJS.register(CategoryScale,LinearScale,PointElement,LineElement,Title,Tooltip,Legend,zoomPlugin,annotationPlugin);export const TestDataView=e=>{const t=useTis(),r=e.projectId??t.selection.projectId,a=e.methodId??t.selection.methodId,n=e.runId??t.selection.runId,l=e.schema??(a?t.schemas[a]:void 0),{throttleMs:o=100,cycleTableHeight:s="400px",chartHeight:i="320px"}=e,{invoke:c,subscribe:d,unsubscribe:u}=useContext(EventEmitterContext),[m,p]=useState(null),[y,f]=useState([]),[h,g]=useState({}),[_,x]=useState({}),[b,j]=useState(!1),[v,w]=useState(!1),C=useCallback(async(e,t,l)=>{const o=e?.cycle_index;if(r&&a&&n&&o)try{const e=await c("tis.update_cycle",MessageType.Request,{project_id:r,method_id:a,run_id:n,cycle_index:o,fields:{[t]:l}});if(!1===e?.success)return;f(e=>e.map(e=>e?.cycle_index===o?{...e,[t]:l}:e))}catch(e){}},[c,r,a,n]),S=useRef(null),[T,R]=useState(null),[M,L]=useState(null),[E,I]=useState(!1),[O,A]=useState(null),[D,N]=useState(null),[k,F]=useState(!1),[H,z]=useState([]),[P,B]=useState(null),V=useMemo(()=>{const e=[];for(const[t,r]of Object.entries(l?.views??{}))e.push({name:t,view:r});return e},[l]),[$,G]=useState(V.length>0?V[0].name:null);useEffect(()=>{if(0===V.length)return;null!==$&&V.some(e=>e.name===$)||G(V[0].name)},[V,$]);const W=V.find(e=>e.name===$)?.view,q="raw_trace"===W?.type,U=useRef([]),J=useRef(null),Y=useRef(null),Z=()=>{Y.current||(Y.current=setTimeout(()=>{if(Y.current=null,U.current.length>0){const e=U.current;U.current=[],f(t=>[...e.slice().reverse(),...t])}J.current&&(g(J.current),J.current=null)},o))};useEffect(()=>{if(!r||!a||!n)return p(null),f([]),void g({});let e=!1;return(async()=>{try{const t=await c("tis.read_test",MessageType.Request,{project_id:r,method_id:a,run_id:n});!e&&t?.success&&(p(t.data),g(t.data.results??{}));const l=await c("tis.read_cycles",MessageType.Request,{project_id:r,method_id:a,run_id:n,offset:0,limit:200,order:"desc"});!e&&l?.success&&f(l.data.cycles??[])}catch(e){}})(),()=>{e=!0}},[r,a,n,c]),useEffect(()=>{const e=e=>e?.project_id===r&&e?.method_id===a&&e?.run_id===n,t=d("tis.cycle_added",t=>{e(t)&&t.cycle&&(U.current.push(t.cycle),Z())}),l=d("tis.results_updated",t=>{e(t)&&(J.current=t.results??{},Z())});return()=>{u(t),u(l),Y.current&&(clearTimeout(Y.current),Y.current=null)}},[r,a,n,o]);const K="string"==typeof m?.sample_id&&m.sample_id?m.sample_id:"string"==typeof m?.config?.sample_id?m.config.sample_id:"";useEffect(()=>{if(!r||!a||!K)return void x({});let e=!1;(async()=>{try{const t=await c("tis.sample_summary",MessageType.Request,{project_id:r,method_id:a,sample_id:K});!e&&t?.success&&x(t.data?.summary??{})}catch(e){}})();const t=d("tis.sample_summary_updated",e=>{e?.project_id===r&&e?.method_id===a&&e?.sample_id===K&&x(e.summary??{})});return()=>{e=!0,u(t)}},[r,a,K,c,d,u]);const Q=useRawCycleData({projectId:r,methodId:a,runId:n,blobName:l?.raw_data?.blob_name??"trace",source:W?.source??"raw",enabled:q}),X=useMemo(()=>{if(!W)return null;if("cycle_scatter"===W.type){const e=W.x.field;if(!e)return null;const t=[...y].reverse();return{labels:t.map(t=>t[e]),datasets:W.y.map((e,r)=>({label:e.label??e.field,data:t.map(t=>t[e.field]),yAxisID:"right"===e.y_axis?"y1":"y",borderColor:palette(r),backgroundColor:palette(r),tension:.1,pointRadius:2}))}}if("raw_trace"===W.type){if(!Q.raw)return null;const e=W.x.column;if(!e)return null;const t=Q.raw[e]??[],r=!1!==W.smooth;return{datasets:W.y.map((e,a)=>{const n=Q.raw[e.column]??[],l=r?smoothTraceForDisplay(t,n,W.smoothWindow):n.map((e,r)=>({x:t[r],y:e}));return{label:e.label??e.column,data:l,yAxisID:"right"===e.y_axis?"y1":"y",borderColor:palette(a),backgroundColor:palette(a),pointRadius:0,borderWidth:1.5,showLine:!0,...r?{cubicInterpolationMode:"monotone"}:{}}})}}return null},[W,y,Q.raw]),ee=W?.y.some(e=>"right"===e.y_axis)??!1,te=useMemo(()=>{if(!q)return[];const e=Q.envelope,t=e?.regions??e?.context?.regions;return Array.isArray(t)?t:[]},[q,Q.envelope]),re=useMemo(()=>[...W?.regions??[],...te],[W,te]),ae=useMemo(()=>{const e="raw_trace"===W?.type;return{responsive:!0,maintainAspectRatio:!1,parsing:!e&&void 0,scales:{x:e?{type:"linear",title:{display:!!W?.x.label,text:W?.x.label}}:{title:{display:!!W?.x.label,text:W?.x.label}},y:{position:"left",title:{display:!0,text:leftAxisLabel(W)}},...ee?{y1:{position:"right",grid:{drawOnChartArea:!1},title:{display:!0,text:rightAxisLabel(W)}}}:{}},plugins:{legend:{display:!0},zoom:{pan:{enabled:!0,mode:"xy"},zoom:{wheel:{enabled:!0},pinch:{enabled:!0},mode:"xy"}},annotation:{annotations:buildRegionAnnotations(re)}}}},[W,ee,re]),ne=l?.raw_data?.blob_name??"trace",le=useRef(""),oe=useCallback(async()=>{if(!r||!a||!n)return[];try{const e=await c("tis.list_raw",MessageType.Request,{project_id:r,method_id:a,run_id:n});if(!e?.success)return[];const t=e.data?.cycles??[];return t.filter(e=>e?.name===ne&&"number"==typeof e?.cycle_index).map(e=>e.cycle_index).sort((e,t)=>e-t)}catch{return[]}},[r,a,n,ne,c]),se=useCallback(async e=>{if(!r||!a||!n)return;const t=`${r}|${a}|${n}|${ne}|${e??"latest"}`;if(le.current===t)return;le.current=t;const l={project_id:r,method_id:a,run_id:n,name:ne};null!=e&&(l.cycle_index=e),I(!0),L(null),R(null);try{const e=await c("tis.read_raw",MessageType.Request,l);e?.success?R(e.data??{}):L(e?.error_message??"No raw data on disk for this run.")}catch(e){L(String(e?.message??e))}finally{I(!1)}F(!0),N(null),A(null);try{const e=await c("tis.read_filtered",MessageType.Request,l);e?.success?A(e.data??{}):N(e?.error_message??"No filtered data on disk for this run.")}catch(e){N(String(e?.message??e))}finally{F(!1)}},[r,a,n,ne,c]);useEffect(()=>{le.current="",z([]),B(null)},[r,a,n,ne]);return useEffect(()=>{b&&null!=P&&se(P)},[b,P,se]),r&&a&&n&&l?_jsxs("div",{className:"vblock",style:{display:"flex",flexDirection:"column",gap:"1rem"},children:[_jsx(Header,{meta:m,config:m?.config,runId:n,projectId:r,methodId:a,canViewRaw:!!l.raw_data,onViewRaw:async()=>{j(!0);let e=H;0===e.length&&(e=await oe(),z(e));const t=e.length>0?e[e.length-1]:null,r=P??t;P!==r&&B(r),await se(r)},onShowConfig:()=>w(!0)}),_jsxs("div",{className:"p-card",style:{padding:"1rem"},children:[_jsxs("div",{className:"flex",style:{gap:"1rem",alignItems:"center",marginBottom:"0.5rem",flexWrap:"wrap"},children:[_jsx(Dropdown,{value:$,options:V.map(e=>({label:e.view.title??e.name,value:e.name})),onChange:e=>G(e.value),placeholder:0===V.length?"No view defined":"Select a view",disabled:0===V.length}),_jsx("h3",{style:{margin:0},children:W?.title??""}),q&&Q.cycles.length>1&&_jsxs(_Fragment,{children:[_jsx("label",{htmlFor:"chart-cycle-picker",style:{color:"var(--text-secondary-color)"},children:"Cycle:"}),_jsx(Dropdown,{inputId:"chart-cycle-picker",value:Q.selectedCycle,options:Q.cycles.map(e=>({label:`Cycle ${e}`,value:e})),onChange:e=>Q.setSelectedCycle(Number(e.value)),style:{minWidth:"8rem"}}),_jsxs("span",{style:{color:"var(--text-secondary-color)"},children:["of ",Q.cycles.length]})]}),_jsx("div",{style:{flex:1}}),_jsx(Button,{icon:"pi pi-th-large",outlined:!0,rounded:!0,size:"small",onClick:()=>S.current?.resetZoom?.(),disabled:!X,tooltip:"Reset chart zoom",tooltipOptions:{position:"left"},"aria-label":"Reset chart zoom"})]}),_jsxs("div",{style:{height:i,position:"relative"},children:[q&&Q.loading&&_jsx(ChartOverlay,{children:"Loading raw data…"}),q&&Q.error&&_jsx(ChartOverlay,{children:Q.error}),X&&_jsx(Line,{ref:S,data:X,options:ae})]})]}),(()=>{const e=y.length>CYCLE_VIRTUAL_THRESHOLD,t=(e,t)=>({field:e.name,label:e.name,units:e.units,editable:t,body:t=>formatCell(t[e.name],e.type,e.scale)}),r=[...(l.cycle_config_fields??[]).map(e=>t(e,!0)),...(l.cycle_fields??[]).map(e=>t(e,!!e.editable))];return _jsx(ScienceTable,{title:`Cycle Data (${y.length})`,columns:r,rows:y,scrollable:e,scrollHeight:e?s:void 0,emptyMessage:"No cycles yet.",onCellEdit:C})})(),(()=>{const e={...h,..._},t=Object.keys(e).length>0,r=(l.results_fields??[]).map(e=>({field:e.name,label:e.name,units:e.units,body:t=>formatCell(t[e.name],e.type,e.scale)}));return _jsx(ScienceTable,{title:"Results",columns:r,rows:t?[e]:[],emptyMessage:"No results yet."})})(),l.raw_data&&_jsxs(Dialog,{visible:b,onHide:()=>j(!1),header:`Run Data — ${n}`,style:{width:"90vw",height:"80vh"},maximizable:!0,children:[_jsx(CyclePickerBar,{cycles:H,selected:P,onChange:B}),_jsx(RawEnvelopeHeader,{envelope:T}),_jsxs(TabView,{style:{height:"100%"},children:[_jsx(TabPanel,{header:"Raw Data",children:_jsx(DataBlobTable,{blob:unwrapEnvelope(T),loading:E,error:M,rawData:l.raw_data})}),_jsx(TabPanel,{header:"Filtered Data",children:_jsx(DataBlobTable,{blob:unwrapEnvelope(O),loading:k,error:D,rawData:l.raw_data,emptyMessage:"Filtered data is written by post-processing — none on disk for this run yet."})})]})]}),_jsx(Dialog,{visible:v,onHide:()=>w(!1),header:"Test Configuration",style:{width:"min(640px, 90vw)"},modal:!0,children:_jsx(ConfigList,{config:m?.config})})]}):_jsx("div",{className:"p-card",style:{padding:"1rem",color:"var(--text-secondary-color)"},children:"No test selected. Pick a row from the History tab or start a run."})};const Header=({meta:e,config:t,runId:r,projectId:a,methodId:n,canViewRaw:l,onViewRaw:o,onShowConfig:s})=>{const i="string"==typeof e?.sample_id&&e.sample_id||"string"==typeof e?.config?.sample_id&&e.config.sample_id||"",c=t&&"object"==typeof t&&Object.entries(t).some(([e])=>"sample_id"!==e);return _jsx("div",{className:"p-card",style:{padding:"1rem"},children:_jsxs("div",{className:"flex",style:{justifyContent:"space-between",alignItems:"flex-start",gap:"1rem"},children:[_jsxs("div",{children:[_jsxs("h2",{style:{margin:0,display:"flex",alignItems:"center",gap:"0.5rem"},children:[i||r,c&&_jsx(Button,{icon:"pi pi-info-circle",type:"button",rounded:!0,text:!0,onClick:s,tooltip:"Show test configuration",tooltipOptions:{position:"top"},style:{width:"2rem",height:"2rem",padding:0},"aria-label":"Show test configuration"})]}),_jsxs("div",{style:{color:"var(--text-secondary-color)",fontSize:"0.85em"},children:["project: ",a," · method: ",n," · run: ",r,e?.start_time&&_jsxs(_Fragment,{children:[" · started: ",new Date(e.start_time).toLocaleString()]})]})]}),l&&_jsx(Button,{icon:"pi pi-table",label:"View Raw Data",onClick:o,outlined:!0})]})})},ConfigList=({config:e})=>{const t=e&&"object"==typeof e?Object.entries(e).filter(([e])=>"sample_id"!==e):[];return 0===t.length?_jsx("div",{style:{color:"var(--text-secondary-color)"},children:"No configuration recorded for this run."}):_jsx("div",{style:{display:"grid",gridTemplateColumns:"auto 1fr",gap:"0.5rem 1rem",fontSize:"0.95em"},children:t.map(([e,t])=>_jsxs(React.Fragment,{children:[_jsx("div",{style:{color:"var(--text-secondary-color)"},children:e}),_jsx("div",{children:formatCell(t,"string")})]},e))})},unwrapEnvelope=e=>e&&"object"==typeof e&&"data"in e&&e.data&&"object"==typeof e.data&&Object.values(e.data).some(e=>Array.isArray(e))?e.data:e,CyclePickerBar=({cycles:e,selected:t,onChange:r})=>e.length<=1?null:_jsxs("div",{style:{display:"flex",alignItems:"center",gap:"0.5rem",padding:"0.25rem 0.5rem 0.5rem"},children:[_jsx("label",{htmlFor:"raw-cycle-picker",style:{color:"var(--text-secondary-color)"},children:"Cycle:"}),_jsx(Dropdown,{inputId:"raw-cycle-picker",value:t,options:e.map(e=>({label:`Cycle ${e}`,value:e})),onChange:e=>r(Number(e.value)),style:{minWidth:"8rem"}}),_jsxs("span",{style:{color:"var(--text-secondary-color)"},children:["(",e.length," cycles recorded)"]})]}),RawEnvelopeHeader=({envelope:e})=>{if(!e||"object"!=typeof e)return null;const t=e.cycle_index,r=e.cycle_fields,a=e.context;if(null==t&&!r&&!a)return null;const n=e=>{if(!e||"object"!=typeof e)return null;const t=Object.entries(e).filter(([,e])=>null!==e&&"object"!=typeof e);return 0===t.length?null:t.map(([e,t])=>_jsxs("span",{style:{marginRight:"1rem"},children:[_jsxs("span",{style:{color:"var(--text-secondary-color)"},children:[e,": "]}),_jsx("span",{children:String(t)})]},e))};return _jsxs("div",{style:{padding:"0.5rem",borderBottom:"1px solid var(--surface-border)",fontSize:"0.9rem"},children:[null!=t&&_jsx("div",{children:_jsxs("strong",{children:["Cycle ",t]})}),r&&_jsx("div",{style:{marginTop:"0.25rem"},children:n(r)}),a&&_jsx("div",{style:{marginTop:"0.25rem"},children:n(a)})]})},DataBlobTable=({blob:e,loading:t,error:r,rawData:a,emptyMessage:n})=>{if(t)return _jsx("div",{style:{padding:"1rem",color:"var(--text-secondary-color)"},children:"Loading…"});if(r)return _jsx("div",{style:{padding:"1rem",color:"var(--text-secondary-color)"},children:n??r});if(!e||"object"!=typeof e)return _jsx("div",{style:{padding:"1rem",color:"var(--text-secondary-color)"},children:"No data."});const l=Object.keys(a.columns??{}),o=Object.keys(e).filter(t=>Array.isArray(e[t])),s=[];for(const t of l)Array.isArray(e[t])&&s.push(t);for(const e of o)s.includes(e)||s.push(e);if(0===s.length)return _jsx("div",{style:{padding:"1rem",color:"var(--text-secondary-color)"},children:n??"No columnar data in this blob."});const i=s.reduce((t,r)=>Math.min(t,e[r].length),Number.POSITIVE_INFINITY),c=Number.isFinite(i)?i:0,d=Array.from({length:c},(t,r)=>{const a={__i:r};for(const t of s)a[t]=e[t][r];return a}),u=e=>{const t=a.units?.[e];return t?`${e} [${t}]`:e};return _jsxs(DataTable,{value:d,scrollable:!0,scrollHeight:"60vh",virtualScrollerOptions:{itemSize:32},emptyMessage:n??"No data.",size:"small",stripedRows:!0,children:[_jsx(Column,{field:"__i",header:"#",style:{width:"5rem",textAlign:"right"},bodyStyle:{fontVariantNumeric:"tabular-nums",textAlign:"right"}}),s.map(e=>_jsx(Column,{field:e,header:u(e),style:{minWidth:"8rem"},bodyStyle:{fontVariantNumeric:"tabular-nums",textAlign:"right"},body:t=>formatNumeric(t[e])},e))]})},formatNumeric=e=>null==e?"":"number"==typeof e&&Number.isFinite(e)?Number.parseFloat(e.toPrecision(6)).toString():String(e),CYCLE_VIRTUAL_THRESHOLD=30,CHART_COLORS=["#4ea8de","#f59e0b","#22c55e","#a855f7","#ef4444","#14b8a6","#eab308","#ec4899"],palette=e=>CHART_COLORS[e%CHART_COLORS.length],SG_ORDER=3,SMOOTH_TARGET_POINTS=800;function invertMatrix(e){const t=e.length,r=e.map((e,r)=>[...e,...Array.from({length:t},(e,t)=>r===t?1:0)]);for(let e=0;e<t;e++){let a=e;for(let n=e+1;n<t;n++)Math.abs(r[n][e])>Math.abs(r[a][e])&&(a=n);if(Math.abs(r[a][e])<1e-12)return null;[r[e],r[a]]=[r[a],r[e]];const n=r[e][e];for(let a=0;a<2*t;a++)r[e][a]/=n;for(let a=0;a<t;a++){if(a===e)continue;const n=r[a][e];if(0!==n)for(let l=0;l<2*t;l++)r[a][l]-=n*r[e][l]}}return r.map(e=>e.slice(t))}function sgWeights(e,t){const r=2*e+1,a=Math.min(t,r-1),n=[];for(let t=-e;t<=e;t++){const e=[];let r=1;for(let n=0;n<=a;n++)e.push(r),r*=t;n.push(e)}const l=a+1,o=Array.from({length:l},()=>new Array(l).fill(0));for(let e=0;e<l;e++)for(let t=0;t<l;t++){let a=0;for(let l=0;l<r;l++)a+=n[l][e]*n[l][t];o[e][t]=a}const s=invertMatrix(o);if(!s)return new Array(r).fill(1/r);const i=new Array(r);for(let e=0;e<r;e++){let t=0;for(let r=0;r<l;r++)t+=s[0][r]*n[e][r];i[e]=t}return i}function savitzkyGolay(e,t){const r=e.length;if(0===r||t<1)return e.slice();const a=new Map,n=e=>{let t=a.get(e);return t||(t=sgWeights(e,3),a.set(e,t)),t},l=new Array(r);for(let a=0;a<r;a++){const o=Math.min(t,a,r-1-a);if(o<1){l[a]=e[a];continue}const s=n(o);let i=0;for(let t=-o;t<=o;t++)i+=s[t+o]*e[a+t];l[a]=i}return l}function smoothTraceForDisplay(e,t,r){const a=Math.min(e.length,t.length);if(0===a)return[];const n=r&&r>1?Math.max(1,Math.floor((Math.min(r,a)-1)/2)):Math.max(2,Math.min(40,Math.round(a/250))),l=savitzkyGolay(t.slice(0,a),n),o=Math.max(1,Math.ceil(a/SMOOTH_TARGET_POINTS)),s=[];for(let t=0;t<a;t+=o)s.push({x:e[t],y:l[t]});return(a-1)%o!=0&&s.push({x:e[a-1],y:l[a-1]}),s}const DEFAULT_REGION_FILL="rgba(78, 168, 222, 0.15)",REGION_LABEL_COLOR="rgba(226, 232, 240, 0.85)";function buildRegionAnnotations(e){if(!e||0===e.length)return{};const t={};return e.forEach((e,r)=>{const a=!!e.borderColor;t[`region-${r}`]={type:"box",xScaleID:"x",xMin:e.xMin,xMax:e.xMax,backgroundColor:e.color??DEFAULT_REGION_FILL,borderColor:a?e.borderColor:"transparent",borderWidth:a?1:0,drawTime:"beforeDatasetsDraw",...e.label?{label:{display:!0,content:e.label,position:{x:"center",y:"start"},color:REGION_LABEL_COLOR,font:{size:11}}}:{}}}),t}const ChartOverlay=({children:e})=>_jsx("div",{style:{position:"absolute",inset:0,display:"flex",alignItems:"center",justifyContent:"center",color:"var(--text-secondary-color)",pointerEvents:"none"},children:e}),seriesLabel=e=>e.label??e.field??e.column??"",leftAxisLabel=e=>e?.y.filter(e=>"right"!==e.y_axis).map(seriesLabel).join(" / ")??"",rightAxisLabel=e=>e?.y.filter(e=>"right"===e.y_axis).map(seriesLabel).join(" / ")??"",formatCell=(e,t,r)=>null==e?"":(r&&1!==r&&"number"==typeof e&&Number.isFinite(e)&&(e*=r),"f32"===t||"f64"===t?"number"==typeof e?e.toFixed(4):String(e):"object"==typeof e?JSON.stringify(e):String(e));
@@ -0,0 +1,151 @@
1
+ import React from 'react';
2
+ /**
3
+ * One field in a test method's schema. Mirrors the Rust `TestField`
4
+ * (autocore-ams `config.rs`) — the same shape backs project_fields,
5
+ * config_fields, cycle_config_fields, cycle_fields and results_fields.
6
+ */
7
+ export interface TestFieldDef {
8
+ /** Canonical key — wire format, generated code, on-disk JSON. */
9
+ name: string;
10
+ type: string;
11
+ units?: string;
12
+ required?: boolean;
13
+ source?: string;
14
+ /** Pretty label rendered by the form. Falls back to `name`. Units
15
+ * are appended automatically; don't pre-format `[mm]` into label. */
16
+ label?: string;
17
+ /** Long-form guidance surfaced as a hover tooltip on an info icon. */
18
+ description?: string;
19
+ /** Seed value applied when the operator selects this test method.
20
+ * For source-bound fields the default is written to the GM tag so
21
+ * the control program sees it; for non-source fields it's stashed
22
+ * straight into stagedConfig. Operator edits override per-stage,
23
+ * but the schema default never mutates — re-selecting the method
24
+ * re-applies the default. **Authored in display units** when
25
+ * `scale` is set — the form divides by `scale` before writing to
26
+ * GM / stagedConfig so the underlying storage stays raw. */
27
+ default?: any;
28
+ /** Optional unit-conversion multiplier. Mirrors AutoCoreTagContext:
29
+ * ```
30
+ * display = raw * scale
31
+ * raw = display / scale
32
+ * ```
33
+ * Example: backend stores degrees, operator enters revolutions →
34
+ * `scale: 0.00277778`. None / 1.0 = no conversion.
35
+ *
36
+ * Storage stays raw — the form scales only on input and display.
37
+ * Cycle and results values are scaled by the corresponding paths
38
+ * in TestDataView; the server scales CSV exports too. */
39
+ scale?: number;
40
+ /** Optional inclusive bounds (display units, same convention as `default`
41
+ * and `scale`) for the operator's numeric entry. The numeric input
42
+ * rejects values outside `[min, max]`; non-numeric fields ignore them. */
43
+ min?: number;
44
+ max?: number;
45
+ /** Optional fixed set of choices. When present, the field renders
46
+ * as a dropdown and the operator must pick one of the declared
47
+ * values rather than typing freely. Each entry is either a bare
48
+ * scalar (label === value) or an explicit `{ label, value }` pair
49
+ * when the displayed text should differ from the stored value.
50
+ * Works with any `type`; like `default`, values are authored in
51
+ * display units when `scale` is set. */
52
+ options?: Array<string | number | boolean | {
53
+ label?: string;
54
+ value: string | number | boolean;
55
+ }>;
56
+ /** Operator-editable after recording. Meaningful on `cycle_fields`;
57
+ * `cycle_config_fields` are always editable (they're annotation, not
58
+ * measurement) and don't need the flag. */
59
+ editable?: boolean;
60
+ /** `cycle_config_fields` only: clear this entry once a row has recorded
61
+ * it, so the next row can't silently inherit a stale annotation. Fires
62
+ * at the method's `cycle_config_scope` boundary. */
63
+ autoclear?: boolean;
64
+ }
65
+ /**
66
+ * Which boundary an operator annotates `cycle_config_fields` at. Mirrors
67
+ * the Rust `CycleConfigScope`.
68
+ *
69
+ * `'run'` one latch per Start — the same values stamp every cycle of
70
+ * the run and clear when it closes. Default, and the only
71
+ * correct choice for a machine that records many cycles from
72
+ * one Start.
73
+ * `'cycle'` one latch per cycle — values clear after each recorded row
74
+ * and the gate re-arms, so the operator annotates every one.
75
+ */
76
+ export type CycleConfigScope = 'run' | 'cycle';
77
+ /**
78
+ * Convention: `display = raw * scale`, `raw = display / scale`. Matches
79
+ * AutoCoreTagContext. Default scale = 1.0 (no conversion). Non-numeric
80
+ * values (string, null, undefined, NaN) pass through unchanged — the
81
+ * forms share one change handler across fields of every type.
82
+ *
83
+ * Storage (config map, GM, on-disk JSON) always holds the raw value. Only
84
+ * the inputs the operator looks at and the cells in TestDataView use the
85
+ * display value, so scales can change in project.json without
86
+ * invalidating historical records.
87
+ */
88
+ export declare const rawToDisplay: (raw: any, scale: number | undefined) => any;
89
+ export declare const displayToRaw: (display: any, scale: number | undefined) => any;
90
+ /** Field label with `[units]` appended when declared. */
91
+ export declare const labelOf: (f: TestFieldDef) => string;
92
+ export declare const hasDescription: (f: TestFieldDef) => boolean;
93
+ /**
94
+ * "Not entered." Mirrors the server's `cycle_config_value_is_empty`
95
+ * (autocore-tis `config.rs`) so the HMI gate and the GM gate can never
96
+ * disagree about whether a field is filled in: absent, null, or an
97
+ * empty/whitespace string. Numeric zero and `false` are entries.
98
+ */
99
+ export declare const fieldValueIsEmpty: (v: any) => boolean;
100
+ /**
101
+ * Range check for a numeric field's stored RAW value against its declared
102
+ * `min`/`max` (authored in DISPLAY units). Returns a short human-readable
103
+ * reason ("must be ≥ 5") when out of range, or null when in range / not
104
+ * applicable (empty value, no bounds, or non-numeric).
105
+ */
106
+ export declare const rangeIssue: (f: TestFieldDef, raw: any) => string | null;
107
+ /**
108
+ * The single validity rule for an operator-entered field: required-and-empty,
109
+ * or out of range. Returns a human-readable reason, or null when the value
110
+ * is acceptable. Both forms build their issue lists and their per-field red
111
+ * markers from this, so the summary dialog and the field icons always agree.
112
+ */
113
+ export declare const fieldIssue: (f: TestFieldDef, raw: any) => string | null;
114
+ export declare const fieldIsValid: (f: TestFieldDef, raw: any) => boolean;
115
+ /**
116
+ * Normalise a field's `options` (bare scalars and/or `{label, value}`
117
+ * pairs) into the `{ label, value }[]` shape PrimeReact's Dropdown wants.
118
+ * Bare scalars use their stringified form as the label.
119
+ */
120
+ export declare const normalizeOptions: (opts: TestFieldDef["options"]) => {
121
+ label: string;
122
+ value: string | number | boolean;
123
+ }[];
124
+ export interface TestFieldRowProps {
125
+ field: TestFieldDef;
126
+ /** Stored RAW value. */
127
+ value: any;
128
+ /** Receives the RAW value (the row converts from display for you). */
129
+ onChange: (raw: any) => void;
130
+ /** Marks the control invalid. Defaults to `fieldIsValid(field, value)`. */
131
+ valid?: boolean;
132
+ /** Read-only rendering — used while a cycle is in flight and its
133
+ * annotation is already latched. */
134
+ disabled?: boolean;
135
+ /**
136
+ * Replaces the schema-derived input for this field. Used by
137
+ * <TestSetupForm> for config fields an AMS `asset_ref` claims, where
138
+ * the picker is sourced from the asset registry rather than the field
139
+ * declaration.
140
+ */
141
+ control?: React.ReactNode;
142
+ /** Opens the host form's shared info dialog. When omitted, fields with
143
+ * a `description` render no info affordance. */
144
+ onInfo?: (field: TestFieldDef) => void;
145
+ }
146
+ /**
147
+ * One row of a 4-column `ac-form-grid`: label, control, info button,
148
+ * validity icon. Returns a Fragment, so the caller owns the grid.
149
+ */
150
+ export declare const TestFieldRow: React.FC<TestFieldRowProps>;
151
+ //# sourceMappingURL=TestFieldRow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TestFieldRow.d.ts","sourceRoot":"","sources":["../../../src/components/tis/TestFieldRow.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React from"react";import{Button}from"primereact/button";import{Dropdown}from"primereact/dropdown";import{ValueInput}from"../ValueInput";import{TextInput}from"../TextInput";export const rawToDisplay=(e,l)=>l&&1!==l&&"number"==typeof e&&Number.isFinite(e)?e*l:e;export const displayToRaw=(e,l)=>l&&1!==l&&"number"==typeof e&&Number.isFinite(e)?e/l:e;export const labelOf=e=>{const l=e.label&&e.label.length>0?e.label:e.name;return e.units?`${l} [${e.units}]`:l};export const hasDescription=e=>"string"==typeof e.description&&e.description.length>0;export const fieldValueIsEmpty=e=>null==e||"string"==typeof e&&""===e.trim();export const rangeIssue=(e,l)=>{if(fieldValueIsEmpty(l)||""===l)return null;if(null==e.min&&null==e.max)return null;const n=Number(rawToDisplay(Number(l),e.scale));if(!Number.isFinite(n))return null;const a=null!=e.min&&null!=e.max?Math.min(e.min,e.max):e.min,t=null!=e.min&&null!=e.max?Math.max(e.min,e.max):e.max;return null!=a&&n<a?`must be ≥ ${a}`:null!=t&&n>t?`must be ≤ ${t}`:null};export const fieldIssue=(e,l)=>e.required&&fieldValueIsEmpty(l)?"is required":rangeIssue(e,l);export const fieldIsValid=(e,l)=>null===fieldIssue(e,l);export const normalizeOptions=e=>(e??[]).map(e=>null!==e&&"object"==typeof e?{label:String(e.label??e.value),value:e.value}:{label:String(e),value:e});export const TestFieldRow=({field:e,value:l,onChange:n,valid:a,disabled:t,control:i,onInfo:r})=>{const s=a??fieldIsValid(e,l),o=!i&&Array.isArray(e.options)&&e.options.length>0?normalizeOptions(e.options):null,u=!i&&!o&&"string"!==e.type&&"bool"!==e.type,p=i??(o?_jsx(Dropdown,{value:l??null,options:o,onChange:e=>n(e.value),placeholder:`Select ${e.label??e.name}…`,className:"ac-dropdown-clearable"+(s?"":" p-invalid"),showClear:!e.required,disabled:t}):u?_jsx(ValueInput,{label:void 0,value:null!=l?Number(rawToDisplay(Number(l),e.scale)):null,min:e.min,max:e.max,onValueChanged:l=>n(displayToRaw(l,e.scale)),className:s?"":"p-invalid",disabled:t}):_jsx(TextInput,{label:void 0,value:null!=l?String(l):"",onValueChanged:e=>n(e),className:s?"":"p-invalid",disabled:t}));return _jsxs(React.Fragment,{children:[_jsx("span",{className:"ac-form-label",children:labelOf(e)}),p,r&&hasDescription(e)?_jsx(Button,{icon:"pi pi-info-circle",text:!0,rounded:!0,"aria-label":`About ${labelOf(e)}`,onClick:()=>r(e)}):_jsx("span",{"aria-hidden":"true"}),_jsx("span",{style:{color:s?"var(--green-500)":"var(--red-500)",display:"flex",alignItems:"center"},children:_jsx("i",{className:s?"pi pi-check":"pi pi-times"})})]})};