@adcops/autocore-react 3.5.7 → 3.5.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/forms/useEditDraft.d.ts +49 -0
- package/dist/components/forms/useEditDraft.d.ts.map +1 -0
- package/dist/components/forms/useEditDraft.js +1 -0
- package/dist/components/index.d.ts +6 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +1 -1
- package/dist/components/tis/TestDataView.d.ts +8 -0
- package/dist/components/tis/TestDataView.d.ts.map +1 -1
- package/dist/components/tis/TestDataView.js +1 -1
- package/dist/components/tis/TestRawDataView.d.ts.map +1 -1
- package/dist/components/tis/TestRawDataView.js +1 -1
- package/dist/components/tis/chartViews.d.ts +57 -0
- package/dist/components/tis/chartViews.d.ts.map +1 -0
- package/dist/components/tis/chartViews.js +1 -0
- package/dist/components/tis-editor/TisConfigEditor.css +11 -0
- package/dist/components/tis-editor/TisConfigEditor.d.ts.map +1 -1
- package/dist/components/tis-editor/TisConfigEditor.js +1 -1
- package/dist/components/tis-editor/editor/AuthoringContext.d.ts +37 -0
- package/dist/components/tis-editor/editor/AuthoringContext.d.ts.map +1 -0
- package/dist/components/tis-editor/editor/AuthoringContext.js +1 -0
- package/dist/components/tis-editor/editor/ChartViewDialog.d.ts +11 -0
- package/dist/components/tis-editor/editor/ChartViewDialog.d.ts.map +1 -1
- package/dist/components/tis-editor/editor/ChartViewDialog.js +1 -1
- package/dist/components/tis-editor/editor/FieldArrayEditor.d.ts.map +1 -1
- package/dist/components/tis-editor/editor/FieldArrayEditor.js +1 -1
- package/dist/components/tis-editor/editor/RawDataEditor.d.ts.map +1 -1
- package/dist/components/tis-editor/editor/RawDataEditor.js +1 -1
- package/dist/components/tis-editor/editor/TestFieldDialog.d.ts +7 -0
- package/dist/components/tis-editor/editor/TestFieldDialog.d.ts.map +1 -1
- package/dist/components/tis-editor/editor/TestFieldDialog.js +1 -1
- package/dist/components/tis-editor/editor/ViewsEditor.d.ts.map +1 -1
- package/dist/components/tis-editor/editor/ViewsEditor.js +1 -1
- package/dist/components/tis-editor/types.d.ts +6 -0
- package/dist/components/tis-editor/types.d.ts.map +1 -1
- package/dist/components/varpick/VariableInput.d.ts +41 -0
- package/dist/components/varpick/VariableInput.d.ts.map +1 -0
- package/dist/components/varpick/VariableInput.js +1 -0
- package/dist/components/varpick/VariablePicker.d.ts +45 -0
- package/dist/components/varpick/VariablePicker.d.ts.map +1 -0
- package/dist/components/varpick/VariablePicker.js +1 -0
- package/dist/components/varpick/index.d.ts +16 -0
- package/dist/components/varpick/index.d.ts.map +1 -0
- package/dist/components/varpick/index.js +1 -0
- package/dist/components/varpick/tisCatalogs.d.ts +85 -0
- package/dist/components/varpick/tisCatalogs.d.ts.map +1 -0
- package/dist/components/varpick/tisCatalogs.js +1 -0
- package/dist/components/varpick/varpick.css +167 -0
- package/dist/core/AutoCoreTagContext.d.ts.map +1 -1
- package/dist/core/AutoCoreTagContext.js +1 -1
- package/dist/core/AutoCoreTagTypes.d.ts +13 -0
- package/dist/core/AutoCoreTagTypes.d.ts.map +1 -1
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -1
- package/dist/hooks/useGmVariables.d.ts +57 -0
- package/dist/hooks/useGmVariables.d.ts.map +1 -0
- package/dist/hooks/useGmVariables.js +1 -0
- package/dist/hooks/useSequenceProducers.d.ts +38 -0
- package/dist/hooks/useSequenceProducers.d.ts.map +1 -0
- package/dist/hooks/useSequenceProducers.js +1 -0
- package/package.json +7 -2
- package/src/components/forms/useEditDraft.ts +0 -0
- package/src/components/index.ts +20 -0
- package/src/components/tis/TestDataView.tsx +16 -10
- package/src/components/tis/TestRawDataView.tsx +6 -7
- package/src/components/tis/chartViews.ts +104 -0
- package/src/components/tis-editor/TisConfigEditor.css +11 -0
- package/src/components/tis-editor/TisConfigEditor.tsx +31 -0
- package/src/components/tis-editor/editor/AuthoringContext.tsx +43 -0
- package/src/components/tis-editor/editor/ChartViewDialog.tsx +48 -17
- package/src/components/tis-editor/editor/FieldArrayEditor.tsx +1 -0
- package/src/components/tis-editor/editor/RawDataEditor.tsx +7 -2
- package/src/components/tis-editor/editor/TestFieldDialog.tsx +90 -23
- package/src/components/tis-editor/editor/ViewsEditor.tsx +56 -5
- package/src/components/tis-editor/types.ts +6 -0
- package/src/components/varpick/VariableInput.tsx +126 -0
- package/src/components/varpick/VariablePicker.tsx +168 -0
- package/src/components/varpick/index.ts +22 -0
- package/src/components/varpick/tisCatalogs.ts +235 -0
- package/src/components/varpick/varpick.css +167 -0
- package/src/core/AutoCoreTagContext.tsx +3 -1
- package/src/core/AutoCoreTagTypes.ts +14 -0
- package/src/hooks/index.ts +11 -0
- package/src/hooks/useGmVariables.ts +142 -0
- package/src/hooks/useSequenceProducers.ts +104 -0
- package/tools/tests/dist/TestFieldDialog-C4mKVh7q.js +32817 -0
- package/tools/tests/dist/autocore-react.css +257 -0
- package/tools/tests/dist/tis-editor.entry.js +9295 -0
- package/tools/tests/dist/varpick.entry.js +113 -0
- package/tools/tests/live-server.probe.mjs +172 -0
- package/tools/tests/tis-editor.entry.tsx +46 -0
- package/tools/tests/tis-editor.test.mjs +133 -0
- package/tools/tests/varpick.entry.tsx +81 -0
- package/tools/tests/varpick.test.mjs +208 -0
- package/tools/tests/vite.config.mjs +35 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useEditDraft — draft state for a dialog that edits one record.
|
|
3
|
+
*
|
|
4
|
+
* A dialog seeds its draft from the record it was opened on, then owns that
|
|
5
|
+
* draft until it closes. Written the obvious way — a `useEffect` keyed on the
|
|
6
|
+
* `initial` prop — the reseed fires whenever the prop's OBJECT IDENTITY
|
|
7
|
+
* changes, which is not the same event as "the operator opened a different
|
|
8
|
+
* record":
|
|
9
|
+
*
|
|
10
|
+
* - a parent that builds `initial={{ id, record }}` inline hands over a new
|
|
11
|
+
* object on every render of its own, and
|
|
12
|
+
* - these editors sit under `AutoCoreTagProvider` / `TisProvider`, whose
|
|
13
|
+
* consumers re-render on live tag and broadcast traffic — many times a
|
|
14
|
+
* second on a running machine.
|
|
15
|
+
*
|
|
16
|
+
* Together those reseeded the draft within a frame of every keystroke, so the
|
|
17
|
+
* TIS chart-view dialog was effectively read-only: type a character, watch the
|
|
18
|
+
* original value come back. (gen4_ac, 2026-08-29.)
|
|
19
|
+
*
|
|
20
|
+
* The reseed here is keyed on an explicit EDIT TOKEN instead — closed, or open
|
|
21
|
+
* on a named record — so upstream identity churn cannot reach it. Two
|
|
22
|
+
* transitions reseed, and nothing else does:
|
|
23
|
+
*
|
|
24
|
+
* closed → open:<key> dialog opened on a record → seed
|
|
25
|
+
* open:<key A> → open:<key B> swapped to another record → seed
|
|
26
|
+
* open:<key> → closed dialog closed → draft kept as-is
|
|
27
|
+
*/
|
|
28
|
+
import type { Dispatch, SetStateAction } from 'react';
|
|
29
|
+
export interface EditDraft<T> {
|
|
30
|
+
/** The working copy. Edits survive any re-render of the tree above. */
|
|
31
|
+
draft: T;
|
|
32
|
+
setDraft: Dispatch<SetStateAction<T>>;
|
|
33
|
+
/**
|
|
34
|
+
* The current edit token. Stable for as long as one record stays open, so
|
|
35
|
+
* it is safe as a `useEffect` dependency for companion state that has to
|
|
36
|
+
* be cleared alongside a reseed (a validation error, say).
|
|
37
|
+
*/
|
|
38
|
+
token: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* @param visible Whether the dialog is open.
|
|
42
|
+
* @param editKey Stable identity of the record being edited — a view id, a
|
|
43
|
+
* field name. Empty string for "new record".
|
|
44
|
+
* @param seed Builds the initial draft. Called only on a reseed, so it may
|
|
45
|
+
* read the current props directly.
|
|
46
|
+
*/
|
|
47
|
+
export declare function useEditDraft<T>(visible: boolean, editKey: string, seed: () => T): EditDraft<T>;
|
|
48
|
+
export default useEditDraft;
|
|
49
|
+
//# sourceMappingURL=useEditDraft.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useEditDraft.d.ts","sourceRoot":"","sources":["../../../src/components/forms/useEditDraft.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAKtD,MAAM,WAAW,SAAS,CAAC,CAAC;IACxB,uEAAuE;IACvE,KAAK,EAAE,CAAC,CAAC;IACT,QAAQ,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;IACtC;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAC1B,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,CAAC,GACd,SAAS,CAAC,CAAC,CAAC,CAed;AAED,eAAe,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{useState}from"react";const CLOSED="\0closed";export function useEditDraft(t,e,r){const o=t?`open:${e}`:CLOSED,[a,s]=useState(r),[u,f]=useState(o);return u!==o&&(f(o),t&&s(r())),{draft:a,setDraft:s,token:o}}export default useEditDraft;
|
|
@@ -6,6 +6,8 @@ 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 { orderedViews, renumberViews, moveView } from './tis/chartViews';
|
|
10
|
+
export type { NamedView, OrderableView } from './tis/chartViews';
|
|
9
11
|
export { TestFieldRow } from './tis/TestFieldRow';
|
|
10
12
|
export type { TestFieldRowProps, CycleConfigScope } from './tis/TestFieldRow';
|
|
11
13
|
export { CycleConfigForm, cycleConfigSummary } from './tis/CycleConfigForm';
|
|
@@ -45,4 +47,8 @@ export { NetworkPanel } from './network/NetworkPanel';
|
|
|
45
47
|
export type { NetworkPanelProps } from './network/NetworkPanel';
|
|
46
48
|
export { StagedChangeBanner } from './network/StagedChangeBanner';
|
|
47
49
|
export type { StagedChangeBannerProps } from './network/StagedChangeBanner';
|
|
50
|
+
export { VariablePicker, VariableInput } from './varpick';
|
|
51
|
+
export type { VariablePickerProps, VariableInputProps } from './varpick';
|
|
52
|
+
export { boundCatalog, chartFieldCatalog, configSourceCatalog, cycleSourceCatalog, rawSourceCatalog, } from './varpick';
|
|
53
|
+
export type { TisCatalogContext } from './varpick';
|
|
48
54
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"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"}
|
package/dist/components/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
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,DEFAULT_X_DECIMALS}from"./tis/TestDataView";export{UnitSystemSelector}from"./UnitSystemSelector";export{UnitsEditor}from"./UnitsEditor";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{orderedViews,renumberViews,moveView}from"./tis/chartViews";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,DEFAULT_X_DECIMALS}from"./tis/TestDataView";export{UnitSystemSelector}from"./UnitSystemSelector";export{UnitsEditor}from"./UnitsEditor";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";export{VariablePicker,VariableInput}from"./varpick";export{boundCatalog,chartFieldCatalog,configSourceCatalog,cycleSourceCatalog,rawSourceCatalog}from"./varpick";
|
|
@@ -121,6 +121,14 @@ export interface ChartView {
|
|
|
121
121
|
* table, CSV export and every calculation still see the full value.
|
|
122
122
|
*/
|
|
123
123
|
x_decimals?: number;
|
|
124
|
+
/**
|
|
125
|
+
* Position in the view picker, ascending — the view with the lowest
|
|
126
|
+
* `order` is the one this panel opens on. Written by the TIS editor's
|
|
127
|
+
* Move up / Move down. See `chartViews.ts`: the keys of `views` arrive
|
|
128
|
+
* sorted by id, so the order an author chose has to be carried
|
|
129
|
+
* explicitly.
|
|
130
|
+
*/
|
|
131
|
+
order?: number;
|
|
124
132
|
/**
|
|
125
133
|
* Optional shaded X-range bands drawn over the plot, declared per view
|
|
126
134
|
* in project.json (static). These are drawn on every cycle.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TestDataView.d.ts","sourceRoot":"","sources":["../../../src/components/tis/TestDataView.tsx"],"names":[],"mappings":"AA0BA,OAAO,KAAwE,MAAM,OAAO,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{AutoCoreTagContext}from"../../core/AutoCoreTagContext";import{formatScaled}from"../../core/formatScaled";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,n=e.methodId??t.selection.methodId,a=e.runId??t.selection.runId,o=e.schema??(n?t.schemas[n]:void 0),{throttleMs:l=100,cycleTableHeight:i="400px",chartHeight:s="320px"}=e,{invoke:c,subscribe:d,unsubscribe:u}=useContext(EventEmitterContext),{scales:m}=useContext(AutoCoreTagContext),[p,y]=useState(null),[f,h]=useState([]),[g,_]=useState({}),[x,b]=useState({}),[j,v]=useState(!1),[w,C]=useState(!1),S=useCallback(async(e,t,o)=>{const l=e?.cycle_index;if(r&&n&&a&&l)try{const e=await c("tis.update_cycle",MessageType.Request,{project_id:r,method_id:n,run_id:a,cycle_index:l,fields:{[t]:o}});if(!1===e?.success)return;h(e=>e.map(e=>e?.cycle_index===l?{...e,[t]:o}:e))}catch(e){}},[c,r,n,a]),T=useRef(null),[R,O]=useState(null),[A,D]=useState(null),[M,E]=useState(!1),[L,I]=useState(null),[N,F]=useState(null),[k,q]=useState(!1),[H,P]=useState([]),[V,z]=useState(null),$=useMemo(()=>{const e=[];for(const[t,r]of Object.entries(o?.views??{}))e.push({name:t,view:r});return e},[o]),[B,G]=useState($.length>0?$[0].name:null);useEffect(()=>{if(0===$.length)return;null!==B&&$.some(e=>e.name===B)||G($[0].name)},[$,B]);const W=$.find(e=>e.name===B)?.view,U="raw_trace"===W?.type,J=useRef([]),X=useRef(null),Y=useRef(null),Z=()=>{Y.current||(Y.current=setTimeout(()=>{if(Y.current=null,J.current.length>0){const e=J.current;J.current=[],h(t=>[...e.slice().reverse(),...t])}X.current&&(_(X.current),X.current=null)},l))};useEffect(()=>{if(!r||!n||!a)return y(null),h([]),void _({});let e=!1;return(async()=>{try{const t=await c("tis.read_test",MessageType.Request,{project_id:r,method_id:n,run_id:a});!e&&t?.success&&(y(t.data),_(t.data.results??{}));const o=await c("tis.read_cycles",MessageType.Request,{project_id:r,method_id:n,run_id:a,offset:0,limit:200,order:"desc"});!e&&o?.success&&h(o.data.cycles??[])}catch(e){}})(),()=>{e=!0}},[r,n,a,c]),useEffect(()=>{const e=e=>e?.project_id===r&&e?.method_id===n&&e?.run_id===a,t=d("tis.cycle_added",t=>{e(t)&&t.cycle&&(J.current.push(t.cycle),Z())}),o=d("tis.results_updated",t=>{e(t)&&(X.current=t.results??{},Z())});return()=>{u(t),u(o),Y.current&&(clearTimeout(Y.current),Y.current=null)}},[r,n,a,l]);const K="string"==typeof p?.sample_id&&p.sample_id?p.sample_id:"string"==typeof p?.config?.sample_id?p.config.sample_id:"";useEffect(()=>{if(!r||!n||!K)return void b({});let e=!1;const t=async()=>{try{const t=await c("tis.sample_summary",MessageType.Request,{project_id:r,method_id:n,sample_id:K,run_id:a});!e&&t?.success&&b(t.data?.summary??{})}catch(e){}};t();const o=[d("tis.sample_summary_updated",e=>{e?.project_id===r&&e?.method_id===n&&e?.sample_id===K&&t()}),d("tis.cycle_added",e=>{e?.project_id===r&&e?.method_id===n&&t()})];return()=>{e=!0,o.forEach(u)}},[r,n,K,a,c,d,u]);const Q=useRawCycleData({projectId:r,methodId:n,runId:a,blobName:o?.raw_data?.blob_name??"trace",source:W?.source??"raw",enabled:U}),ee=useMemo(()=>{if(!W)return null;if("cycle_scatter"===W.type){const e=W.x.field;if(!e)return null;const t=[...f].reverse(),r=m?.[quantityOfField(o,e)??""],n=W.x_decimals??r?.precision??DEFAULT_X_DECIMALS;return{labels:t.map(t=>formatAxisTick(toDisplayValue(t[e],r),n)),datasets:W.y.map((e,r)=>({label:e.label??e.field,data:t.map(t=>toDisplayValue(t[e.field],m?.[quantityOfField(o,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=m?.[quantityOfColumn(o,e)??""],r=Q.raw[e]??[],n=t?r.map(e=>toDisplayValue(e,t)):r,a=!1!==W.smooth;return{datasets:W.y.map((e,t)=>{const r=m?.[quantityOfColumn(o,e.column)??""],l=Q.raw[e.column]??[],i=r?l.map(e=>toDisplayValue(e,r)):l,s=a?smoothTraceForDisplay(n,i,W.smoothWindow):i.map((e,t)=>({x:n[t],y:e}));return{label:e.label??e.column,data:s,yAxisID:"right"===e.y_axis?"y1":"y",borderColor:palette(t),backgroundColor:palette(t),pointRadius:0,borderWidth:1.5,showLine:!0,...a?{cubicInterpolationMode:"monotone"}:{}}})}}return null},[W,f,Q.raw,m,o]),te=W?.y.some(e=>"right"===e.y_axis)??!1,re=useMemo(()=>{if(!U)return[];const e=Q.envelope,t=e?.regions??e?.context?.regions;return Array.isArray(t)?t:[]},[U,Q.envelope]),ne=useMemo(()=>[...W?.regions??[],...re],[W,re]),ae=useMemo(()=>{const e="raw_trace"===W?.type,t=t=>{const r=e?quantityOfColumn(o,t.column):quantityOfField(o,t.field);return r?m?.[r]?.label:void 0},r=e?quantityOfColumn(o,W?.x.column):quantityOfField(o,W?.x.field),n=r?m?.[r]?.label:void 0,a=W?.x.label?n?`${W.x.label} [${n}]`:W.x.label:void 0,l=W?.x_decimals??(r?m?.[r]?.precision:void 0)??DEFAULT_X_DECIMALS,i={callback(t){const r=e?t:this?.getLabelForValue?.(t)??t;return formatAxisTick(r,l)}};return{responsive:!0,maintainAspectRatio:!1,parsing:!e&&void 0,scales:{x:e?{type:"linear",ticks:i,title:{display:!!a,text:a}}:{ticks:i,title:{display:!!a,text:a}},y:{position:"left",title:{display:!0,text:axisLabel(W,"left",t)}},...te?{y1:{position:"right",grid:{drawOnChartArea:!1},title:{display:!0,text:axisLabel(W,"right",t)}}}:{}},plugins:{legend:{display:!0},zoom:{pan:{enabled:!0,mode:"xy"},zoom:{wheel:{enabled:!0},pinch:{enabled:!0},mode:"xy"}},annotation:{annotations:buildRegionAnnotations(ne)}}}},[W,te,ne,m,o]),oe=o?.raw_data?.blob_name??"trace",le=useRef(""),ie=useCallback(async()=>{if(!r||!n||!a)return[];try{const e=await c("tis.list_raw",MessageType.Request,{project_id:r,method_id:n,run_id:a});if(!e?.success)return[];const t=e.data?.cycles??[];return t.filter(e=>e?.name===oe&&"number"==typeof e?.cycle_index).map(e=>e.cycle_index).sort((e,t)=>e-t)}catch{return[]}},[r,n,a,oe,c]),se=useCallback(async e=>{if(!r||!n||!a)return;const t=`${r}|${n}|${a}|${oe}|${e??"latest"}`;if(le.current===t)return;le.current=t;const o={project_id:r,method_id:n,run_id:a,name:oe};null!=e&&(o.cycle_index=e),E(!0),D(null),O(null);try{const e=await c("tis.read_raw",MessageType.Request,o);e?.success?O(e.data??{}):D(e?.error_message??"No raw data on disk for this run.")}catch(e){D(String(e?.message??e))}finally{E(!1)}q(!0),F(null),I(null);try{const e=await c("tis.read_filtered",MessageType.Request,o);e?.success?I(e.data??{}):F(e?.error_message??"No filtered data on disk for this run.")}catch(e){F(String(e?.message??e))}finally{q(!1)}},[r,n,a,oe,c]);useEffect(()=>{le.current="",P([]),z(null)},[r,n,a,oe]);return useEffect(()=>{j&&null!=V&&se(V)},[j,V,se]),r&&n&&a&&o?_jsxs("div",{className:"vblock",style:{display:"flex",flexDirection:"column",gap:"1rem"},children:[_jsx(Header,{meta:p,config:p?.config,runId:a,projectId:r,methodId:n,canViewRaw:!!o.raw_data,onViewRaw:async()=>{v(!0);let e=H;0===e.length&&(e=await ie(),P(e));const t=e.length>0?e[e.length-1]:null,r=V??t;V!==r&&z(r),await se(r)},onShowConfig:()=>C(!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:B,options:$.map(e=>({label:e.view.title??e.name,value:e.name})),onChange:e=>G(e.value),placeholder:0===$.length?"No view defined":"Select a view",disabled:0===$.length}),_jsx("h3",{style:{margin:0},children:W?.title??""}),U&&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:()=>T.current?.resetZoom?.(),disabled:!ee,tooltip:"Reset chart zoom",tooltipOptions:{position:"left"},"aria-label":"Reset chart zoom"})]}),_jsxs("div",{style:{height:s,position:"relative"},children:[U&&Q.loading&&_jsx(ChartOverlay,{children:"Loading raw data…"}),U&&Q.error&&_jsx(ChartOverlay,{children:Q.error}),ee&&_jsx(Line,{ref:T,data:ee,options:ae})]})]}),(()=>{const e=f.length>CYCLE_VIRTUAL_THRESHOLD,t=[...(o.cycle_config_fields??[]).map(e=>toScienceColumn(e,!0,m)),...(o.cycle_fields??[]).map(e=>toScienceColumn(e,!!e.editable,m))];return _jsx(ScienceTable,{title:`Cycle Data (${f.length})`,columns:t,rows:f,indexOrder:"descending",scrollable:e,scrollHeight:e?i:void 0,emptyMessage:"No cycles yet.",onCellEdit:S})})(),(()=>{const e={...g,...x},t=Object.keys(e).length>0,r=o.results_fields??[],n=r.map(e=>toScienceColumn(e,!1,m)),a=r.some(isProjectScoped);return _jsxs(_Fragment,{children:[_jsx(ScienceTable,{title:"Results",columns:n,rows:t?[e]:[],emptyMessage:"No results yet."}),a&&_jsx("div",{style:{fontSize:"0.8rem",color:"var(--text-secondary-color)",margin:"0.25rem 0 0.75rem"},children:"* across every test of this sample in the project. All other values describe this test."})]})})(),o.raw_data&&_jsxs(Dialog,{visible:j,onHide:()=>v(!1),header:`Run Data — ${a}`,style:{width:"90vw",height:"80vh"},maximizable:!0,children:[_jsx(CyclePickerBar,{cycles:H,selected:V,onChange:z}),_jsx(RawEnvelopeHeader,{envelope:R}),_jsxs(TabView,{style:{height:"100%"},children:[_jsx(TabPanel,{header:"Raw Data",children:_jsx(DataBlobTable,{blob:unwrapEnvelope(R),loading:M,error:A,rawData:o.raw_data})}),_jsx(TabPanel,{header:"Filtered Data",children:_jsx(DataBlobTable,{blob:unwrapEnvelope(L),loading:k,error:N,rawData:o.raw_data,emptyMessage:"Filtered data is written by post-processing — none on disk for this run yet."})})]})]}),_jsx(Dialog,{visible:w,onHide:()=>C(!1),header:"Test Configuration",style:{width:"min(640px, 90vw)"},modal:!0,children:_jsx(ConfigList,{config:p?.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:n,methodId:a,canViewRaw:o,onViewRaw:l,onShowConfig:i})=>{const s="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:[s||r,c&&_jsx(Button,{icon:"pi pi-info-circle",type:"button",rounded:!0,text:!0,onClick:i,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: ",n," · method: ",a," · run: ",r,e?.start_time&&_jsxs(_Fragment,{children:[" · started: ",new Date(e.start_time).toLocaleString()]})]})]}),o&&_jsx(Button,{icon:"pi pi-table",label:"View Raw Data",onClick:l,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,n=e.context;if(null==t&&!r&&!n)return null;const a=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:a(r)}),n&&_jsx("div",{style:{marginTop:"0.25rem"},children:a(n)})]})},DataBlobTable=({blob:e,loading:t,error:r,rawData:n,emptyMessage:a})=>{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:a??r});if(!e||"object"!=typeof e)return _jsx("div",{style:{padding:"1rem",color:"var(--text-secondary-color)"},children:"No data."});const o=Object.keys(n.columns??{}),l=Object.keys(e).filter(t=>Array.isArray(e[t])),i=[];for(const t of o)Array.isArray(e[t])&&i.push(t);for(const e of l)i.includes(e)||i.push(e);if(0===i.length)return _jsx("div",{style:{padding:"1rem",color:"var(--text-secondary-color)"},children:a??"No columnar data in this blob."});const s=i.reduce((t,r)=>Math.min(t,e[r].length),Number.POSITIVE_INFINITY),c=Number.isFinite(s)?s:0,d=Array.from({length:c},(t,r)=>{const n={__i:r};for(const t of i)n[t]=e[t][r];return n}),u=e=>{const t=n.units?.[e];return t?`${e} [${t}]`:e};return _jsxs(DataTable,{value:d,scrollable:!0,scrollHeight:"60vh",virtualScrollerOptions:{itemSize:32},emptyMessage:a??"No data.",size:"small",stripedRows:!0,children:[_jsx(Column,{field:"__i",header:"#",style:{width:"5rem",textAlign:"right"},bodyStyle:{fontVariantNumeric:"tabular-nums",textAlign:"right"}}),i.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 n=e;for(let a=e+1;a<t;a++)Math.abs(r[a][e])>Math.abs(r[n][e])&&(n=a);if(Math.abs(r[n][e])<1e-12)return null;[r[e],r[n]]=[r[n],r[e]];const a=r[e][e];for(let n=0;n<2*t;n++)r[e][n]/=a;for(let n=0;n<t;n++){if(n===e)continue;const a=r[n][e];if(0!==a)for(let o=0;o<2*t;o++)r[n][o]-=a*r[e][o]}}return r.map(e=>e.slice(t))}function sgWeights(e,t){const r=2*e+1,n=Math.min(t,r-1),a=[];for(let t=-e;t<=e;t++){const e=[];let r=1;for(let a=0;a<=n;a++)e.push(r),r*=t;a.push(e)}const o=n+1,l=Array.from({length:o},()=>new Array(o).fill(0));for(let e=0;e<o;e++)for(let t=0;t<o;t++){let n=0;for(let o=0;o<r;o++)n+=a[o][e]*a[o][t];l[e][t]=n}const i=invertMatrix(l);if(!i)return new Array(r).fill(1/r);const s=new Array(r);for(let e=0;e<r;e++){let t=0;for(let r=0;r<o;r++)t+=i[0][r]*a[e][r];s[e]=t}return s}function savitzkyGolay(e,t){const r=e.length;if(0===r||t<1)return e.slice();const n=new Map,a=e=>{let t=n.get(e);return t||(t=sgWeights(e,3),n.set(e,t)),t},o=new Array(r);for(let n=0;n<r;n++){const l=Math.min(t,n,r-1-n);if(l<1){o[n]=e[n];continue}const i=a(l);let s=0;for(let t=-l;t<=l;t++)s+=i[t+l]*e[n+t];o[n]=s}return o}function smoothTraceForDisplay(e,t,r){const n=Math.min(e.length,t.length);if(0===n)return[];const a=r&&r>1?Math.max(1,Math.floor((Math.min(r,n)-1)/2)):Math.max(2,Math.min(40,Math.round(n/250))),o=savitzkyGolay(t.slice(0,n),a),l=Math.max(1,Math.ceil(n/SMOOTH_TARGET_POINTS)),i=[];for(let t=0;t<n;t+=l)i.push({x:e[t],y:o[t]});return(n-1)%l!=0&&i.push({x:e[n-1],y:o[n-1]}),i}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 n=!!e.borderColor;t[`region-${r}`]={type:"box",xScaleID:"x",xMin:e.xMin,xMax:e.xMax,backgroundColor:e.color??DEFAULT_REGION_FILL,borderColor:n?e.borderColor:"transparent",borderWidth:n?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});export const DEFAULT_X_DECIMALS=2;const formatAxisTick=(e,t)=>{const r="number"==typeof e?e:Number(e);return Number.isFinite(r)?Number.parseFloat(r.toFixed(t)).toString():null==e?"":String(e)},quantityOfField=(e,t)=>{if(e&&t)for(const r of[e.cycle_config_fields,e.cycle_fields,e.results_fields]){const e=(r??[]).find(e=>e.name===t);if(e?.quantity)return e.quantity}},quantityOfColumn=(e,t)=>{if(e&&t)return e.raw_data?.columns?.[t]?.quantity},toDisplayValue=(e,t)=>t&&"number"==typeof e&&Number.isFinite(e)?e*t.scale+(t.offset??0):e,seriesLabel=e=>e.label??e.field??e.column??"",axisLabel=(e,t,r)=>{const n=e?.y.filter(e=>"right"===e.y_axis==("right"===t))??[],a=n.map(seriesLabel).join(" / "),o=Array.from(new Set(n.map(r).filter(Boolean)));return 1===o.length?`${a} [${o[0]}]`:a},isProjectScoped=e=>"project"===e.aggregate?.scope,toScienceColumn=(e,t=!1,r)=>{const n=e.quantity?r?.[e.quantity]:void 0;return{field:e.name,label:(e.label&&e.label.length>0?e.label:e.name)+(isProjectScoped(e)?" *":""),units:n?n.label:e.units,editable:t,body:t=>formatCell(t[e.name],e.type,e.scale,n)}},formatCell=(e,t,r,n)=>null==e?"":n&&"number"==typeof e&&Number.isFinite(e)?formatScaled(e*n.scale+(n.offset??0),n):(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{AutoCoreTagContext}from"../../core/AutoCoreTagContext";import{formatScaled}from"../../core/formatScaled";import{useRawCycleData}from"./useRawCycleData";import{orderedViews}from"./chartViews";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,o=e.schema??(a?t.schemas[a]:void 0),{throttleMs:l=100,cycleTableHeight:i="400px",chartHeight:s="320px"}=e,{invoke:c,subscribe:d,unsubscribe:u}=useContext(EventEmitterContext),{scales:m}=useContext(AutoCoreTagContext),[p,y]=useState(null),[f,h]=useState([]),[g,_]=useState({}),[x,b]=useState({}),[j,v]=useState(!1),[w,C]=useState(!1),S=useCallback(async(e,t,o)=>{const l=e?.cycle_index;if(r&&a&&n&&l)try{const e=await c("tis.update_cycle",MessageType.Request,{project_id:r,method_id:a,run_id:n,cycle_index:l,fields:{[t]:o}});if(!1===e?.success)return;h(e=>e.map(e=>e?.cycle_index===l?{...e,[t]:o}:e))}catch(e){}},[c,r,a,n]),T=useRef(null),[R,O]=useState(null),[A,D]=useState(null),[M,E]=useState(!1),[L,I]=useState(null),[N,F]=useState(null),[k,q]=useState(!1),[V,H]=useState([]),[P,z]=useState(null),$=useMemo(()=>orderedViews(o?.views),[o]),[B,G]=useState($.length>0?$[0].name:null);useEffect(()=>{if(0===$.length)return;null!==B&&$.some(e=>e.name===B)||G($[0].name)},[$,B]);const W=$.find(e=>e.name===B)?.view,U="raw_trace"===W?.type,J=useRef([]),X=useRef(null),Y=useRef(null),Z=()=>{Y.current||(Y.current=setTimeout(()=>{if(Y.current=null,J.current.length>0){const e=J.current;J.current=[],h(t=>[...e.slice().reverse(),...t])}X.current&&(_(X.current),X.current=null)},l))};useEffect(()=>{if(!r||!a||!n)return y(null),h([]),void _({});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&&(y(t.data),_(t.data.results??{}));const o=await c("tis.read_cycles",MessageType.Request,{project_id:r,method_id:a,run_id:n,offset:0,limit:200,order:"desc"});!e&&o?.success&&h(o.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&&(J.current.push(t.cycle),Z())}),o=d("tis.results_updated",t=>{e(t)&&(X.current=t.results??{},Z())});return()=>{u(t),u(o),Y.current&&(clearTimeout(Y.current),Y.current=null)}},[r,a,n,l]);const K="string"==typeof p?.sample_id&&p.sample_id?p.sample_id:"string"==typeof p?.config?.sample_id?p.config.sample_id:"";useEffect(()=>{if(!r||!a||!K)return void b({});let e=!1;const t=async()=>{try{const t=await c("tis.sample_summary",MessageType.Request,{project_id:r,method_id:a,sample_id:K,run_id:n});!e&&t?.success&&b(t.data?.summary??{})}catch(e){}};t();const o=[d("tis.sample_summary_updated",e=>{e?.project_id===r&&e?.method_id===a&&e?.sample_id===K&&t()}),d("tis.cycle_added",e=>{e?.project_id===r&&e?.method_id===a&&t()})];return()=>{e=!0,o.forEach(u)}},[r,a,K,n,c,d,u]);const Q=useRawCycleData({projectId:r,methodId:a,runId:n,blobName:o?.raw_data?.blob_name??"trace",source:W?.source??"raw",enabled:U}),ee=useMemo(()=>{if(!W)return null;if("cycle_scatter"===W.type){const e=W.x.field;if(!e)return null;const t=[...f].reverse(),r=m?.[quantityOfField(o,e)??""],a=W.x_decimals??r?.precision??DEFAULT_X_DECIMALS;return{labels:t.map(t=>formatAxisTick(toDisplayValue(t[e],r),a)),datasets:W.y.map((e,r)=>({label:e.label??e.field,data:t.map(t=>toDisplayValue(t[e.field],m?.[quantityOfField(o,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=m?.[quantityOfColumn(o,e)??""],r=Q.raw[e]??[],a=t?r.map(e=>toDisplayValue(e,t)):r,n=!1!==W.smooth;return{datasets:W.y.map((e,t)=>{const r=m?.[quantityOfColumn(o,e.column)??""],l=Q.raw[e.column]??[],i=r?l.map(e=>toDisplayValue(e,r)):l,s=n?smoothTraceForDisplay(a,i,W.smoothWindow):i.map((e,t)=>({x:a[t],y:e}));return{label:e.label??e.column,data:s,yAxisID:"right"===e.y_axis?"y1":"y",borderColor:palette(t),backgroundColor:palette(t),pointRadius:0,borderWidth:1.5,showLine:!0,...n?{cubicInterpolationMode:"monotone"}:{}}})}}return null},[W,f,Q.raw,m,o]),te=W?.y.some(e=>"right"===e.y_axis)??!1,re=useMemo(()=>{if(!U)return[];const e=Q.envelope,t=e?.regions??e?.context?.regions;return Array.isArray(t)?t:[]},[U,Q.envelope]),ae=useMemo(()=>[...W?.regions??[],...re],[W,re]),ne=useMemo(()=>{const e="raw_trace"===W?.type,t=t=>{const r=e?quantityOfColumn(o,t.column):quantityOfField(o,t.field);return r?m?.[r]?.label:void 0},r=e?quantityOfColumn(o,W?.x.column):quantityOfField(o,W?.x.field),a=r?m?.[r]?.label:void 0,n=W?.x.label?a?`${W.x.label} [${a}]`:W.x.label:void 0,l=W?.x_decimals??(r?m?.[r]?.precision:void 0)??DEFAULT_X_DECIMALS,i={callback(t){const r=e?t:this?.getLabelForValue?.(t)??t;return formatAxisTick(r,l)}};return{responsive:!0,maintainAspectRatio:!1,parsing:!e&&void 0,scales:{x:e?{type:"linear",ticks:i,title:{display:!!n,text:n}}:{ticks:i,title:{display:!!n,text:n}},y:{position:"left",title:{display:!0,text:axisLabel(W,"left",t)}},...te?{y1:{position:"right",grid:{drawOnChartArea:!1},title:{display:!0,text:axisLabel(W,"right",t)}}}:{}},plugins:{legend:{display:!0},zoom:{pan:{enabled:!0,mode:"xy"},zoom:{wheel:{enabled:!0},pinch:{enabled:!0},mode:"xy"}},annotation:{annotations:buildRegionAnnotations(ae)}}}},[W,te,ae,m,o]),oe=o?.raw_data?.blob_name??"trace",le=useRef(""),ie=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===oe&&"number"==typeof e?.cycle_index).map(e=>e.cycle_index).sort((e,t)=>e-t)}catch{return[]}},[r,a,n,oe,c]),se=useCallback(async e=>{if(!r||!a||!n)return;const t=`${r}|${a}|${n}|${oe}|${e??"latest"}`;if(le.current===t)return;le.current=t;const o={project_id:r,method_id:a,run_id:n,name:oe};null!=e&&(o.cycle_index=e),E(!0),D(null),O(null);try{const e=await c("tis.read_raw",MessageType.Request,o);e?.success?O(e.data??{}):D(e?.error_message??"No raw data on disk for this run.")}catch(e){D(String(e?.message??e))}finally{E(!1)}q(!0),F(null),I(null);try{const e=await c("tis.read_filtered",MessageType.Request,o);e?.success?I(e.data??{}):F(e?.error_message??"No filtered data on disk for this run.")}catch(e){F(String(e?.message??e))}finally{q(!1)}},[r,a,n,oe,c]);useEffect(()=>{le.current="",H([]),z(null)},[r,a,n,oe]);return useEffect(()=>{j&&null!=P&&se(P)},[j,P,se]),r&&a&&n&&o?_jsxs("div",{className:"vblock",style:{display:"flex",flexDirection:"column",gap:"1rem"},children:[_jsx(Header,{meta:p,config:p?.config,runId:n,projectId:r,methodId:a,canViewRaw:!!o.raw_data,onViewRaw:async()=>{v(!0);let e=V;0===e.length&&(e=await ie(),H(e));const t=e.length>0?e[e.length-1]:null,r=P??t;P!==r&&z(r),await se(r)},onShowConfig:()=>C(!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:B,options:$.map(e=>({label:e.view.title??e.name,value:e.name})),onChange:e=>G(e.value),placeholder:0===$.length?"No view defined":"Select a view",disabled:0===$.length}),_jsx("h3",{style:{margin:0},children:W?.title??""}),U&&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:()=>T.current?.resetZoom?.(),disabled:!ee,tooltip:"Reset chart zoom",tooltipOptions:{position:"left"},"aria-label":"Reset chart zoom"})]}),_jsxs("div",{style:{height:s,position:"relative"},children:[U&&Q.loading&&_jsx(ChartOverlay,{children:"Loading raw data…"}),U&&Q.error&&_jsx(ChartOverlay,{children:Q.error}),ee&&_jsx(Line,{ref:T,data:ee,options:ne})]})]}),(()=>{const e=f.length>CYCLE_VIRTUAL_THRESHOLD,t=[...(o.cycle_config_fields??[]).map(e=>toScienceColumn(e,!0,m)),...(o.cycle_fields??[]).map(e=>toScienceColumn(e,!!e.editable,m))];return _jsx(ScienceTable,{title:`Cycle Data (${f.length})`,columns:t,rows:f,indexOrder:"descending",scrollable:e,scrollHeight:e?i:void 0,emptyMessage:"No cycles yet.",onCellEdit:S})})(),(()=>{const e={...g,...x},t=Object.keys(e).length>0,r=o.results_fields??[],a=r.map(e=>toScienceColumn(e,!1,m)),n=r.some(isProjectScoped);return _jsxs(_Fragment,{children:[_jsx(ScienceTable,{title:"Results",columns:a,rows:t?[e]:[],emptyMessage:"No results yet."}),n&&_jsx("div",{style:{fontSize:"0.8rem",color:"var(--text-secondary-color)",margin:"0.25rem 0 0.75rem"},children:"* across every test of this sample in the project. All other values describe this test."})]})})(),o.raw_data&&_jsxs(Dialog,{visible:j,onHide:()=>v(!1),header:`Run Data — ${n}`,style:{width:"90vw",height:"80vh"},maximizable:!0,children:[_jsx(CyclePickerBar,{cycles:V,selected:P,onChange:z}),_jsx(RawEnvelopeHeader,{envelope:R}),_jsxs(TabView,{style:{height:"100%"},children:[_jsx(TabPanel,{header:"Raw Data",children:_jsx(DataBlobTable,{blob:unwrapEnvelope(R),loading:M,error:A,rawData:o.raw_data})}),_jsx(TabPanel,{header:"Filtered Data",children:_jsx(DataBlobTable,{blob:unwrapEnvelope(L),loading:k,error:N,rawData:o.raw_data,emptyMessage:"Filtered data is written by post-processing — none on disk for this run yet."})})]})]}),_jsx(Dialog,{visible:w,onHide:()=>C(!1),header:"Test Configuration",style:{width:"min(640px, 90vw)"},modal:!0,children:_jsx(ConfigList,{config:p?.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:o,onViewRaw:l,onShowConfig:i})=>{const s="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:[s||r,c&&_jsx(Button,{icon:"pi pi-info-circle",type:"button",rounded:!0,text:!0,onClick:i,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()]})]})]}),o&&_jsx(Button,{icon:"pi pi-table",label:"View Raw Data",onClick:l,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 o=Object.keys(a.columns??{}),l=Object.keys(e).filter(t=>Array.isArray(e[t])),i=[];for(const t of o)Array.isArray(e[t])&&i.push(t);for(const e of l)i.includes(e)||i.push(e);if(0===i.length)return _jsx("div",{style:{padding:"1rem",color:"var(--text-secondary-color)"},children:n??"No columnar data in this blob."});const s=i.reduce((t,r)=>Math.min(t,e[r].length),Number.POSITIVE_INFINITY),c=Number.isFinite(s)?s:0,d=Array.from({length:c},(t,r)=>{const a={__i:r};for(const t of i)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"}}),i.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 o=0;o<2*t;o++)r[a][o]-=n*r[e][o]}}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 o=a+1,l=Array.from({length:o},()=>new Array(o).fill(0));for(let e=0;e<o;e++)for(let t=0;t<o;t++){let a=0;for(let o=0;o<r;o++)a+=n[o][e]*n[o][t];l[e][t]=a}const i=invertMatrix(l);if(!i)return new Array(r).fill(1/r);const s=new Array(r);for(let e=0;e<r;e++){let t=0;for(let r=0;r<o;r++)t+=i[0][r]*n[e][r];s[e]=t}return s}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},o=new Array(r);for(let a=0;a<r;a++){const l=Math.min(t,a,r-1-a);if(l<1){o[a]=e[a];continue}const i=n(l);let s=0;for(let t=-l;t<=l;t++)s+=i[t+l]*e[a+t];o[a]=s}return o}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))),o=savitzkyGolay(t.slice(0,a),n),l=Math.max(1,Math.ceil(a/SMOOTH_TARGET_POINTS)),i=[];for(let t=0;t<a;t+=l)i.push({x:e[t],y:o[t]});return(a-1)%l!=0&&i.push({x:e[a-1],y:o[a-1]}),i}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});export const DEFAULT_X_DECIMALS=2;const formatAxisTick=(e,t)=>{const r="number"==typeof e?e:Number(e);return Number.isFinite(r)?Number.parseFloat(r.toFixed(t)).toString():null==e?"":String(e)},quantityOfField=(e,t)=>{if(e&&t)for(const r of[e.cycle_config_fields,e.cycle_fields,e.results_fields]){const e=(r??[]).find(e=>e.name===t);if(e?.quantity)return e.quantity}},quantityOfColumn=(e,t)=>{if(e&&t)return e.raw_data?.columns?.[t]?.quantity},toDisplayValue=(e,t)=>t&&"number"==typeof e&&Number.isFinite(e)?e*t.scale+(t.offset??0):e,seriesLabel=e=>e.label??e.field??e.column??"",axisLabel=(e,t,r)=>{const a=e?.y.filter(e=>"right"===e.y_axis==("right"===t))??[],n=a.map(seriesLabel).join(" / "),o=Array.from(new Set(a.map(r).filter(Boolean)));return 1===o.length?`${n} [${o[0]}]`:n},isProjectScoped=e=>"project"===e.aggregate?.scope,toScienceColumn=(e,t=!1,r)=>{const a=e.quantity?r?.[e.quantity]:void 0;return{field:e.name,label:(e.label&&e.label.length>0?e.label:e.name)+(isProjectScoped(e)?" *":""),units:a?a.label:e.units,editable:t,body:t=>formatCell(t[e.name],e.type,e.scale,a)}},formatCell=(e,t,r,a)=>null==e?"":a&&"number"==typeof e&&Number.isFinite(e)?formatScaled(e*a.scale+(a.offset??0),a):(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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TestRawDataView.d.ts","sourceRoot":"","sources":["../../../src/components/tis/TestRawDataView.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAoC,MAAM,OAAO,CAAC;AAWzD,OAAO,KAAK,EAAa,UAAU,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"TestRawDataView.d.ts","sourceRoot":"","sources":["../../../src/components/tis/TestRawDataView.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAoC,MAAM,OAAO,CAAC;AAWzD,OAAO,KAAK,EAAa,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAU5D,MAAM,WAAW,oBAAoB;IACjC,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,mEAAmE;IACnE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0CAA0C;IAC1C,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAmJ1D,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import React,{useMemo,useRef,useState}from"react";import{Button}from"primereact/button";import{Dropdown}from"primereact/dropdown";import{Chart as ChartJS,CategoryScale,LinearScale,PointElement,LineElement,Title,Tooltip,Legend}from"chart.js";import zoomPlugin from"chartjs-plugin-zoom";import{Line}from"react-chartjs-2";import{useTis}from"./TisProvider";import{useRawCycleData}from"./useRawCycleData";ChartJS.register(CategoryScale,LinearScale,PointElement,LineElement,Title,Tooltip,Legend,zoomPlugin);export const TestRawDataView=e=>{const t=useTis(),r=e.projectId??t.selection.projectId,l=e.methodId??t.selection.methodId,a=e.runId??t.selection.runId,o=e.schema??(l?t.schemas[l]:void 0),{blobName:s,chartHeight:
|
|
1
|
+
import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import React,{useMemo,useRef,useState}from"react";import{Button}from"primereact/button";import{Dropdown}from"primereact/dropdown";import{Chart as ChartJS,CategoryScale,LinearScale,PointElement,LineElement,Title,Tooltip,Legend}from"chart.js";import zoomPlugin from"chartjs-plugin-zoom";import{Line}from"react-chartjs-2";import{useTis}from"./TisProvider";import{useRawCycleData}from"./useRawCycleData";import{orderedViews}from"./chartViews";ChartJS.register(CategoryScale,LinearScale,PointElement,LineElement,Title,Tooltip,Legend,zoomPlugin);export const TestRawDataView=e=>{const t=useTis(),r=e.projectId??t.selection.projectId,l=e.methodId??t.selection.methodId,a=e.runId??t.selection.runId,o=e.schema??(l?t.schemas[l]:void 0),{blobName:s,chartHeight:i="60vh"}=e,n=useRef(null),c=useMemo(()=>orderedViews(o?.views,"raw_trace"),[o]),[d,m]=useState(c.length>0?c[0].name:null),p=s??o?.raw_data?.blob_name??"trace",y=c.find(e=>e.name===d)?.view,{cycles:x,selectedCycle:h,setSelectedCycle:u,raw:g,envelope:j,loading:f,error:v}=useRawCycleData({projectId:r,methodId:l,runId:a,blobName:p,source:y?.source??"raw",enabled:!!r&&!!l&&!!a}),_=useMemo(()=>{if(!g||!d)return null;const e=c.find(e=>e.name===d)?.view;if(!e)return null;const t=e.x.column,r=g[t]??[];return{datasets:e.y.map((e,t)=>({label:e.label??e.column,data:(g[e.column]??[]).map((e,t)=>({x:r[t],y:e})),yAxisID:"right"===e.y_axis?"y1":"y",borderColor:palette(t),backgroundColor:palette(t),pointRadius:0,borderWidth:1.5,showLine:!0}))}},[g,d,c]),b=y?.y.some(e=>"right"===e.y_axis)??!1,w=useMemo(()=>({responsive:!0,maintainAspectRatio:!1,parsing:!1,scales:{x:{type:"linear",title:{display:!!y?.x.label,text:y?.x.label}},y:{position:"left",title:{display:!0,text:axisLabel(y,"left")}},...b?{y1:{position:"right",grid:{drawOnChartArea:!1},title:{display:!0,text:axisLabel(y,"right")}}}:{}},plugins:{legend:{display:!0},zoom:{pan:{enabled:!0,mode:"xy"},zoom:{wheel:{enabled:!0},pinch:{enabled:!0},drag:{enabled:!0,modifierKey:"shift"},mode:"xy"}}}}),[y,b]);return r&&l&&a?o?o.raw_data?0===c.length?_jsx(EmptyState,{message:"No raw_trace views declared. Add one to schema.views in project.json."}):_jsxs("div",{className:"vblock",style:{display:"flex",flexDirection:"column",gap:"1rem",height:"100%"},children:[_jsxs("div",{className:"flex",style:{gap:"1rem",alignItems:"center",flexWrap:"wrap"},children:[_jsx(Dropdown,{value:d,options:c.map(e=>({label:e.view.title??e.name,value:e.name})),onChange:e=>m(e.value),placeholder:"Select a view"}),_jsx("h3",{style:{margin:0},children:y?.title??""}),x.length>1&&_jsxs(_Fragment,{children:[_jsx("label",{htmlFor:"rawview-cycle-picker",style:{color:"var(--text-secondary-color)"},children:"Cycle:"}),_jsx(Dropdown,{inputId:"rawview-cycle-picker",value:h,options:x.map(e=>({label:`Cycle ${e}`,value:e})),onChange:e=>u(Number(e.value)),style:{minWidth:"8rem"}}),_jsxs("span",{style:{color:"var(--text-secondary-color)"},children:["of ",x.length]})]}),_jsx("div",{style:{flex:1}}),_jsx(Button,{icon:"pi pi-refresh",label:"Reset Zoom",outlined:!0,onClick:()=>n.current?.resetZoom?.()})]}),_jsx(EnvelopeMetaStrip,{envelope:j}),_jsxs("div",{style:{flex:1,minHeight:0,height:i,position:"relative"},children:[f&&_jsx(Overlay,{children:"Loading raw data…"}),v&&_jsx(Overlay,{children:v}),_&&!f&&!v&&_jsx(Line,{ref:n,data:_,options:w})]})]}):_jsx(EmptyState,{message:"No raw_data is declared for this test method."}):_jsx(EmptyState,{message:"Schema not loaded yet."}):_jsx(EmptyState,{message:"No test selected."})};const Overlay=({children:e})=>_jsx("div",{style:{position:"absolute",inset:0,display:"flex",alignItems:"center",justifyContent:"center",color:"var(--text-secondary-color)",pointerEvents:"none"},children:e}),EmptyState=({message:e})=>_jsx("div",{style:{padding:"1rem",color:"var(--text-secondary-color)"},children:e}),EnvelopeMetaStrip=({envelope:e})=>{if(!e||"object"!=typeof e)return null;const t=e.cycle_index,r=e.cycle_fields,l=e.context;if(null==t&&!r&&!l)return null;const a=e=>e&&"object"==typeof e?Object.entries(e).filter(([,e])=>null!==e&&"object"!=typeof e).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)):null;return _jsxs("div",{style:{padding:"0.5rem 0.25rem",fontSize:"0.9rem",borderTop:"1px solid var(--surface-border)",borderBottom:"1px solid var(--surface-border)"},children:[null!=t&&_jsx("div",{children:_jsxs("strong",{children:["Cycle ",t]})}),r&&_jsx("div",{style:{marginTop:"0.25rem"},children:a(r)}),l&&_jsx("div",{style:{marginTop:"0.25rem"},children:a(l)})]})},CHART_COLORS=["#4ea8de","#f59e0b","#22c55e","#a855f7","#ef4444","#14b8a6","#eab308","#ec4899"],palette=e=>CHART_COLORS[e%CHART_COLORS.length],axisLabel=(e,t)=>e?.y.filter(e=>(e.y_axis??"left")===t).map(e=>e.label??e.column).join(" / ")??"";
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chart-view ordering.
|
|
3
|
+
*
|
|
4
|
+
* `views` is a JSON object and the server holds it in a `BTreeMap`, so what
|
|
5
|
+
* reaches the HMI is sorted by view id — never by the order anyone chose. That
|
|
6
|
+
* order is a real setting: the Data tab opens on the FIRST view, so whichever
|
|
7
|
+
* id happens to sort first becomes the default chart. Renaming views to spell
|
|
8
|
+
* an order is not an option (the id is the wire key, and codegen emits it).
|
|
9
|
+
*
|
|
10
|
+
* So the order is carried explicitly, per view, as `order`: an integer,
|
|
11
|
+
* ascending, renumbered densely by the editor's Move up / Move down.
|
|
12
|
+
*
|
|
13
|
+
* `order` is deliberately NOT modelled by the Rust `ChartView`. It rides in
|
|
14
|
+
* that struct's flattened `extra` map, the way `x_decimals`, `smooth` and
|
|
15
|
+
* `regions` already do, so a `tis.put_method` → `tis.save_config` round-trip
|
|
16
|
+
* preserves it with no server-side change to deploy.
|
|
17
|
+
*
|
|
18
|
+
* A view with no `order` sorts after every ordered one, by id — so a method
|
|
19
|
+
* that has never been through the editor keeps exactly the order it shows
|
|
20
|
+
* today, and a newly added view lands last instead of jumping to the front.
|
|
21
|
+
*/
|
|
22
|
+
/** Minimal shape this module needs; both the editor's and the runtime's
|
|
23
|
+
* `ChartView` satisfy it. */
|
|
24
|
+
export interface OrderableView {
|
|
25
|
+
order?: number;
|
|
26
|
+
type?: string;
|
|
27
|
+
}
|
|
28
|
+
/** A view together with its id — the id is the wire key, not a field. */
|
|
29
|
+
export interface NamedView<V> {
|
|
30
|
+
name: string;
|
|
31
|
+
view: V;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The method's views in display order: by `order` ascending, then by id.
|
|
35
|
+
*
|
|
36
|
+
* @param views The method's `views` map, as received from the server.
|
|
37
|
+
* @param ofType Optional `type` filter (e.g. `'raw_trace'`).
|
|
38
|
+
*/
|
|
39
|
+
export declare function orderedViews<V extends OrderableView>(views?: Record<string, V> | null, ofType?: string): NamedView<V>[];
|
|
40
|
+
/**
|
|
41
|
+
* Stamp `order` 0..n-1 onto `views` following `orderedIds`.
|
|
42
|
+
*
|
|
43
|
+
* Every view is renumbered, not just the moved one: dense integers mean the
|
|
44
|
+
* next move is a swap of two adjacent numbers, and a method that was
|
|
45
|
+
* previously unordered comes out fully ordered after one Move rather than
|
|
46
|
+
* half-and-half.
|
|
47
|
+
*
|
|
48
|
+
* Ids in `views` but missing from `orderedIds` keep their existing `order`
|
|
49
|
+
* and land after the renumbered ones.
|
|
50
|
+
*/
|
|
51
|
+
export declare function renumberViews<V extends OrderableView>(views: Record<string, V>, orderedIds: string[]): Record<string, V>;
|
|
52
|
+
/**
|
|
53
|
+
* Move the view at `index` by `dir` (-1 up, +1 down) and renumber.
|
|
54
|
+
* Out-of-range moves return the map unchanged.
|
|
55
|
+
*/
|
|
56
|
+
export declare function moveView<V extends OrderableView>(views: Record<string, V>, index: number, dir: -1 | 1): Record<string, V>;
|
|
57
|
+
//# sourceMappingURL=chartViews.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chartViews.d.ts","sourceRoot":"","sources":["../../../src/components/tis/chartViews.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH;8BAC8B;AAC9B,MAAM,WAAW,aAAa;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,yEAAyE;AACzE,MAAM,WAAW,SAAS,CAAC,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,CAAC,CAAC;CACX;AAQD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,aAAa,EAChD,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,IAAI,EAChC,MAAM,CAAC,EAAE,MAAM,GAChB,SAAS,CAAC,CAAC,CAAC,EAAE,CAWhB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,aAAa,EACjD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,EACxB,UAAU,EAAE,MAAM,EAAE,GACrB,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAUnB;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,aAAa,EAC5C,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,EACxB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,GACZ,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAMnB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const UNORDERED=Number.MAX_SAFE_INTEGER,orderOf=e=>"number"==typeof e?.order&&Number.isFinite(e.order)?e.order:UNORDERED;export function orderedViews(e,r){const o=[];for(const[n,t]of Object.entries(e??{}))r&&t?.type!==r||o.push({name:n,view:t});return o.sort((e,r)=>{const o=orderOf(e.view)-orderOf(r.view);return 0!==o?o:e.name.localeCompare(r.name)}),o}export function renumberViews(e,r){const o={};r.forEach((r,n)=>{const t=e[r];t&&(o[r]={...t,order:n})});for(const[r,n]of Object.entries(e))r in o||(o[r]=n);return o}export function moveView(e,r,o){const n=orderedViews(e).map(e=>e.name),t=r+o;return r<0||r>=n.length||t<0||t>=n.length?e:([n[r],n[t]]=[n[t],n[r]],renumberViews(e,n))}
|
|
@@ -105,6 +105,17 @@
|
|
|
105
105
|
font-size: 0.8rem;
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
+
/* A degradation, not a failure: the editor works, it just knows less. Amber
|
|
109
|
+
* rather than the red used for a real error. */
|
|
110
|
+
.tis-editor__notice {
|
|
111
|
+
background: #fffbeb;
|
|
112
|
+
color: #92400e;
|
|
113
|
+
border-left: 3px solid #d97706;
|
|
114
|
+
padding: 0.5rem 1rem;
|
|
115
|
+
margin: 0.5rem 1rem;
|
|
116
|
+
font-size: 0.875rem;
|
|
117
|
+
}
|
|
118
|
+
|
|
108
119
|
.tis-editor__empty {
|
|
109
120
|
flex: 1;
|
|
110
121
|
display: flex;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TisConfigEditor.d.ts","sourceRoot":"","sources":["../../../src/components/tis-editor/TisConfigEditor.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAWH,OAAO,EAAgB,KAAK,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAM5E,OAAO,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"TisConfigEditor.d.ts","sourceRoot":"","sources":["../../../src/components/tis-editor/TisConfigEditor.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAWH,OAAO,EAAgB,KAAK,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAM5E,OAAO,uBAAuB,CAAC;AAM/B,MAAM,WAAW,oBAAoB;IACjC;+EAC2E;IAC3E,SAAS,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,OAAO,CAAC,EAAE,aAAa,CAAC;CAC3B;AAmBD,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAoS1D,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import{useEffect,useMemo,useState}from"react";import{DataTable}from"primereact/datatable";import{Column}from"primereact/column";import{Button}from"primereact/button";import{InputText}from"primereact/inputtext";import{Dialog}from"primereact/dialog";import{useContext}from"react";import{EventEmitterContext}from"../../core/EventEmitterContext";import{MessageType}from"../../hub/CommandMessage";import{useTisConfig}from"../../hooks/useTisConfig";import{useAmsAssetTypes}from"../../hooks/useAmsAssetTypes";import{MethodFormEditor}from"./editor/MethodFormEditor";import{SaveDiffDialog}from"./editor/SaveDiffDialog";import"./TisConfigEditor.css";const EMPTY_METHOD={label:"",description:"",project_fields:[],config_fields:[],cycle_config_fields:[],cycle_fields:[],results_fields:[],views:{},asset_refs:[]};export const TisConfigEditor=({projectId:e,invoker:t})=>{const s=useContext(EventEmitterContext),i=useMemo(()=>t??(async(e,t)=>await s.invoke(e,MessageType.Request,t)),[t,s]),o=useTisConfig(e,{invoker:i}),a=useAmsAssetTypes({invoker:i}),[
|
|
1
|
+
import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import{useEffect,useMemo,useState}from"react";import{DataTable}from"primereact/datatable";import{Column}from"primereact/column";import{Button}from"primereact/button";import{InputText}from"primereact/inputtext";import{Dialog}from"primereact/dialog";import{useContext}from"react";import{EventEmitterContext}from"../../core/EventEmitterContext";import{MessageType}from"../../hub/CommandMessage";import{useTisConfig}from"../../hooks/useTisConfig";import{useAmsAssetTypes}from"../../hooks/useAmsAssetTypes";import{MethodFormEditor}from"./editor/MethodFormEditor";import{SaveDiffDialog}from"./editor/SaveDiffDialog";import"./TisConfigEditor.css";import{useGmVariables}from"../../hooks/useGmVariables";import{useSequenceProducers}from"../../hooks/useSequenceProducers";import{AuthoringContext}from"./editor/AuthoringContext";import{AutoCoreTagContext}from"../../core/AutoCoreTagContext";const EMPTY_METHOD={label:"",description:"",project_fields:[],config_fields:[],cycle_config_fields:[],cycle_fields:[],results_fields:[],views:{},asset_refs:[]};export const TisConfigEditor=({projectId:e,invoker:t})=>{const s=useContext(EventEmitterContext),i=useMemo(()=>t??(async(e,t)=>await s.invoke(e,MessageType.Request,t)),[t,s]),o=useTisConfig(e,{invoker:i}),{tags:a}=useContext(AutoCoreTagContext),r=useGmVariables({invoker:i,fallbackTags:a}),n=useAmsAssetTypes({invoker:i}),[l,d]=useState(null),[c,m]=useState(null),[u,f]=useState(!1),[p,h]=useState(!1),[g,_]=useState(!1),[x,y]=useState(""),b=useMemo(()=>o.config?Object.entries(o.config.methods).map(([e,t])=>({id:e,label:t?.label??""})):[],[o.config]);useEffect(()=>{if(!l&&o.config){const e=o.config.defaultMethodId||Object.keys(o.config.methods)[0]||null;d(e)}},[o.config,l]),useEffect(()=>{m(null)},[l]);const{producedNames:v}=useSequenceProducers(l),j=useMemo(()=>({variables:r.variables,producedNames:v,partial:r.partial}),[r.variables,v,r.partial]);return _jsx(AuthoringContext.Provider,{value:j,children:_jsxs("div",{className:"tis-editor",children:[_jsxs("header",{className:"tis-editor__header",children:[_jsxs("h2",{children:["Test Methods"," ",o.config?.dirty&&_jsx("span",{className:"tis-editor__dirty-pill",children:"unsaved"})]}),_jsxs("div",{className:"tis-editor__header-actions",children:[_jsx(Button,{label:"Save…",icon:"pi pi-save",disabled:u||!o.config?.dirty,onClick:()=>h(!0)}),_jsx(Button,{label:"Revert",icon:"pi pi-undo",className:"p-button-secondary",disabled:u||!o.config?.dirty,onClick:async()=>{if(window.confirm("Discard all in-progress edits? This cannot be undone.")){f(!0);try{await o.revert()}catch(e){m(String(e?.message??e))}finally{f(!1)}}}})]})]}),o.error&&_jsxs("div",{className:"tis-editor__error",children:[_jsx("strong",{children:"Error:"})," ",_jsx("pre",{children:o.error})]}),r.partial&&_jsx("div",{className:"tis-editor__notice",children:"This server cannot describe its own variables, so the pickers are listing only the variables published to this HMI, without descriptions. Update autocore_server to get the full list."}),_jsxs("div",{className:"tis-editor__body",children:[_jsxs("aside",{className:"tis-editor__sidebar",children:[_jsxs("div",{className:"tis-editor__sidebar-actions",children:[_jsx(Button,{label:"New",icon:"pi pi-plus",disabled:u,onClick:()=>_(!0)}),_jsx(Button,{label:"Duplicate",icon:"pi pi-clone",className:"p-button-secondary",disabled:u||!l,onClick:async()=>{if(!l||!o.config)return;const e=o.config.methods[l];if(!e)return;let t=`${l}_copy`,s=2;for(;o.config.methods[t];)t=`${l}_copy_${s++}`;f(!0);try{await o.putMethod(t,JSON.parse(JSON.stringify(e))),d(t)}catch(e){m(String(e?.message??e))}finally{f(!1)}}}),_jsx(Button,{label:"Delete",icon:"pi pi-trash",className:"p-button-danger",disabled:u||!l,onClick:async()=>{if(l&&window.confirm(`Remove method "${l}"? This is staged — Save persists it.`)){f(!0);try{await o.removeMethod(l),d(null)}catch(e){m(String(e?.message??e))}finally{f(!1)}}}})]}),_jsxs(DataTable,{value:b,selection:b.find(e=>e.id===l)??null,onSelectionChange:e=>d(e.value?.id??null),selectionMode:"single",dataKey:"id",scrollable:!0,scrollHeight:"flex",emptyMessage:o.loading?"Loading…":"No test methods defined.",children:[_jsx(Column,{field:"id",header:"Method ID"}),_jsx(Column,{field:"label",header:"Label"})]})]}),_jsx("section",{className:"tis-editor__detail",children:l&&o.config?.methods[l]?_jsxs(_Fragment,{children:[c&&_jsx("div",{className:"tis-editor__error",children:_jsx("pre",{children:c})}),_jsx(MethodFormEditor,{methodId:l,method:o.config.methods[l],onApply:async e=>{if(l){f(!0);try{await o.putMethod(l,e),m(null)}catch(e){m(String(e?.message??e))}finally{f(!1)}}},busy:u,knownAssetTypes:n.types})]}):_jsx("div",{className:"tis-editor__empty",children:"Select a test method on the left, or create a new one."})})]}),_jsxs(Dialog,{header:"New Test Method",visible:g,onHide:()=>_(!1),style:{width:"24rem"},children:[_jsxs("label",{className:"tis-editor__new-method-label",children:["Method ID",_jsx(InputText,{value:x,onChange:e=>y(e.target.value),placeholder:"e.g. translational_traction",autoFocus:!0})]}),_jsx("small",{children:"Canonical key — appears in wire payloads, on-disk paths, and generated code."}),_jsxs("div",{style:{display:"flex",gap:"0.5rem",justifyContent:"flex-end",marginTop:"1rem"},children:[_jsx(Button,{label:"Cancel",className:"p-button-text",onClick:()=>_(!1)}),_jsx(Button,{label:"Create",disabled:!x.trim()||u,onClick:async()=>{const e=x.trim();if(e)if(o.config?.methods[e])m(`A method named "${e}" already exists.`);else{f(!0);try{await o.putMethod(e,EMPTY_METHOD),d(e),_(!1),y("")}catch(e){m(String(e?.message??e))}finally{f(!1)}}}})]})]}),_jsx(SaveDiffDialog,{visible:p,staged:o.config?.methods??{},invoker:i,onConfirm:async()=>{f(!0);try{await o.save(),h(!1)}catch(e){m(String(e?.message??e))}finally{f(!1)}},onCancel:()=>h(!1)})]})})};export default TisConfigEditor;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the method editor's pickers can offer.
|
|
3
|
+
*
|
|
4
|
+
* A context rather than props because the fields that need it — a field
|
|
5
|
+
* dialog's Source, a bound, a chart axis, a raw column — sit three and four
|
|
6
|
+
* levels below the editor that fetches it, and threading the same two values
|
|
7
|
+
* through every intermediate component is how a prop list becomes noise.
|
|
8
|
+
*
|
|
9
|
+
* Everything here is optional. With none of it the pickers still open; they just
|
|
10
|
+
* have nothing to list, which is exactly the state the editor was in before they
|
|
11
|
+
* existed.
|
|
12
|
+
*/
|
|
13
|
+
import type { GmVariable } from '@adcops/autocore-varpick';
|
|
14
|
+
export interface AuthoringCatalogs {
|
|
15
|
+
/** The machine's GM variable table, from `gm.get_variables`. */
|
|
16
|
+
variables: GmVariable[];
|
|
17
|
+
/**
|
|
18
|
+
* `store_value` names in the selected method's sequence.
|
|
19
|
+
*
|
|
20
|
+
* `undefined` means "not looked up" — the host could not read the
|
|
21
|
+
* `.seq.json`, or this product has no sequencer. That is deliberately
|
|
22
|
+
* different from `[]`, which means "read it, and it stores nothing": the
|
|
23
|
+
* first must not claim a cycle field has no producer.
|
|
24
|
+
*/
|
|
25
|
+
producedNames?: string[];
|
|
26
|
+
/**
|
|
27
|
+
* True when `variables` came from the generated tag spec rather than the
|
|
28
|
+
* server — names and types, no descriptions, `ux: true` only.
|
|
29
|
+
*
|
|
30
|
+
* Worth surfacing: a picker that silently lists two thirds of the machine
|
|
31
|
+
* is worse than one that says it is listing two thirds of the machine.
|
|
32
|
+
*/
|
|
33
|
+
partial?: boolean;
|
|
34
|
+
}
|
|
35
|
+
export declare const AuthoringContext: import("react").Context<AuthoringCatalogs>;
|
|
36
|
+
export declare const useAuthoringCatalogs: () => AuthoringCatalogs;
|
|
37
|
+
//# sourceMappingURL=AuthoringContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthoringContext.d.ts","sourceRoot":"","sources":["../../../../src/components/tis-editor/editor/AuthoringContext.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAE3D,MAAM,WAAW,iBAAiB;IAC9B,gEAAgE;IAChE,SAAS,EAAE,UAAU,EAAE,CAAC;IAExB;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IAEzB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,eAAO,MAAM,gBAAgB,4CAAsD,CAAC;AAEpF,eAAO,MAAM,oBAAoB,QAAO,iBAAiD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createContext,useContext}from"react";export const AuthoringContext=createContext({variables:[]});export const useAuthoringCatalogs=()=>useContext(AuthoringContext);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ChartView } from '../types';
|
|
2
|
+
import type { Catalog } from '@adcops/autocore-varpick';
|
|
2
3
|
export interface ChartViewDialogProps {
|
|
3
4
|
visible: boolean;
|
|
4
5
|
initial: {
|
|
@@ -9,6 +10,16 @@ export interface ChartViewDialogProps {
|
|
|
9
10
|
onSave: (viewId: string, view: ChartView) => void;
|
|
10
11
|
/** Known field/column names; offered as datalist suggestions. */
|
|
11
12
|
knownKeys: string[];
|
|
13
|
+
/**
|
|
14
|
+
* The same names, grouped and described, for the picker button.
|
|
15
|
+
*
|
|
16
|
+
* Takes the view TYPE because it decides which list is the likely answer:
|
|
17
|
+
* a `raw_trace` plots trace columns, a `cycle_scatter` plots cycle fields.
|
|
18
|
+
* A datalist alone was not enough — it only appears once you start typing,
|
|
19
|
+
* which is no help when you do not know what to type, and it does not open
|
|
20
|
+
* at all on a touchscreen.
|
|
21
|
+
*/
|
|
22
|
+
fieldCatalog?: (viewType: string) => Catalog;
|
|
12
23
|
/** Other view ids already in use — for uniqueness validation. */
|
|
13
24
|
siblingIds: string[];
|
|
14
25
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChartViewDialog.d.ts","sourceRoot":"","sources":["../../../../src/components/tis-editor/editor/ChartViewDialog.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ChartViewDialog.d.ts","sourceRoot":"","sources":["../../../../src/components/tis-editor/editor/ChartViewDialog.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAA0B,SAAS,EAAE,MAAM,UAAU,CAAC;AAElE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAiBxD,MAAM,WAAW,oBAAoB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,SAAS,CAAA;KAAE,GAAG,IAAI,CAAC;IACpD,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,KAAK,IAAI,CAAC;IAClD,iEAAiE;IACjE,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;IAC7C,iEAAiE;IACjE,UAAU,EAAE,MAAM,EAAE,CAAC;CACxB;AAQD,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CA4K1D,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import{useEffect,useState}from"react";import{Dialog}from"primereact/dialog";import{Button}from"primereact/button";import{InputText}from"primereact/inputtext";import{Dropdown}from"primereact/dropdown";import{InputNumber}from"primereact/inputnumber";import{FormRow}from"../../forms/FormRow";import{DEFAULT_X_DECIMALS}from"../../tis/TestDataView";const MAX_X_DECIMALS=8,VIEW_TYPES=[{label:"Cycle scatter",value:"cycle_scatter"},{label:"Raw trace",value:"raw_trace"}],Y_AXES=[{label:"Left",value:"left"},{label:"Right",value:"right"}],blank=()=>({title:"",type:"cycle_scatter",x:{field:"",label:""},y:[]});export const ChartViewDialog=({visible:e,initial:
|
|
1
|
+
import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import{useEffect,useState}from"react";import{Dialog}from"primereact/dialog";import{Button}from"primereact/button";import{InputText}from"primereact/inputtext";import{Dropdown}from"primereact/dropdown";import{InputNumber}from"primereact/inputnumber";import{FormRow}from"../../forms/FormRow";import{useEditDraft}from"../../forms/useEditDraft";import{DEFAULT_X_DECIMALS}from"../../tis/TestDataView";import{VariableInput}from"../../varpick";const MAX_X_DECIMALS=8,VIEW_TYPES=[{label:"Cycle scatter",value:"cycle_scatter"},{label:"Raw trace",value:"raw_trace"}],Y_AXES=[{label:"Left",value:"left"},{label:"Right",value:"right"}],blank=()=>({title:"",type:"cycle_scatter",x:{field:"",label:""},y:[]});export const ChartViewDialog=({visible:e,initial:t,onCancel:l,onSave:a,knownKeys:i,siblingIds:r,fieldCatalog:n})=>{const{draft:o,setDraft:s,token:c}=useEditDraft(e,t?.viewId??"",()=>({viewId:t?.viewId??"",view:t?JSON.parse(JSON.stringify(t.view)):blank()})),m=o.viewId,d=o.view,u=e=>s(t=>({...t,view:e})),[p,x]=useState(null);useEffect(()=>{x(null)},[c]);const _="raw_trace"===d.type,h=_?"column":"field",v=e=>{u({...d,x:{...d.x,...e}})},f=(e,t)=>{const l=[...d.y];l[e]={...l[e],...t},u({...d,y:l})};return _jsxs(Dialog,{header:t?`Edit view: ${t.viewId}`:"New chart view",visible:e,onHide:l,style:{width:"42rem"},children:[p&&_jsx("div",{style:{color:"#dc2626",marginBottom:"0.5rem"},children:p}),_jsx(FormRow,{label:"View ID",required:!0,hint:"Stable key (e.g. cof_scatter). Cannot collide with other views.",children:_jsx(InputText,{value:m,onChange:e=>{return t=e.target.value,s(e=>({...e,viewId:t}));var t}})}),_jsx(FormRow,{label:"Title",children:_jsx(InputText,{value:d.title??"",onChange:e=>u({...d,title:e.target.value})})}),_jsx(FormRow,{label:"Type",required:!0,children:_jsx(Dropdown,{value:d.type,options:VIEW_TYPES,onChange:e=>u({...d,type:e.value})})}),_jsx(FormRow,{label:_?"X column":"X field",required:!0,children:_jsx(VariableInput,{value:d.x[h]??"",onChange:e=>v({[h]:e}),catalog:()=>n?.(d.type)??[],ariaLabel:"Choose the X axis column",pickerTitle:"X axis",pickerHint:"A chart naming a column that does not exist draws an empty plot with no error, which reads as “the machine recorded nothing”."})}),_jsx(FormRow,{label:"X label",children:_jsx(InputText,{value:d.x.label??"",onChange:e=>v({label:e.target.value})})}),_jsx(FormRow,{label:"X decimals",hint:`Decimal places on X-axis tick labels. Blank uses the default (${DEFAULT_X_DECIMALS}). Display only — stored data keeps full precision.`,children:_jsx(InputNumber,{value:d.x_decimals??null,onValueChange:e=>{const t={...d};null==e.value?delete t.x_decimals:t.x_decimals=e.value,u(t)},min:0,max:8,placeholder:String(DEFAULT_X_DECIMALS),showButtons:!0})}),_jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",margin:"1rem 0 0.5rem"},children:[_jsx("strong",{children:"Y series"}),_jsx(Button,{label:"Add series",icon:"pi pi-plus",size:"small",onClick:()=>{u({...d,y:[...d.y,{[h]:"",label:"",y_axis:"left"}]})}})]}),0===d.y.length&&_jsx("small",{children:"No series — add at least one."}),d.y.map((e,t)=>_jsxs("div",{style:{display:"grid",gridTemplateColumns:"1fr 1fr 6rem 2rem",gap:"0.5rem",marginBottom:"0.25rem",alignItems:"center"},children:[_jsx(VariableInput,{placeholder:_?"column":"field",value:e[h]??"",onChange:e=>f(t,{[h]:e}),catalog:()=>n?.(d.type)??[],ariaLabel:`Choose the column for series ${t+1}`,pickerTitle:"Y series"}),_jsx(InputText,{placeholder:"label",value:e.label??"",onChange:e=>f(t,{label:e.target.value})}),_jsx(Dropdown,{value:e.y_axis??"left",options:Y_AXES,onChange:e=>f(t,{y_axis:e.value})}),_jsx(Button,{icon:"pi pi-trash",className:"p-button-text p-button-danger p-button-sm",onClick:()=>(e=>{u({...d,y:d.y.filter((t,l)=>l!==e)})})(t),"aria-label":"Remove series"})]},t)),_jsx("datalist",{id:"known-keys",children:i.map(e=>_jsx("option",{value:e},e))}),_jsxs("div",{style:{display:"flex",justifyContent:"flex-end",gap:"0.5rem",marginTop:"1rem"},children:[_jsx(Button,{label:"Cancel",className:"p-button-text",onClick:l}),_jsx(Button,{label:"Save",onClick:()=>{const e=m.trim()?r.includes(m)&&m!==t?.viewId?`A view named "${m}" already exists.`:null:"View ID is required.";e?x(e):a(m,d)}})]})]})};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FieldArrayEditor.d.ts","sourceRoot":"","sources":["../../../../src/components/tis-editor/editor/FieldArrayEditor.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAa,UAAU,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAyBrE,MAAM,WAAW,qBAAqB;IAClC,QAAQ,EAAE,aAAa,CAAC;IACxB,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;CACxC;AAED,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,
|
|
1
|
+
{"version":3,"file":"FieldArrayEditor.d.ts","sourceRoot":"","sources":["../../../../src/components/tis-editor/editor/FieldArrayEditor.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAa,UAAU,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAyBrE,MAAM,WAAW,qBAAqB;IAClC,QAAQ,EAAE,aAAa,CAAC;IACxB,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;CACxC;AAED,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAyH5D,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import{useState}from"react";import{DataTable}from"primereact/datatable";import{Column}from"primereact/column";import{Button}from"primereact/button";import{FormSection}from"../../forms/FormSection";import{TestFieldDialog}from"./TestFieldDialog";const TITLES={project_fields:"Project Fields",config_fields:"Config Fields",cycle_config_fields:"Cycle Configuration Fields",cycle_fields:"Cycle Fields",results_fields:"Results Fields"},DESCRIPTIONS={project_fields:"System-level fields (operator, station). Filled by the HMI but not cycled.",config_fields:"Operator-input config (speeds, loads). Snapshotted into test.json on start.",cycle_config_fields:"Operator-entered annotation recorded onto every cycle row (e.g. which of six positions this is). Shown on the HMI Cycle tab and written as the first Cycle Data columns after the row index. Mark them Required so the machine cannot start unannotated, and Autoclear so the next row cannot inherit a stale value.",cycle_fields:"Per-cycle capture. One row appended to cycles.jsonl per cycle.",results_fields:"Post-test summary (min/max/avg, pass/fail). Written once at finish. A field can also be a cross-test Aggregate (avg/min/max/stddev/count over tests sharing a sample_id)."},aggregateLabel=e=>{const t=e.aggregate;return t?"count"===t.fn?"count":`${t.fn}(${t.of??"?"})`:""};export const FieldArrayEditor=({arrayKey:e,method:t,onChange:
|
|
1
|
+
import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import{useState}from"react";import{DataTable}from"primereact/datatable";import{Column}from"primereact/column";import{Button}from"primereact/button";import{FormSection}from"../../forms/FormSection";import{TestFieldDialog}from"./TestFieldDialog";const TITLES={project_fields:"Project Fields",config_fields:"Config Fields",cycle_config_fields:"Cycle Configuration Fields",cycle_fields:"Cycle Fields",results_fields:"Results Fields"},DESCRIPTIONS={project_fields:"System-level fields (operator, station). Filled by the HMI but not cycled.",config_fields:"Operator-input config (speeds, loads). Snapshotted into test.json on start.",cycle_config_fields:"Operator-entered annotation recorded onto every cycle row (e.g. which of six positions this is). Shown on the HMI Cycle tab and written as the first Cycle Data columns after the row index. Mark them Required so the machine cannot start unannotated, and Autoclear so the next row cannot inherit a stale value.",cycle_fields:"Per-cycle capture. One row appended to cycles.jsonl per cycle.",results_fields:"Post-test summary (min/max/avg, pass/fail). Written once at finish. A field can also be a cross-test Aggregate (avg/min/max/stddev/count over tests sharing a sample_id)."},aggregateLabel=e=>{const t=e.aggregate;return t?"count"===t.fn?"count":`${t.fn}(${t.of??"?"})`:""};export const FieldArrayEditor=({arrayKey:e,method:t,onChange:l})=>{const s=t[e]??[],[i,o]=useState(!1),[n,a]=useState(null),r=(i,o)=>{const n=i+o;if(n<0||n>=s.length)return;const a=[...s];[a[i],a[n]]=[a[n],a[i]],l({...t,[e]:a})};return _jsxs(_Fragment,{children:[_jsx(FormSection,{title:TITLES[e],description:DESCRIPTIONS[e],actions:_jsx(Button,{label:"Add field",icon:"pi pi-plus",size:"small",onClick:()=>{a(null),o(!0)}}),children:_jsxs(DataTable,{value:s,dataKey:"name",emptyMessage:"No fields defined.",children:[_jsx(Column,{field:"name",header:"Name"}),_jsx(Column,{field:"type",header:"Type",style:{width:"6rem"}}),_jsx(Column,{field:"units",header:"Units",style:{width:"6rem"}}),_jsx(Column,{header:"Req",body:e=>e.required?"✓":"",style:{width:"4rem"}}),_jsx(Column,{field:"label",header:"Label"}),"results_fields"===e&&_jsx(Column,{header:"Aggregate",body:e=>aggregateLabel(e),style:{width:"8rem"}}),"cycle_config_fields"===e&&_jsx(Column,{header:"Autoclear",body:e=>e.autoclear?"✓":"",style:{width:"6rem"}}),_jsx(Column,{header:"",body:(i,n)=>_jsxs("div",{style:{display:"flex",gap:"0.25rem"},children:[_jsx(Button,{icon:"pi pi-arrow-up",className:"p-button-text p-button-sm",disabled:0===n.rowIndex,onClick:()=>r(n.rowIndex,-1),"aria-label":"Move up"}),_jsx(Button,{icon:"pi pi-arrow-down",className:"p-button-text p-button-sm",disabled:n.rowIndex===s.length-1,onClick:()=>r(n.rowIndex,1),"aria-label":"Move down"}),_jsx(Button,{icon:"pi pi-pencil",className:"p-button-text p-button-sm",onClick:()=>{return e=n.rowIndex,a(e),void o(!0);var e},"aria-label":"Edit"}),_jsx(Button,{icon:"pi pi-trash",className:"p-button-text p-button-danger p-button-sm",onClick:()=>(i=>{const o=s[i];if(!o)return;if(!window.confirm(`Remove field "${o.name}"?`))return;const n=s.filter((e,t)=>t!==i);l({...t,[e]:n})})(n.rowIndex),"aria-label":"Remove"})]}),style:{width:"10rem"}})]})}),_jsx(TestFieldDialog,{visible:i,initial:null!==n?s[n]??null:null,siblingNames:s.map(e=>e.name),isResultsField:"results_fields"===e,isCycleConfigField:"cycle_config_fields"===e,isCycleField:"cycle_fields"===e,cycleFieldNames:(t.cycle_fields??[]).map(e=>e.name).filter(Boolean),resultsFieldNames:(t.results_fields??[]).map(e=>e.name).filter(Boolean),onCancel:()=>o(!1),onSave:i=>{const a=[...s];null===n?a.push(i):a[n]=i,l({...t,[e]:a}),o(!1)}})]})};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RawDataEditor.d.ts","sourceRoot":"","sources":["../../../../src/components/tis-editor/editor/RawDataEditor.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAA2B,UAAU,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"RawDataEditor.d.ts","sourceRoot":"","sources":["../../../../src/components/tis-editor/editor/RawDataEditor.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAA2B,UAAU,EAAE,MAAM,UAAU,CAAC;AAGpE,MAAM,WAAW,kBAAkB;IAC/B,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;CACxC;AAID,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA0GtD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import{InputText}from"primereact/inputtext";import{Button}from"primereact/button";import{Checkbox}from"primereact/checkbox";import{FormSection}from"../../forms/FormSection";import{FormRow}from"../../forms/FormRow";const emptyRawData=()=>({blob_name:"trace",columns:{}});export const RawDataEditor=({method:e,onChange:
|
|
1
|
+
import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import{InputText}from"primereact/inputtext";import{Button}from"primereact/button";import{Checkbox}from"primereact/checkbox";import{FormSection}from"../../forms/FormSection";import{FormRow}from"../../forms/FormRow";import{VariableInput,rawSourceCatalog}from"../../varpick";const emptyRawData=()=>({blob_name:"trace",columns:{}});export const RawDataEditor=({method:e,onChange:o})=>{const n=e.raw_data,t=!!n,r=n=>{o({...e,raw_data:n})},a=(e,o)=>{n&&r({...n,columns:{...n.columns,[e]:o}})};return _jsxs(FormSection,{title:"Raw Data",description:"Columnar blob shape captured per cycle under raw_data/. Required only when the method records DAQ traces.",actions:_jsx(Checkbox,{checked:t,onChange:e=>r(e.checked?emptyRawData():null)}),children:[!t&&_jsx("small",{children:"Raw data capture disabled. Tick the box above to enable."}),t&&n&&_jsxs(_Fragment,{children:[_jsx(FormRow,{label:"Blob name",required:!0,hint:"Base filename under raw_data/, no extension.",children:_jsx(InputText,{value:n.blob_name,onChange:e=>r({...n,blob_name:e.target.value})})}),_jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",marginTop:"0.75rem"},children:[_jsx("strong",{children:"Columns"}),_jsx(Button,{label:"Add column",icon:"pi pi-plus",size:"small",onClick:()=>{if(!n)return;let e="column",o=1;for(;n.columns[`${e}${o}`];)o++;r({...n,columns:{...n.columns,[`${e}${o}`]:{source:"time"}}})}})]}),0===Object.keys(n.columns).length&&_jsx("small",{children:"No columns defined."}),Object.entries(n.columns).map(([e,o])=>_jsxs("div",{style:{display:"grid",gridTemplateColumns:"1fr 1.5fr 1.5fr 2rem",gap:"0.5rem",marginTop:"0.25rem",alignItems:"center"},children:[_jsx(InputText,{placeholder:"column name",defaultValue:e,onBlur:o=>((e,o)=>{if(!n||!o.trim()||o===e)return;if(n.columns[o])return;const t={...n.columns};t[o]=t[e],delete t[e],r({...n,columns:t})})(e,o.target.value.trim())}),_jsx(VariableInput,{placeholder:"source (time / ni.<daq>.channels.<name> / derived)",value:o.source,onChange:n=>a(e,{...o,source:n}),catalog:()=>rawSourceCatalog(),ariaLabel:`Choose the source for column ${e}`,pickerTitle:"Column source",pickerHint:"A DAQ channel is named ni.<daq>.channels.<name> and is not listed here — the editor has no channel catalog, so type it."}),_jsx(InputText,{placeholder:"formula (only when source=derived)",value:o.formula??"",onChange:n=>a(e,{...o,formula:n.target.value||void 0}),disabled:"derived"!==o.source}),_jsx(Button,{icon:"pi pi-trash",className:"p-button-text p-button-danger p-button-sm",onClick:()=>(e=>{if(!n)return;if(!window.confirm(`Remove column "${e}"?`))return;const o={...n.columns};delete o[e],r({...n,columns:o})})(e),"aria-label":"Remove column"})]},e))]})]})};
|
|
@@ -15,6 +15,13 @@ export interface TestFieldDialogProps {
|
|
|
15
15
|
/** Candidate target field names for an aggregate's `of`, by source. */
|
|
16
16
|
cycleFieldNames?: string[];
|
|
17
17
|
resultsFieldNames?: string[];
|
|
18
|
+
/**
|
|
19
|
+
* True when this field belongs to `cycle_fields`. Only there does Source
|
|
20
|
+
* have two possible producers — a GM tag read at record time, or the
|
|
21
|
+
* sequence storing a value under this column's NAME — so only there is the
|
|
22
|
+
* picker a producer picker rather than a variable list.
|
|
23
|
+
*/
|
|
24
|
+
isCycleField?: boolean;
|
|
18
25
|
}
|
|
19
26
|
export declare const TestFieldDialog: React.FC<TestFieldDialogProps>;
|
|
20
27
|
//# sourceMappingURL=TestFieldDialog.d.ts.map
|