@adcops/autocore-react 3.5.7 → 3.5.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/components/forms/useEditDraft.d.ts +49 -0
  2. package/dist/components/forms/useEditDraft.d.ts.map +1 -0
  3. package/dist/components/forms/useEditDraft.js +1 -0
  4. package/dist/components/index.d.ts +2 -0
  5. package/dist/components/index.d.ts.map +1 -1
  6. package/dist/components/index.js +1 -1
  7. package/dist/components/tis/TestDataView.d.ts +8 -0
  8. package/dist/components/tis/TestDataView.d.ts.map +1 -1
  9. package/dist/components/tis/TestDataView.js +1 -1
  10. package/dist/components/tis/TestRawDataView.d.ts.map +1 -1
  11. package/dist/components/tis/TestRawDataView.js +1 -1
  12. package/dist/components/tis/chartViews.d.ts +57 -0
  13. package/dist/components/tis/chartViews.d.ts.map +1 -0
  14. package/dist/components/tis/chartViews.js +1 -0
  15. package/dist/components/tis-editor/editor/ChartViewDialog.d.ts.map +1 -1
  16. package/dist/components/tis-editor/editor/ChartViewDialog.js +1 -1
  17. package/dist/components/tis-editor/editor/TestFieldDialog.d.ts.map +1 -1
  18. package/dist/components/tis-editor/editor/TestFieldDialog.js +1 -1
  19. package/dist/components/tis-editor/editor/ViewsEditor.d.ts.map +1 -1
  20. package/dist/components/tis-editor/editor/ViewsEditor.js +1 -1
  21. package/dist/components/tis-editor/types.d.ts +6 -0
  22. package/dist/components/tis-editor/types.d.ts.map +1 -1
  23. package/package.json +3 -1
  24. package/src/components/forms/useEditDraft.ts +0 -0
  25. package/src/components/index.ts +3 -0
  26. package/src/components/tis/TestDataView.tsx +16 -10
  27. package/src/components/tis/TestRawDataView.tsx +6 -7
  28. package/src/components/tis/chartViews.ts +104 -0
  29. package/src/components/tis-editor/editor/ChartViewDialog.tsx +24 -10
  30. package/src/components/tis-editor/editor/TestFieldDialog.tsx +25 -12
  31. package/src/components/tis-editor/editor/ViewsEditor.tsx +31 -5
  32. package/src/components/tis-editor/types.ts +6 -0
  33. package/tools/tests/dist/tis-editor.entry.css +90 -0
  34. package/tools/tests/dist/tis-editor.entry.js +41431 -0
  35. package/tools/tests/tis-editor.entry.tsx +46 -0
  36. package/tools/tests/tis-editor.test.mjs +133 -0
  37. package/tools/tests/vite.config.mjs +30 -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';
@@ -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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"}
@@ -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";
@@ -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":"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"}
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;AAS5D,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,CAqJ1D,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:n="60vh"}=e,i=useRef(null),c=useMemo(()=>{const e=[];for(const[t,r]of Object.entries(o?.views??{}))"raw_trace"===r.type&&e.push({name:t,view:r});return e},[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:()=>i.current?.resetZoom?.()})]}),_jsx(EnvelopeMetaStrip,{envelope:j}),_jsxs("div",{style:{flex:1,minHeight:0,height:n,position:"relative"},children:[f&&_jsx(Overlay,{children:"Loading raw data…"}),v&&_jsx(Overlay,{children:v}),_&&!f&&!v&&_jsx(Line,{ref:i,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(" / ")??"";
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))}
@@ -1 +1 @@
1
- {"version":3,"file":"ChartViewDialog.d.ts","sourceRoot":"","sources":["../../../../src/components/tis-editor/editor/ChartViewDialog.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAA0B,SAAS,EAAE,MAAM,UAAU,CAAC;AAiBlE,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,iEAAiE;IACjE,UAAU,EAAE,MAAM,EAAE,CAAC;CACxB;AAQD,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CA0J1D,CAAC"}
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;AAiBlE,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,iEAAiE;IACjE,UAAU,EAAE,MAAM,EAAE,CAAC;CACxB;AAQD,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAuK1D,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:l,onCancel:t,onSave:a,knownKeys:i,siblingIds:n})=>{const[s,r]=useState(""),[o,u]=useState(blank()),[m,c]=useState(null);useEffect(()=>{e&&(r(l?.viewId??""),u(l?JSON.parse(JSON.stringify(l.view)):blank()),c(null))},[e,l]);const d="raw_trace"===o.type,p=d?"column":"field",x=e=>{u({...o,x:{...o.x,...e}})},_=(e,l)=>{const t=[...o.y];t[e]={...t[e],...l},u({...o,y:t})};return _jsxs(Dialog,{header:l?`Edit view: ${l.viewId}`:"New chart view",visible:e,onHide:t,style:{width:"42rem"},children:[m&&_jsx("div",{style:{color:"#dc2626",marginBottom:"0.5rem"},children:m}),_jsx(FormRow,{label:"View ID",required:!0,hint:"Stable key (e.g. cof_scatter). Cannot collide with other views.",children:_jsx(InputText,{value:s,onChange:e=>r(e.target.value)})}),_jsx(FormRow,{label:"Title",children:_jsx(InputText,{value:o.title??"",onChange:e=>u({...o,title:e.target.value})})}),_jsx(FormRow,{label:"Type",required:!0,children:_jsx(Dropdown,{value:o.type,options:VIEW_TYPES,onChange:e=>u({...o,type:e.value})})}),_jsx(FormRow,{label:d?"X column":"X field",required:!0,children:_jsx(InputText,{value:o.x[p]??"",onChange:e=>x({[p]:e.target.value}),list:"known-keys"})}),_jsx(FormRow,{label:"X label",children:_jsx(InputText,{value:o.x.label??"",onChange:e=>x({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:o.x_decimals??null,onValueChange:e=>{const l={...o};null==e.value?delete l.x_decimals:l.x_decimals=e.value,u(l)},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({...o,y:[...o.y,{[p]:"",label:"",y_axis:"left"}]})}})]}),0===o.y.length&&_jsx("small",{children:"No series — add at least one."}),o.y.map((e,l)=>_jsxs("div",{style:{display:"grid",gridTemplateColumns:"1fr 1fr 6rem 2rem",gap:"0.5rem",marginBottom:"0.25rem",alignItems:"center"},children:[_jsx(InputText,{placeholder:d?"column":"field",value:e[p]??"",onChange:e=>_(l,{[p]:e.target.value}),list:"known-keys"}),_jsx(InputText,{placeholder:"label",value:e.label??"",onChange:e=>_(l,{label:e.target.value})}),_jsx(Dropdown,{value:e.y_axis??"left",options:Y_AXES,onChange:e=>_(l,{y_axis:e.value})}),_jsx(Button,{icon:"pi pi-trash",className:"p-button-text p-button-danger p-button-sm",onClick:()=>(e=>{u({...o,y:o.y.filter((l,t)=>t!==e)})})(l),"aria-label":"Remove series"})]},l)),_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:t}),_jsx(Button,{label:"Save",onClick:()=>{const e=s.trim()?n.includes(s)&&s!==l?.viewId?`A view named "${s}" already exists.`:null:"View ID is required.";e?c(e):a(s,o)}})]})]})};
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";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})=>{const{draft:n,setDraft:s,token:o}=useEditDraft(e,t?.viewId??"",()=>({viewId:t?.viewId??"",view:t?JSON.parse(JSON.stringify(t.view)):blank()})),u=n.viewId,m=n.view,d=e=>s(t=>({...t,view:e})),[c,p]=useState(null);useEffect(()=>{p(null)},[o]);const x="raw_trace"===m.type,_=x?"column":"field",v=e=>{d({...m,x:{...m.x,...e}})},w=(e,t)=>{const l=[...m.y];l[e]={...l[e],...t},d({...m,y:l})};return _jsxs(Dialog,{header:t?`Edit view: ${t.viewId}`:"New chart view",visible:e,onHide:l,style:{width:"42rem"},children:[c&&_jsx("div",{style:{color:"#dc2626",marginBottom:"0.5rem"},children:c}),_jsx(FormRow,{label:"View ID",required:!0,hint:"Stable key (e.g. cof_scatter). Cannot collide with other views.",children:_jsx(InputText,{value:u,onChange:e=>{return t=e.target.value,s(e=>({...e,viewId:t}));var t}})}),_jsx(FormRow,{label:"Title",children:_jsx(InputText,{value:m.title??"",onChange:e=>d({...m,title:e.target.value})})}),_jsx(FormRow,{label:"Type",required:!0,children:_jsx(Dropdown,{value:m.type,options:VIEW_TYPES,onChange:e=>d({...m,type:e.value})})}),_jsx(FormRow,{label:x?"X column":"X field",required:!0,children:_jsx(InputText,{value:m.x[_]??"",onChange:e=>v({[_]:e.target.value}),list:"known-keys"})}),_jsx(FormRow,{label:"X label",children:_jsx(InputText,{value:m.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:m.x_decimals??null,onValueChange:e=>{const t={...m};null==e.value?delete t.x_decimals:t.x_decimals=e.value,d(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:()=>{d({...m,y:[...m.y,{[_]:"",label:"",y_axis:"left"}]})}})]}),0===m.y.length&&_jsx("small",{children:"No series — add at least one."}),m.y.map((e,t)=>_jsxs("div",{style:{display:"grid",gridTemplateColumns:"1fr 1fr 6rem 2rem",gap:"0.5rem",marginBottom:"0.25rem",alignItems:"center"},children:[_jsx(InputText,{placeholder:x?"column":"field",value:e[_]??"",onChange:e=>w(t,{[_]:e.target.value}),list:"known-keys"}),_jsx(InputText,{placeholder:"label",value:e.label??"",onChange:e=>w(t,{label:e.target.value})}),_jsx(Dropdown,{value:e.y_axis??"left",options:Y_AXES,onChange:e=>w(t,{y_axis:e.value})}),_jsx(Button,{icon:"pi pi-trash",className:"p-button-text p-button-danger p-button-sm",onClick:()=>(e=>{d({...m,y:m.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=u.trim()?r.includes(u)&&u!==t?.viewId?`A view named "${u}" already exists.`:null:"View ID is required.";e?p(e):a(u,m)}})]})]})};
@@ -1 +1 @@
1
- {"version":3,"file":"TestFieldDialog.d.ts","sourceRoot":"","sources":["../../../../src/components/tis-editor/editor/TestFieldDialog.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,SAAS,EAA2C,MAAM,UAAU,CAAC;AAkDnF,MAAM,WAAW,oBAAoB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,SAAS,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IACnC,8EAA8E;IAC9E,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB;8CAC0C;IAC1C,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;0EACsE;IACtE,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,uEAAuE;IACvE,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;CAChC;AAID,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAuT1D,CAAC"}
1
+ {"version":3,"file":"TestFieldDialog.d.ts","sourceRoot":"","sources":["../../../../src/components/tis-editor/editor/TestFieldDialog.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,SAAS,EAA2C,MAAM,UAAU,CAAC;AAkDnF,MAAM,WAAW,oBAAoB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,SAAS,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IACnC,8EAA8E;IAC9E,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB;8CAC0C;IAC1C,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;0EACsE;IACtE,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,uEAAuE;IACvE,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;CAChC;AAID,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAmU1D,CAAC"}
@@ -1 +1 @@
1
- import{jsx as _jsx,Fragment as _Fragment,jsxs as _jsxs}from"react/jsx-runtime";import{useContext,useEffect,useMemo,useState}from"react";import{Dialog}from"primereact/dialog";import{Button}from"primereact/button";import{InputText}from"primereact/inputtext";import{InputTextarea}from"primereact/inputtextarea";import{Dropdown}from"primereact/dropdown";import{Checkbox}from"primereact/checkbox";import{InputNumber}from"primereact/inputnumber";import{FormRow}from"../../forms/FormRow";import{boundText,parseBound,boundInvalid}from"../../tis/TestFieldRow";import{AutoCoreTagContext}from"../../../core/AutoCoreTagContext";const FIELD_TYPES=[{label:"string",value:"string"},{label:"i32",value:"i32"},{label:"i64",value:"i64"},{label:"u32",value:"u32"},{label:"u64",value:"u64"},{label:"f32",value:"f32"},{label:"f64",value:"f64"},{label:"bool",value:"bool"}],AGG_FNS=[{label:"— none (analysis-fed) —",value:""},{label:"avg",value:"avg"},{label:"min",value:"min"},{label:"max",value:"max"},{label:"stddev",value:"stddev"},{label:"count (how many went into the rollup)",value:"count"}],AGG_FROMS=[{label:"cycle field (every cycle, every test)",value:"cycle_fields"},{label:"result (one value per test)",value:"results"}],COUNT_CHOICES=[{label:"cycles in this test",value:"test_cycles",scope:"test",from:"cycle_fields"},{label:"cycles for this sample, all tests",value:"project_cycles",scope:"project",from:"cycle_fields"},{label:"tests for this sample",value:"project_tests",scope:"project",from:"results"}],AGG_SCOPES=[{label:"this test only",value:"test"},{label:"this sample, every test in the project",value:"project"}],blank={name:"",type:"f32"};export const TestFieldDialog=({visible:e,initial:t,onCancel:a,onSave:o,siblingNames:l,isResultsField:n=!1,isCycleConfigField:r=!1,cycleFieldNames:i=[],resultsFieldNames:s=[]})=>{const[u,c]=useState(blank),[d,m]=useState(""),[h,p]=useState(null),{scales:g}=useContext(AutoCoreTagContext),f=useMemo(()=>Object.keys(g??{}).sort().map(e=>({label:e,value:e})),[g]);useEffect(()=>{e&&(c(t?{...t}:{...blank}),m(null==t?.default?"":String(t.default)),p(null))},[e,t]);const v=u.aggregate,b=v?.from??"cycle_fields",x=v?.scope??"test",_=COUNT_CHOICES.find(e=>e.scope===x&&e.from===b)?.value??"test_cycles",y=("results"===b?s:i).filter(e=>e&&e!==u.name).map(e=>({label:e,value:e}));return _jsxs(Dialog,{header:t?`Edit field: ${t.name}`:"New field",visible:e,onHide:a,style:{width:"36rem"},children:[h&&_jsx("div",{style:{color:"#dc2626",marginBottom:"0.75rem"},children:h}),_jsx(FormRow,{label:"Name",required:!0,hint:"Wire-format key. Also the column name in CSV exports.",children:_jsx(InputText,{value:u.name,onChange:e=>c({...u,name:e.target.value})})}),_jsx(FormRow,{label:"Type",required:!0,children:_jsx(Dropdown,{value:u.type,options:FIELD_TYPES,onChange:e=>c({...u,type:e.value}),editable:!0})}),_jsx(FormRow,{label:"Quantity",hint:"Ties this field to a row of the machine's units.json, so it follows the operator's Metric/Imperial choice and takes its unit label from the active system. Set this in preference to Units/Scale, which are fixed.",children:_jsx(Dropdown,{value:u.quantity??"",options:f,onChange:e=>c({...u,quantity:e.value||void 0}),placeholder:"— none (fixed Units/Scale below) —",showClear:!0,editable:!0})}),_jsx(FormRow,{label:"Units",hint:"Fixed display label appended to form labels (e.g. m/s). Ignored when Quantity is set — the active unit system supplies the label.",children:_jsx(InputText,{value:u.units??"",onChange:e=>c({...u,units:e.target.value||void 0})})}),_jsx(FormRow,{label:"Label",hint:"Pretty form label. Falls back to name when empty.",children:_jsx(InputText,{value:u.label??"",onChange:e=>c({...u,label:e.target.value||void 0})})}),_jsx(FormRow,{label:"Required",hint:r?"Blocks the machine until the operator fills this in — tis.cycle_ready stays false and start_test is refused. This is what stops an unannotated row from being recorded.":void 0,children:_jsx(Checkbox,{checked:!!u.required,onChange:e=>c({...u,required:!!e.checked})})}),r&&_jsx(FormRow,{label:"Autoclear",hint:"Clear the operator's entry once a row has recorded it, so the next row can't inherit a stale value. Fires after each cycle under 'cycle' scope, at the end of the run under 'run' scope. Pair with Required — on its own it turns stale data into silently missing data.",children:_jsx(Checkbox,{checked:!!u.autoclear,onChange:e=>c({...u,autoclear:!!e.checked})})}),_jsx(FormRow,{label:"Source",hint:"Optional gm.* variable to bind this field to.",children:_jsx(InputText,{value:u.source??"",onChange:e=>c({...u,source:e.target.value||void 0}),placeholder:"gm.<variable_name>"})}),_jsx(FormRow,{label:"Scale",hint:"display = raw × scale. Leave blank for 1.0 (no conversion).",children:_jsx(InputNumber,{value:u.scale??null,onValueChange:e=>c({...u,scale:"number"==typeof e.value?e.value:void 0}),mode:"decimal",minFractionDigits:0,maxFractionDigits:9})}),_jsx(FormRow,{label:"Min",hint:"Optional lower bound the operator can enter (display units). Blank = no minimum. Or bind it to the machine with an FQDN token like ${gm.press_force_min_n} — for a bound that moves, e.g. a load-cell force ceiling.",children:_jsx(InputText,{value:boundText(u.min),onChange:e=>c({...u,min:parseBound(e.target.value)}),className:boundInvalid(u.min)?"p-invalid":"",placeholder:"number or ${gm.…}"})}),_jsx(FormRow,{label:"Max",hint:"Optional upper bound the operator can enter (display units). Blank = no maximum. Or bind it to the machine with an FQDN token like ${gm.press_force_max_n}.",children:_jsx(InputText,{value:boundText(u.max),onChange:e=>c({...u,max:parseBound(e.target.value)}),className:boundInvalid(u.max)?"p-invalid":"",placeholder:"number or ${gm.…}"})}),_jsx(FormRow,{label:"Default",hint:"Applied every time the method loads (operator can override). A literal (display units) like 5, or an FQDN token like ${gm.safe_speed} that snapshots that value on load.",children:_jsx(InputText,{value:d,onChange:e=>m(e.target.value),placeholder:"e.g. 5 or ${gm.safe_speed}"})}),n&&_jsxs(_Fragment,{children:[_jsx("div",{style:{borderTop:"1px solid #e5e7eb",margin:"0.75rem 0 0.25rem"}}),_jsx(FormRow,{label:"Aggregate",hint:"Cross-test rollup. When set, this result is derived server-side over the non-excluded tests sharing the same sample_id — the analysis script does not supply it.",children:_jsx(Dropdown,{value:v?.fn??"",options:AGG_FNS,onChange:e=>(e=>{if(""===e)return void c({...u,aggregate:void 0});if("count"===e)return void c({...u,aggregate:{fn:"count",from:u.aggregate?.from??"cycle_fields",scope:u.aggregate?.scope??"test"}});const t={fn:e,of:u.aggregate?.of,from:u.aggregate?.from??"cycle_fields",scope:u.aggregate?.scope??"test"};c({...u,aggregate:t})})(e.value)})}),v&&"count"===v.fn&&_jsx(FormRow,{label:"Count",hint:"What is being counted. A test's own cycles is the usual choice — it's the number the operator can see in the Cycle Data table.",children:_jsx(Dropdown,{value:_,options:COUNT_CHOICES,onChange:e=>{const t=COUNT_CHOICES.find(t=>t.value===e.value);t&&c({...u,aggregate:{...v,scope:t.scope,from:t.from}})}})}),v&&"count"!==v.fn&&_jsxs(_Fragment,{children:[_jsx(FormRow,{label:"Scope",hint:"How wide the reduction reaches. 'This test only' is the default: a value on a test's own results panel or report describes that test.",children:_jsx(Dropdown,{value:x,options:AGG_SCOPES,onChange:e=>c({...u,aggregate:{...v,scope:e.value}})})}),_jsx(FormRow,{label:"Aggregate from",hint:"Which per-test source the target field is read from.",children:_jsx(Dropdown,{value:b,options:AGG_FROMS,onChange:e=>c({...u,aggregate:{...v,from:e.value}})})}),_jsx(FormRow,{label:"Aggregate of",required:!0,hint:"The field to reduce across tests.",children:_jsx(Dropdown,{value:v.of??null,options:y,onChange:e=>c({...u,aggregate:{...v,of:e.value||void 0}}),editable:!0,placeholder:y.length?"Select a field":`No ${b} defined yet`})})]})]}),_jsx(FormRow,{label:"Description",hint:"Hover tooltip in the form.",children:_jsx(InputTextarea,{rows:2,value:u.description??"",onChange:e=>c({...u,description:e.target.value||void 0})})}),_jsxs("div",{style:{display:"flex",justifyContent:"flex-end",gap:"0.5rem",marginTop:"1rem"},children:[_jsx(Button,{label:"Cancel",className:"p-button-text",onClick:a}),_jsx(Button,{label:"Save",onClick:()=>{const e={...u},a=(e=>{const t=e.trim();if(""!==t){if(t.startsWith("${"))return t;if("true"===t)return!0;if("false"===t)return!1;if(/^-?\d*\.?\d+$/.test(t)){const e=Number(t);if(Number.isFinite(e))return e}return t}})(d);void 0===a?delete e.default:e.default=a;const n=(e=>{if(!e.name.trim())return"Field name is required.";if(!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(e.name))return"Name must be a valid identifier (letters, digits, underscore; cannot start with a digit).";if(l.some(a=>a===e.name&&a!==t?.name))return`A field named "${e.name}" already exists in this array.`;if("number"==typeof e.min&&"number"==typeof e.max&&e.min>e.max)return`Min (${e.min}) cannot be greater than Max (${e.max}).`;for(const t of["min","max"])if(boundInvalid(e[t]))return`${"min"===t?"Min":"Max"} must be a number or an FQDN token like \${gm.some_var} — "${e[t]}" is neither.`;return e.aggregate&&"count"!==e.aggregate.fn&&!e.aggregate.of?.trim()?`Aggregate "${e.aggregate.fn}" needs a target field (the field to ${e.aggregate.fn} across tests).`:null})(e);n?p(n):o(e)}})]})]})};
1
+ import{jsx as _jsx,Fragment as _Fragment,jsxs as _jsxs}from"react/jsx-runtime";import{useContext,useEffect,useMemo,useState}from"react";import{Dialog}from"primereact/dialog";import{Button}from"primereact/button";import{InputText}from"primereact/inputtext";import{InputTextarea}from"primereact/inputtextarea";import{Dropdown}from"primereact/dropdown";import{Checkbox}from"primereact/checkbox";import{InputNumber}from"primereact/inputnumber";import{FormRow}from"../../forms/FormRow";import{useEditDraft}from"../../forms/useEditDraft";import{boundText,parseBound,boundInvalid}from"../../tis/TestFieldRow";import{AutoCoreTagContext}from"../../../core/AutoCoreTagContext";const FIELD_TYPES=[{label:"string",value:"string"},{label:"i32",value:"i32"},{label:"i64",value:"i64"},{label:"u32",value:"u32"},{label:"u64",value:"u64"},{label:"f32",value:"f32"},{label:"f64",value:"f64"},{label:"bool",value:"bool"}],AGG_FNS=[{label:"— none (analysis-fed) —",value:""},{label:"avg",value:"avg"},{label:"min",value:"min"},{label:"max",value:"max"},{label:"stddev",value:"stddev"},{label:"count (how many went into the rollup)",value:"count"}],AGG_FROMS=[{label:"cycle field (every cycle, every test)",value:"cycle_fields"},{label:"result (one value per test)",value:"results"}],COUNT_CHOICES=[{label:"cycles in this test",value:"test_cycles",scope:"test",from:"cycle_fields"},{label:"cycles for this sample, all tests",value:"project_cycles",scope:"project",from:"cycle_fields"},{label:"tests for this sample",value:"project_tests",scope:"project",from:"results"}],AGG_SCOPES=[{label:"this test only",value:"test"},{label:"this sample, every test in the project",value:"project"}],blank={name:"",type:"f32"};export const TestFieldDialog=({visible:e,initial:t,onCancel:a,onSave:o,siblingNames:l,isResultsField:r=!1,isCycleConfigField:n=!1,cycleFieldNames:i=[],resultsFieldNames:s=[]})=>{const{draft:u,setDraft:d,token:c}=useEditDraft(e,t?.name??"",()=>({field:t?{...t}:{...blank},defaultText:null==t?.default?"":String(t.default)})),m=u.field,h=u.defaultText,p=e=>d(t=>({...t,field:e})),[f,g]=useState(null);useEffect(()=>{g(null)},[c]);const{scales:v}=useContext(AutoCoreTagContext),b=useMemo(()=>Object.keys(v??{}).sort().map(e=>({label:e,value:e})),[v]),x=m.aggregate,_=x?.from??"cycle_fields",y=x?.scope??"test",j=COUNT_CHOICES.find(e=>e.scope===y&&e.from===_)?.value??"test_cycles",w=("results"===_?s:i).filter(e=>e&&e!==m.name).map(e=>({label:e,value:e}));return _jsxs(Dialog,{header:t?`Edit field: ${t.name}`:"New field",visible:e,onHide:a,style:{width:"36rem"},children:[f&&_jsx("div",{style:{color:"#dc2626",marginBottom:"0.75rem"},children:f}),_jsx(FormRow,{label:"Name",required:!0,hint:"Wire-format key. Also the column name in CSV exports.",children:_jsx(InputText,{value:m.name,onChange:e=>p({...m,name:e.target.value})})}),_jsx(FormRow,{label:"Type",required:!0,children:_jsx(Dropdown,{value:m.type,options:FIELD_TYPES,onChange:e=>p({...m,type:e.value}),editable:!0})}),_jsx(FormRow,{label:"Quantity",hint:"Ties this field to a row of the machine's units.json, so it follows the operator's Metric/Imperial choice and takes its unit label from the active system. Set this in preference to Units/Scale, which are fixed.",children:_jsx(Dropdown,{value:m.quantity??"",options:b,onChange:e=>p({...m,quantity:e.value||void 0}),placeholder:"— none (fixed Units/Scale below) —",showClear:!0,editable:!0})}),_jsx(FormRow,{label:"Units",hint:"Fixed display label appended to form labels (e.g. m/s). Ignored when Quantity is set — the active unit system supplies the label.",children:_jsx(InputText,{value:m.units??"",onChange:e=>p({...m,units:e.target.value||void 0})})}),_jsx(FormRow,{label:"Label",hint:"Pretty form label. Falls back to name when empty.",children:_jsx(InputText,{value:m.label??"",onChange:e=>p({...m,label:e.target.value||void 0})})}),_jsx(FormRow,{label:"Required",hint:n?"Blocks the machine until the operator fills this in — tis.cycle_ready stays false and start_test is refused. This is what stops an unannotated row from being recorded.":void 0,children:_jsx(Checkbox,{checked:!!m.required,onChange:e=>p({...m,required:!!e.checked})})}),n&&_jsx(FormRow,{label:"Autoclear",hint:"Clear the operator's entry once a row has recorded it, so the next row can't inherit a stale value. Fires after each cycle under 'cycle' scope, at the end of the run under 'run' scope. Pair with Required — on its own it turns stale data into silently missing data.",children:_jsx(Checkbox,{checked:!!m.autoclear,onChange:e=>p({...m,autoclear:!!e.checked})})}),_jsx(FormRow,{label:"Source",hint:"Optional gm.* variable to bind this field to.",children:_jsx(InputText,{value:m.source??"",onChange:e=>p({...m,source:e.target.value||void 0}),placeholder:"gm.<variable_name>"})}),_jsx(FormRow,{label:"Scale",hint:"display = raw × scale. Leave blank for 1.0 (no conversion).",children:_jsx(InputNumber,{value:m.scale??null,onValueChange:e=>p({...m,scale:"number"==typeof e.value?e.value:void 0}),mode:"decimal",minFractionDigits:0,maxFractionDigits:9})}),_jsx(FormRow,{label:"Min",hint:"Optional lower bound the operator can enter (display units). Blank = no minimum. Or bind it to the machine with an FQDN token like ${gm.press_force_min_n} — for a bound that moves, e.g. a load-cell force ceiling.",children:_jsx(InputText,{value:boundText(m.min),onChange:e=>p({...m,min:parseBound(e.target.value)}),className:boundInvalid(m.min)?"p-invalid":"",placeholder:"number or ${gm.…}"})}),_jsx(FormRow,{label:"Max",hint:"Optional upper bound the operator can enter (display units). Blank = no maximum. Or bind it to the machine with an FQDN token like ${gm.press_force_max_n}.",children:_jsx(InputText,{value:boundText(m.max),onChange:e=>p({...m,max:parseBound(e.target.value)}),className:boundInvalid(m.max)?"p-invalid":"",placeholder:"number or ${gm.…}"})}),_jsx(FormRow,{label:"Default",hint:"Applied every time the method loads (operator can override). A literal (display units) like 5, or an FQDN token like ${gm.safe_speed} that snapshots that value on load.",children:_jsx(InputText,{value:h,onChange:e=>(e=>d(t=>({...t,defaultText:e})))(e.target.value),placeholder:"e.g. 5 or ${gm.safe_speed}"})}),r&&_jsxs(_Fragment,{children:[_jsx("div",{style:{borderTop:"1px solid #e5e7eb",margin:"0.75rem 0 0.25rem"}}),_jsx(FormRow,{label:"Aggregate",hint:"Cross-test rollup. When set, this result is derived server-side over the non-excluded tests sharing the same sample_id — the analysis script does not supply it.",children:_jsx(Dropdown,{value:x?.fn??"",options:AGG_FNS,onChange:e=>(e=>{if(""===e)return void p({...m,aggregate:void 0});if("count"===e)return void p({...m,aggregate:{fn:"count",from:m.aggregate?.from??"cycle_fields",scope:m.aggregate?.scope??"test"}});const t={fn:e,of:m.aggregate?.of,from:m.aggregate?.from??"cycle_fields",scope:m.aggregate?.scope??"test"};p({...m,aggregate:t})})(e.value)})}),x&&"count"===x.fn&&_jsx(FormRow,{label:"Count",hint:"What is being counted. A test's own cycles is the usual choice — it's the number the operator can see in the Cycle Data table.",children:_jsx(Dropdown,{value:j,options:COUNT_CHOICES,onChange:e=>{const t=COUNT_CHOICES.find(t=>t.value===e.value);t&&p({...m,aggregate:{...x,scope:t.scope,from:t.from}})}})}),x&&"count"!==x.fn&&_jsxs(_Fragment,{children:[_jsx(FormRow,{label:"Scope",hint:"How wide the reduction reaches. 'This test only' is the default: a value on a test's own results panel or report describes that test.",children:_jsx(Dropdown,{value:y,options:AGG_SCOPES,onChange:e=>p({...m,aggregate:{...x,scope:e.value}})})}),_jsx(FormRow,{label:"Aggregate from",hint:"Which per-test source the target field is read from.",children:_jsx(Dropdown,{value:_,options:AGG_FROMS,onChange:e=>p({...m,aggregate:{...x,from:e.value}})})}),_jsx(FormRow,{label:"Aggregate of",required:!0,hint:"The field to reduce across tests.",children:_jsx(Dropdown,{value:x.of??null,options:w,onChange:e=>p({...m,aggregate:{...x,of:e.value||void 0}}),editable:!0,placeholder:w.length?"Select a field":`No ${_} defined yet`})})]})]}),_jsx(FormRow,{label:"Description",hint:"Hover tooltip in the form.",children:_jsx(InputTextarea,{rows:2,value:m.description??"",onChange:e=>p({...m,description:e.target.value||void 0})})}),_jsxs("div",{style:{display:"flex",justifyContent:"flex-end",gap:"0.5rem",marginTop:"1rem"},children:[_jsx(Button,{label:"Cancel",className:"p-button-text",onClick:a}),_jsx(Button,{label:"Save",onClick:()=>{const e={...m},a=(e=>{const t=e.trim();if(""!==t){if(t.startsWith("${"))return t;if("true"===t)return!0;if("false"===t)return!1;if(/^-?\d*\.?\d+$/.test(t)){const e=Number(t);if(Number.isFinite(e))return e}return t}})(h);void 0===a?delete e.default:e.default=a;const r=(e=>{if(!e.name.trim())return"Field name is required.";if(!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(e.name))return"Name must be a valid identifier (letters, digits, underscore; cannot start with a digit).";if(l.some(a=>a===e.name&&a!==t?.name))return`A field named "${e.name}" already exists in this array.`;if("number"==typeof e.min&&"number"==typeof e.max&&e.min>e.max)return`Min (${e.min}) cannot be greater than Max (${e.max}).`;for(const t of["min","max"])if(boundInvalid(e[t]))return`${"min"===t?"Min":"Max"} must be a number or an FQDN token like \${gm.some_var} — "${e[t]}" is neither.`;return e.aggregate&&"count"!==e.aggregate.fn&&!e.aggregate.of?.trim()?`Aggregate "${e.aggregate.fn}" needs a target field (the field to ${e.aggregate.fn} across tests).`:null})(e);r?g(r):o(e)}})]})]})};
@@ -1 +1 @@
1
- {"version":3,"file":"ViewsEditor.d.ts","sourceRoot":"","sources":["../../../../src/components/tis-editor/editor/ViewsEditor.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAwB,UAAU,EAAE,MAAM,UAAU,CAAC;AAEjE,MAAM,WAAW,gBAAgB;IAC7B,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;CACxC;AAQD,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAwFlD,CAAC"}
1
+ {"version":3,"file":"ViewsEditor.d.ts","sourceRoot":"","sources":["../../../../src/components/tis-editor/editor/ViewsEditor.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAwB,UAAU,EAAE,MAAM,UAAU,CAAC;AAEjE,MAAM,WAAW,gBAAgB;IAC7B,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;CACxC;AAQD,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAiHlD,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{ChartViewDialog}from"./ChartViewDialog";export const ViewsEditor=({method:e,onChange:t})=>{const i=e.views??{},a=Object.entries(i).map(([e,t])=>({id:e,title:t.title??"",type:t.type??""})),[s,n]=useState(!1),[o,r]=useState(null),l=[...(e.project_fields??[]).map(e=>e.name),...(e.config_fields??[]).map(e=>e.name),...(e.cycle_config_fields??[]).map(e=>e.name),...(e.cycle_fields??[]).map(e=>e.name),...(e.results_fields??[]).map(e=>e.name),...Object.keys(e.raw_data?.columns??{}),"cycle_index","timestamp"];return _jsxs(_Fragment,{children:[_jsx(FormSection,{title:"Views",description:"Named chart definitions rendered by <TestDataView> (cycle_scatter) and <TestRawDataView> (raw_trace).",actions:_jsx(Button,{label:"Add view",icon:"pi pi-plus",size:"small",onClick:()=>{r(null),n(!0)}}),children:_jsxs(DataTable,{value:a,dataKey:"id",emptyMessage:"No views defined.",children:[_jsx(Column,{field:"id",header:"View ID"}),_jsx(Column,{field:"title",header:"Title"}),_jsx(Column,{field:"type",header:"Type",style:{width:"8rem"}}),_jsx(Column,{header:"",body:a=>_jsxs("div",{style:{display:"flex",gap:"0.25rem"},children:[_jsx(Button,{icon:"pi pi-pencil",className:"p-button-text p-button-sm",onClick:()=>{return e=a.id,r(e),void n(!0);var e},"aria-label":"Edit"}),_jsx(Button,{icon:"pi pi-trash",className:"p-button-text p-button-danger p-button-sm",onClick:()=>(a=>{if(!window.confirm(`Remove view "${a}"?`))return;const s={...i};delete s[a],t({...e,views:s})})(a.id),"aria-label":"Remove"})]}),style:{width:"6rem"}})]})}),_jsx(ChartViewDialog,{visible:s,initial:o?{viewId:o,view:i[o]}:null,knownKeys:l,siblingIds:Object.keys(i),onCancel:()=>n(!1),onSave:(a,s)=>{const r={...i};o&&o!==a&&delete r[o],r[a]=s,t({...e,views:r}),n(!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{moveView,orderedViews}from"../../tis/chartViews";import{ChartViewDialog}from"./ChartViewDialog";export const ViewsEditor=({method:e,onChange:t})=>{const i=e.views??{},o=orderedViews(i).map(({name:e,view:t})=>({id:e,title:t.title??"",type:t.type??""})),[a,s]=useState(!1),[n,r]=useState(null),l=[...(e.project_fields??[]).map(e=>e.name),...(e.config_fields??[]).map(e=>e.name),...(e.cycle_config_fields??[]).map(e=>e.name),...(e.cycle_fields??[]).map(e=>e.name),...(e.results_fields??[]).map(e=>e.name),...Object.keys(e.raw_data?.columns??{}),"cycle_index","timestamp"],m=(o,a)=>{const s=moveView(i,o,a);s!==i&&t({...e,views:s})};return _jsxs(_Fragment,{children:[_jsx(FormSection,{title:"Views",description:"Named chart definitions rendered by <TestDataView> (cycle_scatter) and <TestRawDataView> (raw_trace). Top to bottom is the order the operator sees in the view picker, and the first one is the chart the Data tab opens on.",actions:_jsx(Button,{label:"Add view",icon:"pi pi-plus",size:"small",onClick:()=>{r(null),s(!0)}}),children:_jsxs(DataTable,{value:o,dataKey:"id",emptyMessage:"No views defined.",children:[_jsx(Column,{field:"id",header:"View ID"}),_jsx(Column,{field:"title",header:"Title"}),_jsx(Column,{field:"type",header:"Type",style:{width:"8rem"}}),_jsx(Column,{header:"",body:(a,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:()=>m(n.rowIndex,-1),"aria-label":"Move up"}),_jsx(Button,{icon:"pi pi-arrow-down",className:"p-button-text p-button-sm",disabled:n.rowIndex===o.length-1,onClick:()=>m(n.rowIndex,1),"aria-label":"Move down"}),_jsx(Button,{icon:"pi pi-pencil",className:"p-button-text p-button-sm",onClick:()=>{return e=a.id,r(e),void s(!0);var e},"aria-label":"Edit"}),_jsx(Button,{icon:"pi pi-trash",className:"p-button-text p-button-danger p-button-sm",onClick:()=>(o=>{if(!window.confirm(`Remove view "${o}"?`))return;const a={...i};delete a[o],t({...e,views:a})})(a.id),"aria-label":"Remove"})]}),style:{width:"10rem"}})]})}),_jsx(ChartViewDialog,{visible:a,initial:n?{viewId:n,view:i[n]}:null,knownKeys:l,siblingIds:Object.keys(i),onCancel:()=>s(!1),onSave:(o,a)=>{const r={...i};n&&n!==o&&delete r[n],r[o]=a,t({...e,views:r}),s(!1)}})]})};
@@ -91,6 +91,12 @@ export interface ChartView {
91
91
  * prints 17-digit ticks.
92
92
  */
93
93
  x_decimals?: number;
94
+ /**
95
+ * Position in the view picker, ascending. Set by the editor's Move
96
+ * up / Move down; see `components/tis/chartViews.ts` for why the order
97
+ * cannot just be the order of the keys.
98
+ */
99
+ order?: number;
94
100
  }
95
101
  export type RawColumnSource = 'time' | 'derived' | string;
96
102
  export interface RawColumn {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/tis-editor/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/tis-editor/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adcops/autocore-react",
3
- "version": "3.5.7",
3
+ "version": "3.5.9",
4
4
  "description": "A React component library for industrial user interfaces.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -12,6 +12,7 @@
12
12
  "generate-docs": "typedoc",
13
13
  "build": "npm run clean && tsc && node ./tools/copy-distribution-files.cjs && npm run build-themes && npm run minify",
14
14
  "build:dev": "npm run clean && tsc && node ./tools/copy-distribution-files.cjs",
15
+ "test:tis-editor": "vite build --config tools/tests/vite.config.mjs && node tools/tests/tis-editor.test.mjs",
15
16
  "dev": "vite",
16
17
  "playground": "vite",
17
18
  "playground:build": "vite build",
@@ -82,6 +83,7 @@
82
83
  "@types/react-dom": "^18.2.7",
83
84
  "@types/react-transition-group": "^4.4.12",
84
85
  "@vitejs/plugin-react": "^6.0.2",
86
+ "jsdom": "^22.1.0",
85
87
  "primereact": "^10.9.7",
86
88
  "rimraf": "^6.0.1",
87
89
  "terser": "^5.44.0",
@@ -38,6 +38,9 @@ export type { TestSetupFormProps } from './tis/TestSetupForm';
38
38
  export { TestSetupView } from './tis/TestSetupView';
39
39
  export type { TestSetupViewProps } from './tis/TestSetupView';
40
40
 
41
+ export { orderedViews, renumberViews, moveView } from './tis/chartViews';
42
+ export type { NamedView, OrderableView } from './tis/chartViews';
43
+
41
44
  export { TestFieldRow } from './tis/TestFieldRow';
42
45
  export type { TestFieldRowProps, CycleConfigScope } from './tis/TestFieldRow';
43
46
 
@@ -47,6 +47,7 @@ import { AutoCoreTagContext } from '../../core/AutoCoreTagContext';
47
47
  import { formatScaled } from '../../core/formatScaled';
48
48
  import type { ScaleConfig } from '../../core/AutoCoreTagTypes';
49
49
  import { useRawCycleData } from './useRawCycleData';
50
+ import { orderedViews } from './chartViews';
50
51
  import { ScienceTable } from './ScienceTable';
51
52
  import type { ScienceColumn } from './ScienceTable';
52
53
 
@@ -171,6 +172,14 @@ export interface ChartView {
171
172
  * table, CSV export and every calculation still see the full value.
172
173
  */
173
174
  x_decimals?: number;
175
+ /**
176
+ * Position in the view picker, ascending — the view with the lowest
177
+ * `order` is the one this panel opens on. Written by the TIS editor's
178
+ * Move up / Move down. See `chartViews.ts`: the keys of `views` arrive
179
+ * sorted by id, so the order an author chose has to be carried
180
+ * explicitly.
181
+ */
182
+ order?: number;
174
183
  /**
175
184
  * Optional shaded X-range bands drawn over the plot, declared per view
176
185
  * in project.json (static). These are drawn on every cycle.
@@ -336,16 +345,13 @@ export const TestDataView: React.FC<TestDataViewProps> = (props) => {
336
345
  const [availableCycles, setAvailableCycles] = useState<number[]>([]);
337
346
  const [selectedCycle, setSelectedCycle] = useState<number | null>(null);
338
347
 
339
- // All views, any type, in declaration order. The dropdown lists
340
- // every one; the chart area dispatches on `view.type` to render
341
- // either a scatter or a raw_trace chart from the appropriate data.
342
- const allViews = useMemo(() => {
343
- const out: { name: string; view: ChartView }[] = [];
344
- for (const [name, v] of Object.entries(schema?.views ?? {})) {
345
- out.push({ name, view: v as ChartView });
346
- }
347
- return out;
348
- }, [schema]);
348
+ // All views, any type, in the author's order (see `orderedViews`). The
349
+ // dropdown lists every one; the chart area dispatches on `view.type` to
350
+ // render either a scatter or a raw_trace chart from the appropriate data.
351
+ const allViews = useMemo(
352
+ () => orderedViews(schema?.views as Record<string, ChartView> | undefined),
353
+ [schema],
354
+ );
349
355
 
350
356
  const [selectedView, setSelectedView] = useState<string | null>(
351
357
  allViews.length > 0 ? allViews[0].name : null,