@adcops/autocore-react 3.6.5 → 3.6.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"ResultHistoryTable.d.ts","sourceRoot":"","sources":["../../../src/components/tis/ResultHistoryTable.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkD,MAAM,OAAO,CAAC;AAWvE,OAAO,0BAA0B,CAAC;AAElC,MAAM,WAAW,uBAAuB;IACpC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAyCD,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CA8lBhE,CAAC"}
1
+ {"version":3,"file":"ResultHistoryTable.d.ts","sourceRoot":"","sources":["../../../src/components/tis/ResultHistoryTable.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkD,MAAM,OAAO,CAAC;AAYvE,OAAO,0BAA0B,CAAC;AAElC,MAAM,WAAW,uBAAuB;IACpC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAkED,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CA+pBhE,CAAC"}
@@ -1 +1 @@
1
- import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React,{useState,useEffect,useContext,useRef}from"react";import{DataTable}from"primereact/datatable";import{Column}from"primereact/column";import{Button}from"primereact/button";import{Badge}from"primereact/badge";import{Menu}from"primereact/menu";import{confirmDialog}from"primereact/confirmdialog";import{EventEmitterContext}from"../../core/EventEmitterContext";import{MessageType}from"../../hub/CommandMessage";import{useTis}from"./TisProvider";import{SampleSummaryPanel}from"./SampleSummaryPanel";import"./ResultHistoryTable.css";const downloadCsvBlob=(e,t)=>{const o=new Blob([t],{type:"text/csv;charset=utf-8;"}),i=URL.createObjectURL(o),s=document.createElement("a");s.href=i,s.download=e,document.body.appendChild(s),s.click(),s.remove(),URL.revokeObjectURL(i)},downloadViaUrl=(e,t)=>{const o=document.createElement("a");o.href=e,o.download=t,document.body.appendChild(o),o.click(),o.remove()};export const ResultHistoryTable=e=>{const t=useTis(),o=e.projectId??t.selection.projectId,i=e.methodId,[s,r]=useState([]),[a,n]=useState(!1),[l,d]=useState(null),[c,p]=useState(null),[u,m]=useState(null),f=useRef(null),[_,h]=useState(null),b=useRef(0),[g,y]=useState(null),{invoke:x}=useContext(EventEmitterContext),w=async()=>{if(o){n(!0);try{const e={project_id:o};i&&(e.method_id=i);const t=await x("tis.list_tests",MessageType.Request,e);t.success&&t.data&&t.data.tests&&r(t.data.tests)}catch(e){}n(!1)}else r([])};useEffect(()=>{w()},[o,i,t.state.activeRunId,t.state.active]),useEffect(()=>{_&&f.current?.show({currentTarget:_.anchor})},[_]);const v=async(e,t)=>{const s=e?.run_id,r=e?.method_id??i;if(!s||!r||!o)return;const a="report"===t?"tis.export_test_csv":"tis.export_test_data_csv",n="report"===t?"test report":"test data";d({runId:s,kind:t});try{const e=await x(a,MessageType.Request,{project_id:o,method_id:r,run_id:s});if(!e?.success)return void alert(`Failed to build ${n} for ${s}`+(e?.error_message?`: ${e.error_message}`:""));const i="string"==typeof e.data?.filename&&e.data.filename?e.data.filename:`${o}_${r}_${s}_${t}.csv`;if("report"===t){const t="string"==typeof e.data?.csv?e.data.csv:"";if(!t)return void alert(`${n} for ${s} is empty.`);downloadCsvBlob(i,t)}else{const t="string"==typeof e.data?.download_url?e.data.download_url:"";if(!t)return void alert(`Server did not return a download URL for ${n}.`);downloadViaUrl(t,i)}}catch(e){alert(`Download failed: ${e instanceof Error?e.message:String(e)}`)}finally{d(null)}},j=async(e,t)=>{const s=e?.run_id,r=e?.method_id??i;if(!s||!r||!o)return;const a="complete"===t?"tis.finish_test":"abandon"===t?"tis.reset_test":"tis.resume_test";y(s);try{const e=await x(a,MessageType.Request,{project_id:o,method_id:r,run_id:s});if(!e?.success)return void alert(`Could not ${t} ${s}`+(e?.error_message?`:\n\n${e.error_message}`:""));await w()}catch(e){alert(`${t} failed: ${e instanceof Error?e.message:String(e)}`)}finally{y(null)}},C=async e=>{if(!o)return;const t="report"===e?"tis.export_project_csv":"tis.export_project_zip",i="report"===e?"project report":"project archive";p(e);try{const s=await x(t,MessageType.Request,{project_id:o});if(!s?.success)return void alert(`Failed to build ${i}`+(s?.error_message?`: ${s.error_message}`:""));const r="string"==typeof s.data?.download_url?s.data.download_url:"";if(!r)return void alert(`Server did not return a download URL for ${i}.`);const a="report"===e?`${o}_project_report.csv`:`${o}_project_archive.zip`,n="string"==typeof s.data?.filename&&s.data.filename?s.data.filename:a;downloadViaUrl(r,n)}catch(e){alert(`Download failed: ${e instanceof Error?e.message:String(e)}`)}finally{p(null)}},T=e=>{const t="string"==typeof e?.sample_id?e.sample_id:"";if(t)return t;const o=e?.config;return o&&"object"==typeof o&&"string"==typeof o.sample_id?o.sample_id:""};return _jsxs("div",{style:{width:"100%",maxWidth:"100%",overflow:"hidden",boxSizing:"border-box"},children:[_jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:"1rem",gap:"0.5rem",flexWrap:"wrap"},children:[_jsx("h3",{style:{margin:0},children:o?`Test History: ${o}${i?` / ${i}`:""}`:"Test History (no project selected)"}),_jsxs("div",{style:{display:"flex",gap:"0.4rem",alignItems:"center"},children:[_jsx(Button,{icon:"report"===c?"pi pi-spin pi-spinner":"pi pi-file",label:"Download Report",size:"small",outlined:!0,disabled:!o||null!==c,onClick:()=>C("report"),tooltip:"Download a CSV report of every test in this project",tooltipOptions:{position:"bottom"}}),_jsx(Button,{icon:"archive"===c?"pi pi-spin pi-spinner":"pi pi-box",label:"Download Archive",size:"small",outlined:!0,disabled:!o||null!==c,onClick:()=>C("archive"),tooltip:"Download a ZIP of the entire project directory (all tests, raw data, configs)",tooltipOptions:{position:"bottom"}}),_jsx(Button,{icon:"pi pi-refresh",label:"Refresh",size:"small",onClick:w,disabled:a})]})]}),_jsx(SampleSummaryPanel,{projectId:o,methodId:i}),_jsxs(DataTable,{value:s,loading:a,paginator:!0,rows:10,emptyMessage:"No tests found.",scrollable:!0,scrollHeight:"flex",tableStyle:{minWidth:0},style:{width:"100%"},rowClassName:e=>!0===e?.excluded?"tis-row-excluded":"",selectionMode:"single",onSelectionChange:e=>{const o=e.value;o?.run_id&&t.setSelection({projectId:o.project_id??null,methodId:o.method_id??null,runId:o.run_id})},children:[_jsx(Column,{header:"Sample ID",sortable:!0,body:T,sortFunction:e=>{const t=[...e.data];return t.sort((t,o)=>T(t).localeCompare(T(o))*(e.order??1)),t},style:{minWidth:"8rem"}}),_jsx(Column,{field:"start_time",header:"Date/Time",sortable:!0,body:e=>{return(t=e.start_time)?new Date(t).toLocaleString():"";var t},style:{minWidth:"12rem"}}),_jsx(Column,{field:"method_id",header:"Test Method",sortable:!0,style:{minWidth:"10rem"}}),_jsx(Column,{header:"Status",field:"status",sortable:!0,body:e=>{const t=(e=>{if(!0===e?.finalized)return{label:"Abandoned",severity:"danger"};const t="string"==typeof e?.status?e.status:"completed";if("completed"===t&&!0===e?.auto_closed)return{label:"Interrupted",severity:"warning"};switch(t){case"in_progress":return{label:"In Progress",severity:"info"};case"paused":return{label:"Paused",severity:"warning"};case"completed":return{label:"Completed",severity:"success"};default:return{label:t,severity:void 0}}})(e);return _jsx(Badge,{value:t.label,severity:t.severity})},style:{minWidth:"6rem"}}),_jsx(Column,{header:"Incl.",align:"center",alignHeader:"center",style:{width:"4.5rem"},body:e=>{const t=!0===e?.excluded,s=u===e.run_id;return _jsx(Button,{icon:s?"pi pi-spin pi-spinner":t?"pi pi-eye-slash":"pi pi-check",rounded:!0,text:!0,size:"small",severity:t?"warning":"success",disabled:null!==u,onClick:()=>(async e=>{const t=e?.run_id,s=e?.method_id??i;if(!t||!s||!o)return;const r=!0!==e?.excluded;m(t);try{const e=await x("tis.set_test_excluded",MessageType.Request,{project_id:o,method_id:s,run_id:t,excluded:r});if(!e?.success)return void alert(`Failed to ${r?"exclude":"include"} ${t}`+(e?.error_message?`: ${e.error_message}`:""));await w()}catch(e){alert(`Exclude toggle failed: ${e instanceof Error?e.message:String(e)}`)}finally{m(null)}})(e),"aria-label":t?"Excluded — click to include":"Included — click to exclude",tooltip:t?"Excluded from cross-test results — click to include":"Included in cross-test results — click to exclude",tooltipOptions:{position:"left"}})}}),_jsx(Column,{header:"Download",style:{width:"14rem"},body:e=>{const t=l?.runId===e.run_id&&"data"===l?.kind,o=l?.runId===e.run_id&&"report"===l?.kind,i=null!==l;return _jsxs("div",{style:{display:"flex",gap:"0.4rem"},children:[_jsx(Button,{icon:t?"pi pi-spin pi-spinner":"pi pi-download",label:"Raw",size:"small",outlined:!0,disabled:i,onClick:()=>v(e,"data"),tooltip:"Download raw + filtered trace data as one CSV",tooltipOptions:{position:"left"}}),_jsx(Button,{icon:o?"pi pi-spin pi-spinner":"pi pi-file",label:"Results",size:"small",outlined:!0,disabled:i,onClick:()=>v(e,"report"),tooltip:"Download a CSV report (metadata + cycles + results) for this test",tooltipOptions:{position:"left"}})]})}}),_jsx(Column,{header:"",style:{width:"3rem"},body:e=>_jsx(Button,{icon:g===e.run_id?"pi pi-spin pi-spinner":"pi pi-ellipsis-v",text:!0,rounded:!0,size:"small",disabled:null!==g,"aria-label":"Test actions",tooltip:"Complete / abandon / reopen this test",tooltipOptions:{position:"left"},onClick:t=>{b.current+=1,h({row:e,anchor:t.currentTarget,seq:b.current})}})})]}),_jsx(Menu,{model:_?(e=>{const t=e?.status,o=!0===e?.finalized,i="in_progress"===t||"paused"===t,s="completed"===t&&!0===e?.auto_closed&&!o,r=[];return i?(r.push({label:"Complete Test",icon:"pi pi-check-circle",command:()=>j(e,"complete")}),r.push({label:"Abandon Test",icon:"pi pi-ban",command:()=>confirmDialog({header:"Abandon Test",message:`Mark ${e?.sample_id||e?.run_id} as abandoned? Recorded data is kept, but the test can no longer be reopened.`,icon:"pi pi-exclamation-triangle",acceptClassName:"p-button-danger",acceptLabel:"Abandon",accept:()=>j(e,"abandon")})})):s?(r.push({label:"Close Test",icon:"pi pi-check-circle",command:()=>confirmDialog({header:"Close Interrupted Test",message:`Close ${e?.sample_id||e?.run_id}? It was closed automatically when the software restarted mid-test. Closing it marks it Completed and keeps the recorded end time. Recorded data is not changed, and the test can still be reopened later.`,icon:"pi pi-check-circle",acceptLabel:"Close Test",accept:()=>j(e,"complete")})}),r.push({label:"Reopen Test",icon:"pi pi-replay",command:()=>confirmDialog({header:"Reopen Test",message:`Reopen ${e?.sample_id||e?.run_id} so new cycles are added to it? Cycle numbering continues from where it stopped. This changes where data is recorded — it does not start the machine.`,icon:"pi pi-replay",acceptLabel:"Reopen",accept:()=>j(e,"reopen")})}),r.push({label:"Abandon Test",icon:"pi pi-ban",command:()=>confirmDialog({header:"Abandon Test",message:`Mark ${e?.sample_id||e?.run_id} as abandoned? Recorded data is kept, but the test can no longer be reopened.`,icon:"pi pi-exclamation-triangle",acceptClassName:"p-button-danger",acceptLabel:"Abandon",accept:()=>j(e,"abandon")})})):"completed"!==t||o?r.push({label:o?"Abandoned — cannot reopen":"No actions available",icon:"pi pi-info-circle",disabled:!0}):r.push({label:"Reopen Test",icon:"pi pi-replay",command:()=>confirmDialog({header:"Reopen Test",message:`Reopen ${e?.sample_id||e?.run_id} so new cycles are added to it? Cycle numbering continues from where it stopped. This changes where data is recorded — it does not start the machine.`,icon:"pi pi-replay",acceptLabel:"Reopen",accept:()=>j(e,"reopen")})}),r})(_.row):[],popup:!0,ref:f})]})};
1
+ import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React,{useState,useEffect,useContext,useRef}from"react";import{DataTable}from"primereact/datatable";import{Column}from"primereact/column";import{Button}from"primereact/button";import{Badge}from"primereact/badge";import{Menu}from"primereact/menu";import{Toast}from"primereact/toast";import{confirmDialog}from"primereact/confirmdialog";import{EventEmitterContext}from"../../core/EventEmitterContext";import{MessageType}from"../../hub/CommandMessage";import{useTis}from"./TisProvider";import{SampleSummaryPanel}from"./SampleSummaryPanel";import"./ResultHistoryTable.css";const downloadCsvBlob=(e,t)=>{const o=new Blob([t],{type:"text/csv;charset=utf-8;"}),i=URL.createObjectURL(o),s=document.createElement("a");s.href=i,s.download=e,document.body.appendChild(s),s.click(),s.remove(),URL.revokeObjectURL(i)},downloadViaUrl=(e,t)=>{const o=document.createElement("a");o.href=e,o.download=t,document.body.appendChild(o),o.click(),o.remove()},LIFECYCLE_DONE={complete:{summary:"Test closed",detail:e=>`${e} is now Completed. It can still be reopened.`},abandon:{summary:"Test abandoned",detail:e=>`${e} is out of the history and out of the sample averages. Its data is still on disk — use Show abandoned to see it.`},reopen:{summary:"Test reopened",detail:e=>`${e} is open again — new cycles are added to it.`}};export const ResultHistoryTable=e=>{const t=useTis(),o=e.projectId??t.selection.projectId,i=e.methodId,[s,a]=useState([]),[r,n]=useState(!1),[l,d]=useState(null),[c,p]=useState(null),[u,m]=useState(null),f=useRef(null),[h,_]=useState(null),b=useRef(0),[y,g]=useState(null),[w,x]=useState(!1),v=useRef(null),{invoke:C}=useContext(EventEmitterContext),j=useRef(0),T=async()=>{if(!o)return void a([]);const e=++j.current;n(!0);try{const t={project_id:o};i&&(t.method_id=i);const s=await C("tis.list_tests",MessageType.Request,t);if(e!==j.current)return;s.success&&s.data&&s.data.tests&&a(s.data.tests)}catch(e){}e===j.current&&n(!1)};useEffect(()=>{T()},[o,i,t.state.activeRunId,t.state.active]),useEffect(()=>{h&&f.current?.show({currentTarget:h.anchor})},[h]);const $=async(e,t)=>{const s=e?.run_id,a=e?.method_id??i;if(!s||!a||!o)return;const r="report"===t?"tis.export_test_csv":"tis.export_test_data_csv",n="report"===t?"test report":"test data";d({runId:s,kind:t});try{const e=await C(r,MessageType.Request,{project_id:o,method_id:a,run_id:s});if(!e?.success)return void alert(`Failed to build ${n} for ${s}`+(e?.error_message?`: ${e.error_message}`:""));const i="string"==typeof e.data?.filename&&e.data.filename?e.data.filename:`${o}_${a}_${s}_${t}.csv`;if("report"===t){const t="string"==typeof e.data?.csv?e.data.csv:"";if(!t)return void alert(`${n} for ${s} is empty.`);downloadCsvBlob(i,t)}else{const t="string"==typeof e.data?.download_url?e.data.download_url:"";if(!t)return void alert(`Server did not return a download URL for ${n}.`);downloadViaUrl(t,i)}}catch(e){alert(`Download failed: ${e instanceof Error?e.message:String(e)}`)}finally{d(null)}},R=async(e,t)=>{const s=e?.run_id,a=e?.method_id??i;if(!s||!a||!o)return;const r="complete"===t?"tis.finish_test":"abandon"===t?"tis.reset_test":"tis.resume_test",n=e?.sample_id||s;g(s);try{const e=await C(r,MessageType.Request,{project_id:o,method_id:a,run_id:s});if(!e?.success)return void alert(`Could not ${t} ${s}`+(e?.error_message?`:\n\n${e.error_message}`:""));await T(),v.current?.show({severity:"abandon"===t?"warn":"success",summary:LIFECYCLE_DONE[t].summary,detail:LIFECYCLE_DONE[t].detail(n),life:4e3})}catch(e){alert(`${t} failed: ${e instanceof Error?e.message:String(e)}`)}finally{g(null)}},S=async e=>{if(!o)return;const t="report"===e?"tis.export_project_csv":"tis.export_project_zip",i="report"===e?"project report":"project archive";p(e);try{const s=await C(t,MessageType.Request,{project_id:o});if(!s?.success)return void alert(`Failed to build ${i}`+(s?.error_message?`: ${s.error_message}`:""));const a="string"==typeof s.data?.download_url?s.data.download_url:"";if(!a)return void alert(`Server did not return a download URL for ${i}.`);const r="report"===e?`${o}_project_report.csv`:`${o}_project_archive.zip`,n="string"==typeof s.data?.filename&&s.data.filename?s.data.filename:r;downloadViaUrl(a,n)}catch(e){alert(`Download failed: ${e instanceof Error?e.message:String(e)}`)}finally{p(null)}},k=e=>{const t="string"==typeof e?.sample_id?e.sample_id:"";if(t)return t;const o=e?.config;return o&&"object"==typeof o&&"string"==typeof o.sample_id?o.sample_id:""},I=s.filter(e=>!0===e?.finalized).length,E=w?s:s.filter(e=>!0!==e?.finalized);return _jsxs("div",{style:{width:"100%",maxWidth:"100%",overflow:"hidden",boxSizing:"border-box"},children:[_jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:"1rem",gap:"0.5rem",flexWrap:"wrap"},children:[_jsx("h3",{style:{margin:0},children:o?`Test History: ${o}${i?` / ${i}`:""}`:"Test History (no project selected)"}),_jsxs("div",{style:{display:"flex",gap:"0.4rem",alignItems:"center"},children:[I>0&&_jsx(Button,{icon:w?"pi pi-eye-slash":"pi pi-eye",label:w?"Hide abandoned":`Show abandoned (${I})`,size:"small",outlined:!0,severity:"secondary",onClick:()=>x(e=>!e)}),_jsx(Button,{icon:"report"===c?"pi pi-spin pi-spinner":"pi pi-file",label:"Download Report",size:"small",outlined:!0,disabled:!o||null!==c,onClick:()=>S("report"),tooltip:"Download a CSV report of every test in this project",tooltipOptions:{position:"bottom"}}),_jsx(Button,{icon:"archive"===c?"pi pi-spin pi-spinner":"pi pi-box",label:"Download Archive",size:"small",outlined:!0,disabled:!o||null!==c,onClick:()=>S("archive"),tooltip:"Download a ZIP of the entire project directory (all tests, raw data, configs)",tooltipOptions:{position:"bottom"}}),_jsx(Button,{icon:"pi pi-refresh",label:"Refresh",size:"small",onClick:T,disabled:r})]})]}),_jsx(SampleSummaryPanel,{projectId:o,methodId:i}),_jsxs(DataTable,{value:E,loading:r,paginator:!0,rows:10,emptyMessage:"No tests found.",scrollable:!0,scrollHeight:"flex",tableStyle:{minWidth:0},style:{width:"100%"},rowClassName:e=>!0===e?.excluded?"tis-row-excluded":"",selectionMode:"single",onSelectionChange:e=>{const o=e.value;o?.run_id&&t.setSelection({projectId:o.project_id??null,methodId:o.method_id??null,runId:o.run_id})},children:[_jsx(Column,{header:"Sample ID",sortable:!0,body:k,sortFunction:e=>{const t=[...e.data];return t.sort((t,o)=>k(t).localeCompare(k(o))*(e.order??1)),t},style:{minWidth:"8rem"}}),_jsx(Column,{field:"start_time",header:"Date/Time",sortable:!0,body:e=>{return(t=e.start_time)?new Date(t).toLocaleString():"";var t},style:{minWidth:"12rem"}}),_jsx(Column,{field:"method_id",header:"Test Method",sortable:!0,style:{minWidth:"10rem"}}),_jsx(Column,{header:"Status",field:"status",sortable:!0,body:e=>{const t=(e=>{if(!0===e?.finalized)return{label:"Abandoned",severity:"danger"};const t="string"==typeof e?.status?e.status:"completed";if("completed"===t&&!0===e?.auto_closed)return{label:"Interrupted",severity:"warning"};switch(t){case"in_progress":return{label:"In Progress",severity:"info"};case"paused":return{label:"Paused",severity:"warning"};case"completed":return{label:"Completed",severity:"success"};default:return{label:t,severity:void 0}}})(e);return _jsx(Badge,{value:t.label,severity:t.severity})},style:{minWidth:"6rem"}}),_jsx(Column,{header:"Incl.",align:"center",alignHeader:"center",style:{width:"4.5rem"},body:e=>{const t=!0===e?.excluded,s=u===e.run_id;return _jsx(Button,{icon:s?"pi pi-spin pi-spinner":t?"pi pi-eye-slash":"pi pi-check",rounded:!0,text:!0,size:"small",severity:t?"warning":"success",disabled:null!==u,onClick:()=>(async e=>{const t=e?.run_id,s=e?.method_id??i;if(!t||!s||!o)return;const a=!0!==e?.excluded;m(t);try{const e=await C("tis.set_test_excluded",MessageType.Request,{project_id:o,method_id:s,run_id:t,excluded:a});if(!e?.success)return void alert(`Failed to ${a?"exclude":"include"} ${t}`+(e?.error_message?`: ${e.error_message}`:""));await T()}catch(e){alert(`Exclude toggle failed: ${e instanceof Error?e.message:String(e)}`)}finally{m(null)}})(e),"aria-label":t?"Excluded — click to include":"Included — click to exclude",tooltip:t?"Excluded from cross-test results — click to include":"Included in cross-test results — click to exclude",tooltipOptions:{position:"left"}})}}),_jsx(Column,{header:"Download",style:{width:"14rem"},body:e=>{const t=l?.runId===e.run_id&&"data"===l?.kind,o=l?.runId===e.run_id&&"report"===l?.kind,i=null!==l;return _jsxs("div",{style:{display:"flex",gap:"0.4rem"},children:[_jsx(Button,{icon:t?"pi pi-spin pi-spinner":"pi pi-download",label:"Raw",size:"small",outlined:!0,disabled:i,onClick:()=>$(e,"data"),tooltip:"Download raw + filtered trace data as one CSV",tooltipOptions:{position:"left"}}),_jsx(Button,{icon:o?"pi pi-spin pi-spinner":"pi pi-file",label:"Results",size:"small",outlined:!0,disabled:i,onClick:()=>$(e,"report"),tooltip:"Download a CSV report (metadata + cycles + results) for this test",tooltipOptions:{position:"left"}})]})}}),_jsx(Column,{header:"",style:{width:"3rem"},body:e=>_jsx(Button,{icon:y===e.run_id?"pi pi-spin pi-spinner":"pi pi-ellipsis-v",text:!0,rounded:!0,size:"small",disabled:null!==y,"aria-label":"Test actions",tooltip:"Complete / abandon / reopen this test",tooltipOptions:{position:"left"},onClick:t=>{b.current+=1,_({row:e,anchor:t.currentTarget,seq:b.current})}})})]}),_jsx(Menu,{model:h?(e=>{const t=e?.status,o=!0===e?.finalized,i="in_progress"===t||"paused"===t,s="completed"===t&&!0===e?.auto_closed&&!o,a=[];return i?(a.push({label:"Complete Test",icon:"pi pi-check-circle",command:()=>R(e,"complete")}),a.push({label:"Abandon Test",icon:"pi pi-ban",command:()=>confirmDialog({header:"Abandon Test",message:`Mark ${e?.sample_id||e?.run_id} as abandoned? Recorded data is kept, but the test can no longer be reopened.`,icon:"pi pi-exclamation-triangle",acceptClassName:"p-button-danger",acceptLabel:"Abandon",accept:()=>R(e,"abandon")})})):s?(a.push({label:"Close Test",icon:"pi pi-check-circle",command:()=>confirmDialog({header:"Close Interrupted Test",message:`Close ${e?.sample_id||e?.run_id}? It was closed automatically when the software restarted mid-test. Closing it marks it Completed and keeps the recorded end time. Recorded data is not changed, and the test can still be reopened later.`,icon:"pi pi-check-circle",acceptLabel:"Close Test",accept:()=>R(e,"complete")})}),a.push({label:"Reopen Test",icon:"pi pi-replay",command:()=>confirmDialog({header:"Reopen Test",message:`Reopen ${e?.sample_id||e?.run_id} so new cycles are added to it? Cycle numbering continues from where it stopped. This changes where data is recorded — it does not start the machine.`,icon:"pi pi-replay",acceptLabel:"Reopen",accept:()=>R(e,"reopen")})}),a.push({label:"Abandon Test",icon:"pi pi-ban",command:()=>confirmDialog({header:"Abandon Test",message:`Mark ${e?.sample_id||e?.run_id} as abandoned? Recorded data is kept, but the test can no longer be reopened.`,icon:"pi pi-exclamation-triangle",acceptClassName:"p-button-danger",acceptLabel:"Abandon",accept:()=>R(e,"abandon")})})):"completed"!==t||o?a.push({label:o?"Abandoned — cannot reopen":"No actions available",icon:"pi pi-info-circle",disabled:!0}):a.push({label:"Reopen Test",icon:"pi pi-replay",command:()=>confirmDialog({header:"Reopen Test",message:`Reopen ${e?.sample_id||e?.run_id} so new cycles are added to it? Cycle numbering continues from where it stopped. This changes where data is recorded — it does not start the machine.`,icon:"pi pi-replay",acceptLabel:"Reopen",accept:()=>R(e,"reopen")})}),a})(h.row):[],popup:!0,ref:f}),_jsx(Toast,{ref:v,position:"top-right"})]})};
@@ -1 +1 @@
1
- {"version":3,"file":"TestDataView.d.ts","sourceRoot":"","sources":["../../../src/components/tis/TestDataView.tsx"],"names":[],"mappings":"AA0BA,OAAO,KAAwE,MAAM,OAAO,CAAC;AAqC7F,MAAM,WAAW,YAAY;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;wEAEoE;IACpE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;sEAEkE;IAClE,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,GAAG,CAAA;KAAE,CAAC,CAAC;IAC3E;;;;iCAI6B;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;oCAGgC;IAChC,SAAS,CAAC,EAAE;QACR,EAAE,EAAE,MAAM,CAAC;QACX,EAAE,CAAC,EAAE,MAAM,CAAC;QACZ,IAAI,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;QAClC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;KAC9B,CAAC;CACL;AAED,MAAM,WAAW,SAAS;IAAI,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CAAE;AAChF,MAAM,WAAW,WAAW;IAAG,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAAE;AAC5G;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IACxB,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,4DAA4D;IAC5D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AACD,MAAM,WAAW,SAAS;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,eAAe,GAAG,WAAW,CAAC;IACpC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,KAAK,GAAG,UAAU,CAAC;IAC5B,CAAC,EAAE,SAAS,CAAC;IACb,CAAC,EAAE,WAAW,EAAE,CAAC;IACjB;;;;;;;;;;OAUG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;;;;;OASG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;CAC3B;AACD,MAAM,WAAW,SAAS;IAAG,MAAM,EAAE,MAAM,CAAC;CAAE;AAC9C,MAAM,WAAW,YAAY;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB;;8CAE0C;IAC1C,OAAO,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC;IACtC,KAAK,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;CACrC;AACD;oDACoD;AACpD,MAAM,WAAW,iBAAiB;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uEAAuE;IACvE,QAAQ,CAAC,EAAE;QAAE,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,CAAC;CACvC;AACD,MAAM,WAAW,UAAU;IAOvB,cAAc,CAAC,EAAE,YAAY,EAAE,CAAC;IAChC,aAAa,CAAC,EAAG,YAAY,EAAE,CAAC;IAChC;;4CAEwC;IACxC,mBAAmB,CAAC,EAAE,YAAY,EAAE,CAAC;IACrC,YAAY,CAAC,EAAI,YAAY,EAAE,CAAC;IAChC,cAAc,CAAC,EAAE,YAAY,EAAE,CAAC;IAChC,QAAQ,CAAC,EAAQ,YAAY,GAAG,IAAI,CAAC;IACrC,KAAK,CAAC,EAAW;QAAE,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC;IAC/C,wDAAwD;IACxD,KAAK,CAAC,EAAW,MAAM,CAAC;IACxB,qDAAqD;IACrD,WAAW,CAAC,EAAK,MAAM,CAAC;IACxB,oEAAoE;IACpE,cAAc,CAAC,EAAE,iBAAiB,EAAE,CAAC;CACxC;AAED,MAAM,WAAW,iBAAiB;IAC9B,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,QAAQ,CAAC,EAAG,MAAM,CAAC;IACnB,gEAAgE;IAChE,KAAK,CAAC,EAAM,MAAM,CAAC;IACnB,kEAAkE;IAClE,MAAM,CAAC,EAAK,UAAU,CAAC;IACvB,8EAA8E;IAC9E,UAAU,CAAC,EAAG,MAAM,CAAC;IACrB,wDAAwD;IACxD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;uEACmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAID,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAw0BpD,CAAC;AAmfF;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,IAAI,CAAC"}
1
+ {"version":3,"file":"TestDataView.d.ts","sourceRoot":"","sources":["../../../src/components/tis/TestDataView.tsx"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- import{jsxs as _jsxs,jsx as _jsx,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,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,I]=useState(null),[A,M]=useState(null),[O,D]=useState(!1),[E,L]=useState(null),[N,F]=useState(null),[k,q]=useState(!1),[V,P]=useState([]),[H,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||!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),D(!0),M(null),I(null);try{const e=await c("tis.read_raw",MessageType.Request,o);e?.success?I(e.data??{}):M(e?.error_message??"No raw data on disk for this run.")}catch(e){M(String(e?.message??e))}finally{D(!1)}q(!0),F(null),L(null);try{const e=await c("tis.read_filtered",MessageType.Request,o);e?.success?L(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]);if(useEffect(()=>{j&&null!=H&&se(H)},[j,H,se]),!(r&&n&&a&&o)){const e=[!r&&"project",!n&&"method",!a&&"run",!o&&"method definition"].filter(Boolean).join(", "),l=!!t.state.active&&!!t.state.activeRunId;return _jsx("div",{className:"p-card",style:{padding:"1rem",color:"var(--text-secondary-color)"},children:l?_jsxs(_Fragment,{children:[_jsxs("div",{children:["A test is running, but this view has not resolved it yet",e?` (no ${e})`:"","."]}),_jsx(Button,{label:"Show the active test",icon:"pi pi-refresh",style:{marginTop:"0.75rem"},onClick:()=>t.setSelection({projectId:t.state.activeProjectId||null,methodId:t.state.activeMethodId||null,sampleId:t.state.activeSampleId||null,runId:t.state.activeRunId||null})})]}):_jsx(_Fragment,{children:"No test selected. Pick a row from the History tab or start a run."})})}return _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=V;0===e.length&&(e=await ie(),P(e));const t=e.length>0?e[e.length-1]:null,r=H??t;H!==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:V,selected:H,onChange:z}),_jsx(RawEnvelopeHeader,{envelope:R}),_jsxs(TabView,{style:{height:"100%"},children:[_jsx(TabPanel,{header:"Raw Data",children:_jsx(DataBlobTable,{blob:unwrapEnvelope(R),loading:O,error:A,rawData:o.raw_data})}),_jsx(TabPanel,{header:"Filtered Data",children:_jsx(DataBlobTable,{blob:unwrapEnvelope(E),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})})]})};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{jsxs as _jsxs,jsx as _jsx,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,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,I]=useState(null),[A,M]=useState(null),[O,D]=useState(!1),[E,L]=useState(null),[N,F]=useState(null),[k,q]=useState(!1),[V,P]=useState([]),[H,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||!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),D(!0),M(null),I(null);try{const e=await c("tis.read_raw",MessageType.Request,o);e?.success?I(e.data??{}):M(e?.error_message??"No raw data on disk for this run.")}catch(e){M(String(e?.message??e))}finally{D(!1)}q(!0),F(null),L(null);try{const e=await c("tis.read_filtered",MessageType.Request,o);e?.success?L(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]);if(useEffect(()=>{j&&null!=H&&se(H)},[j,H,se]),!(r&&n&&a&&o)){const e=[!r&&"project",!n&&"method",!a&&"run",!o&&"method definition"].filter(Boolean).join(", "),l=!!t.state.active;return _jsx("div",{className:"p-card",style:{padding:"1rem",color:"var(--text-secondary-color)"},children:l?_jsxs(_Fragment,{children:[_jsxs("div",{children:["A test is running, but this view has not resolved it yet",e?` (no ${e})`:"","."]}),_jsx(Button,{label:"Show the active test",icon:"pi pi-refresh",style:{marginTop:"0.75rem"},onClick:()=>t.setSelection({projectId:t.state.activeProjectId||null,methodId:t.state.activeMethodId||null,sampleId:t.state.activeSampleId||null,runId:t.state.activeRunId||null})})]}):_jsx(_Fragment,{children:"No test selected. Pick a row from the History tab or start a run."})})}return _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=V;0===e.length&&(e=await ie(),P(e));const t=e.length>0?e[e.length-1]:null,r=H??t;H!==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:V,selected:H,onChange:z}),_jsx(RawEnvelopeHeader,{envelope:R}),_jsxs(TabView,{style:{height:"100%"},children:[_jsx(TabPanel,{header:"Raw Data",children:_jsx(DataBlobTable,{blob:unwrapEnvelope(R),loading:O,error:A,rawData:o.raw_data})}),_jsx(TabPanel,{header:"Filtered Data",children:_jsx(DataBlobTable,{blob:unwrapEnvelope(E),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})})]})};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 +1 @@
1
- {"version":3,"file":"TisProvider.d.ts","sourceRoot":"","sources":["../../../src/components/tis/TisProvider.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,EASV,KAAK,SAAS,EACjB,MAAM,OAAO,CAAC;AAGf,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAMrE;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GAAG,GAAG,CAAC;AAElC,MAAM,MAAM,cAAc,GAAG;IAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,eAAe,CAAA;CAAE,CAAC;AAErE,MAAM,WAAW,YAAY;IACzB,MAAM,EAAE,OAAO,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IAEvB,MAAM,EAAE,OAAO,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IAEpB;;;;;;;;OAQG;IACH,cAAc,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,mBAAmB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,KAAK,EAAE,gBAAgB,CAAC;IACxB,yDAAyD;IACzD,iBAAiB,EAAE,OAAO,CAAC;IAC3B,uEAAuE;IACvE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B;;mEAE+D;IAC/D,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;IACpC;6DACyD;IACzD,KAAK,EAAE,OAAO,CAAC;IACf,iEAAiE;IACjE,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB;iEAC6D;IAC7D,SAAS,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACjB;AAED;gDACgD;AAChD,MAAM,MAAM,iBAAiB,GAAG;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,CAAC;AAEF,MAAM,WAAW,gBAAgB;IAC7B,IAAI,EAAE,GAAG,GAAG,IAAI,CAAC;IACjB,MAAM,EAAE,GAAG,EAAE,CAAC;IACd,OAAO,EAAE,GAAG,CAAC;IACb,OAAO,EAAE;QAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,CAAC;CACxC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,aAAa,GAAG,aAAa,CAAC;IACtC;+DAC2D;IAC3D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC5B,OAAO,EAAE,cAAc,CAAC;IACxB;;;;;+BAK2B;IAC3B,gBAAgB,EAAE,kBAAkB,EAAE,CAAC;IACvC,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,OAAO,CAAC;IAEvB,KAAK,EAAE,YAAY,CAAC;IAEpB,SAAS,EAAE,YAAY,CAAC;IACxB,YAAY,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAWjD,gEAAgE;IAChE,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B;;;iDAG6C;IAC7C,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC;IACtC;uEACmE;IACnE,eAAe,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC;;qCAEiC;IACjC,sBAAsB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAE7C;;;6BAGyB;IACzB,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACnC,mBAAmB,EAAE,OAAO,CAAC;IAC7B;;;mBAGe;IACf,iBAAiB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;IACvE;kEAC8D;IAC9D,gBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC;IAEpE;;;;;;;OAOG;IACH,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAClC;gDAC4C;IAC5C,eAAe,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC;IACtD;qDACiD;IACjD,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAE9B;;;;;;;8BAO0B;IAC1B,wBAAwB,EAAE,MAAM,CAAC;IACjC;;wCAEoC;IACpC,4BAA4B,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAEzD;;;;;;kDAM8C;IAC9C,iBAAiB,EAAE,MAAM,CAAC;IAC1B;;iEAE6D;IAC7D,oBAAoB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAS7C;uEACmE;IACnE,WAAW,EAAE,mBAAmB,CAAC;IACjC;;iDAE6C;IAC7C,iBAAiB,EAAE,YAAY,EAAE,CAAC;IAClC;;kEAE8D;IAC9D,oBAAoB,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE;iEAC6D;IAC7D,gBAAgB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC;iEAC6D;IAC7D,kBAAkB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAExC;;qCAEiC;IACjC,SAAS,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACpE;uEACmE;IACnE,QAAQ,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IACnG,QAAQ,EAAE;QAAE,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,CAAA;KAAE,CAAC;CACnD;AAuCD,QAAA,MAAM,UAAU,gCA+Bd,CAAC;AAqCH,MAAM,WAAW,gBAAgB;IAC7B,QAAQ,EAAE,SAAS,CAAC;IACpB;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAimBlD,CAAC;AAMF,eAAO,MAAM,MAAM,uBAAyC,CAAC;AAC7D,eAAO,MAAM,aAAa,sBAA0C,CAAC;AACrE,eAAO,MAAM,WAAW,oBAA0C,CAAC;AAEnE;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB;;uBAvvBI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC;iBAG3C,OAAO,CAAC,IAAI,CAAC;eAtL1B,MAAM;cACP,MAAM;IAChB,gEAAgE;WACzD,gBAAgB;IACvB,yDAAyD;uBACtC,OAAO;IAC1B,uEAAuE;YAC/D,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAC3B;;mEAE+D;aACtD,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IACnC;6DACyD;WAClD,OAAO;IACd,iEAAiE;aACxD,MAAM,EAAE;IACjB;iEAC6D;eAClD,OAAO;CAg6BrB,CAAC;AACF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,eAAe,wCAv3BF,iBAAiB,KAAK,IAAI,CA03BnD,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,YAAY,MAAM,EAAE,WAAW,MAAM;;;;CAY/D,CAAC;AAEF,eAAO,MAAM,SAAS,GAAI,QAAQ,MAAM;;;;;;;;CAuBvC,CAAC;AAIF,OAAO,EAAE,UAAU,EAAE,CAAC"}
1
+ {"version":3,"file":"TisProvider.d.ts","sourceRoot":"","sources":["../../../src/components/tis/TisProvider.tsx"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- import{jsx as _jsx}from"react/jsx-runtime";import React,{createContext,useCallback,useContext,useEffect,useMemo,useReducer,useRef,useState}from"react";import{EventEmitterContext}from"../../core/EventEmitterContext";import{MessageType}from"../../hub/CommandMessage";const EMPTY_STATE={staged:!1,stagedProjectId:"",stagedMethodId:"",stagedSampleId:"",active:!1,activeProjectId:"",activeMethodId:"",activeSampleId:"",activeRunId:"",lastStartError:""},EMPTY_SELECTION={projectId:"",methodId:"",sampleId:"",runId:""},EMPTY_CYCLE_CONFIG={projectId:"",methodId:"",scope:"run",promptBeforeCycle:!1,values:{},latched:null,ready:!0,missing:[],promptDue:!1},cycleConfigFromPayload=e=>({projectId:String(e?.project_id??""),methodId:String(e?.method_id??""),scope:"cycle"===e?.scope?"cycle":"run",promptBeforeCycle:!!e?.prompt_before_cycle,values:e?.values&&"object"==typeof e.values?e.values:{},latched:e?.latched&&"object"==typeof e.latched?e.latched:null,ready:!1!==e?.ready,missing:Array.isArray(e?.missing)?e.missing:[],promptDue:!!e?.prompt_due}),TisContext=createContext({schemas:{},projectAssetRefs:[],defaultMethodId:"",schemasLoaded:!1,state:EMPTY_STATE,selection:EMPTY_SELECTION,setSelection:()=>{},existingProjects:[],projectKnown:()=>!1,refreshProjects:async()=>{},markProjectJustCreated:()=>{},projectFields:{},projectFieldsLoaded:!1,loadProjectFields:async()=>null,setProjectFields:()=>{},stagedConfig:{},setStagedConfig:()=>{},clearStagedConfig:()=>{},defaultsAppliedForMethod:"",markDefaultsAppliedForMethod:()=>{},configurationName:"",setConfigurationName:()=>{},cycleConfig:EMPTY_CYCLE_CONFIG,cycleConfigFields:[],setCycleConfigValues:async()=>{},clearCycleConfig:async()=>{},refreshCycleConfig:async()=>{},fetchRuns:async()=>[],fetchRun:async()=>null,runCache:{}});function liveReducer(e,t){switch(t.kind){case"staged":return{...e,staged:t.value};case"staged_project_id":return{...e,stagedProjectId:t.value};case"staged_method_id":return{...e,stagedMethodId:t.value};case"staged_sample_id":return{...e,stagedSampleId:t.value};case"active":return{...e,active:t.value};case"active_project_id":return{...e,activeProjectId:t.value};case"active_method_id":return{...e,activeMethodId:t.value};case"active_sample_id":return{...e,activeSampleId:t.value};case"active_run_id":return{...e,activeRunId:t.value};case"last_start_error":return{...e,lastStartError:t.value}}}export const TisProvider=({children:e,defaultMethodId:t})=>{const{invoke:s,read:c,subscribe:a,unsubscribe:d,isConnected:r}=useContext(EventEmitterContext),[o,i]=useState({}),[n,u]=useState([]),[l,_]=useState(t??""),[f,p]=useState(!1),[m,g]=useReducer(liveReducer,EMPTY_STATE),[C,h]=useState({projectId:null,methodId:null,sampleId:null,runId:null}),y=useCallback(async()=>{try{const e=await s("tis.list_schemas",MessageType.Request,{});if(e?.success&&e.data){const s=e.data.test_methods??{},c=e.data.default_method_id??"",a=Array.isArray(e.data.asset_refs)?e.data.asset_refs:[];i(s),u(a),!t&&c&&_(c),p(!0)}}catch(e){}},[s]);useEffect(()=>{y()},[y]),useEffect(()=>{const e=a("tis.schema_changed",()=>{y()});return()=>{d(e)}},[a,d,y]),useEffect(()=>{let e=!1;return(async()=>{try{const t=await s("gnv.ux.selected_project_id",MessageType.Read,{});if(e)return;const c=t?.success?t.data??"":"";"string"==typeof c&&c.length>0&&h(e=>null===e.projectId?{...e,projectId:c}:e)}catch{}})(),()=>{e=!0}},[]),useEffect(()=>{const e=[a("tis.staged",e=>g({kind:"staged",value:!!e})),a("tis.staged_project_id",e=>g({kind:"staged_project_id",value:String(e??"")})),a("tis.staged_method_id",e=>g({kind:"staged_method_id",value:String(e??"")})),a("tis.staged_sample_id",e=>g({kind:"staged_sample_id",value:String(e??"")})),a("tis.active",e=>g({kind:"active",value:!!e})),a("tis.active_project_id",e=>g({kind:"active_project_id",value:String(e??"")})),a("tis.active_method_id",e=>g({kind:"active_method_id",value:String(e??"")})),a("tis.active_sample_id",e=>g({kind:"active_sample_id",value:String(e??"")})),a("tis.active_run_id",e=>g({kind:"active_run_id",value:String(e??"")})),a("tis.last_start_error",e=>g({kind:"last_start_error",value:String(e??"")}))],t=[{fqdn:"gm.tis_staged",kind:"staged",bool:!0},{fqdn:"gm.tis_staged_project_id",kind:"staged_project_id"},{fqdn:"gm.tis_staged_method_id",kind:"staged_method_id"},{fqdn:"gm.tis_staged_sample_id",kind:"staged_sample_id"},{fqdn:"gm.tis_active",kind:"active",bool:!0},{fqdn:"gm.tis_active_project_id",kind:"active_project_id"},{fqdn:"gm.tis_active_method_id",kind:"active_method_id"},{fqdn:"gm.tis_active_sample_id",kind:"active_sample_id"},{fqdn:"gm.tis_active_run_id",kind:"active_run_id"}];let s,o=!1,i=!1;const n=e=>{o||i||(async()=>{if(!r())return!1;let e=!1;for(const{fqdn:s,kind:a,bool:d}of t)try{const t=await c(s);if(o)return!0;if(t&&!1===t.success)continue;const r=t?.data;if(null==r)continue;e=!0,g({kind:a,value:d?!!r:String(r)})}catch{}return e})().then(t=>{o||(t?i=!0:s=setTimeout(()=>n(Math.min(2*e,5e3)),e))})};n(250);const u=a("HUB/connected",()=>{i=!1,n(250)});return()=>{o=!0,s&&clearTimeout(s),d(u),e.forEach(d)}},[a,d,c,r]);const I=useRef({}),[v,j]=useState(0),S=useCallback(()=>j(e=>e+1),[]),T=useCallback((e,t)=>{if(!e)return;const s=I.current[e]??{meta:null,cycles:[],results:{},rawData:{}};I.current[e]={...s,cycles:[...s.cycles,t]},S()},[S]),E=useCallback((e,t)=>{if(!e)return;const s=I.current[e]??{meta:null,cycles:[],results:{},rawData:{}};I.current[e]={...s,results:t},S()},[S]);useEffect(()=>{const e=a("tis.cycle_added",e=>{e?.run_id&&e.cycle&&T(e.run_id,e.cycle)}),t=a("tis.results_updated",e=>{e?.run_id&&E(e.run_id,e.results??{})});return()=>{d(e),d(t)}},[a,d,T,E]);const k=useMemo(()=>({projectId:C.projectId??m.activeProjectId,methodId:C.methodId??(m.activeMethodId||l),sampleId:C.sampleId??m.activeSampleId,runId:C.runId??m.activeRunId}),[C,m,l]),M=useCallback(e=>{h(t=>({projectId:void 0===e.projectId?t.projectId:e.projectId,methodId:void 0===e.methodId?t.methodId:e.methodId,sampleId:void 0===e.sampleId?t.sampleId:e.sampleId,runId:void 0===e.runId?t.runId:e.runId})),void 0!==e.projectId&&s("gnv.ux.selected_project_id",MessageType.Write,e.projectId??"").catch(e=>{})},[s]),x=useRef("");useEffect(()=>{const e=m.activeRunId;e&&e!==x.current&&(x.current=e,h({projectId:null,methodId:null,sampleId:null,runId:null}))},[m.activeRunId]);const R=useCallback(async(e,t)=>{if(!e)return[];const c={project_id:e};t&&(c.method_id=t);try{const e=await s("tis.list_tests",MessageType.Request,c);if(e?.success&&e.data?.tests)return e.data.tests}catch(e){}return[]},[s]),P=useCallback(async(e,t,c)=>{if(!e||!t||!c)return null;try{const a=await s("tis.read_test",MessageType.Request,{project_id:e,method_id:t,run_id:c}),d=await s("tis.read_cycles",MessageType.Request,{project_id:e,method_id:t,run_id:c,offset:0,limit:1e3,order:"asc"});if(!a?.success)return null;const r={meta:a.data??null,cycles:d?.success?d.data?.cycles??[]:[],results:a.data?.results??{},rawData:I.current[c]?.rawData??{}};return I.current[c]=r,S(),r}catch(e){return null}},[s,S]),b=useMemo(()=>({...I.current}),[v]),[F,w]=useState([]),q=useRef(new Set),[Y,A]=useState(0),[L,N]=useState({}),D=useCallback(async()=>{try{const e=await s("tis.list_projects",MessageType.Request,{});e?.success&&e.data?.projects&&w(e.data.projects)}catch(e){}},[s]),O=useCallback(e=>{e&&(q.current.has(e)||(q.current.add(e),A(e=>e+1)))},[]),G=useCallback(e=>!!e&&(!!q.current.has(e)||F.includes(e)),[F,Y]),V=useCallback((e,t)=>{e&&N(s=>({...s,[e]:t}))},[]),B=useCallback(async e=>{if(!e)return null;try{const t=await s("tis.read_project",MessageType.Request,{project_id:e});if(t?.success){const s=t.data?.project_fields??{};return N(t=>({...t,[e]:s})),s}}catch(e){}return N(t=>({...t,[e]:{}})),{}},[s]);useEffect(()=>{D()},[D]),useEffect(()=>{const e=a("tis.project_created",()=>{D()}),t=a("tis.project_updated",e=>{const t="string"==typeof e?.project_id?e.project_id:"";t&&B(t)});return()=>{d(e),d(t)}},[a,d,D,B]),useEffect(()=>{const e=k.projectId;e&&G(e)&&void 0===L[e]&&B(e)},[k.projectId,G,L,B]);const J=L[k.projectId]??{},K=void 0!==L[k.projectId],[H,U]=useState({}),W=useCallback(e=>{U(t=>({...t,...e}))},[]),[z,Q]=useState(""),X=useCallback(e=>{Q(e)},[]),[Z,$]=useState(""),ee=useCallback(()=>{U({}),Q(""),$("")},[]),[te,se]=useState(EMPTY_CYCLE_CONFIG),ce=useMemo(()=>{const e=k.methodId?o[k.methodId]?.cycle_config_fields:void 0;return Array.isArray(e)?e:[]},[o,k.methodId]),ae=useCallback(async()=>{const e=k.projectId,t=k.methodId;if(t)try{const c=await s("tis.cycle_config",MessageType.Request,{project_id:e,method_id:t});if(c?.success)return void se(cycleConfigFromPayload(c.data));se(EMPTY_CYCLE_CONFIG)}catch(e){se(EMPTY_CYCLE_CONFIG)}else se(EMPTY_CYCLE_CONFIG)},[s,k.projectId,k.methodId]),de=useCallback(async e=>{const t=k.projectId,c=k.methodId;if(c)try{const a=await s("tis.set_cycle_config",MessageType.Request,{project_id:t,method_id:c,values:e});a?.success&&se(cycleConfigFromPayload(a.data))}catch(e){}},[s,k.projectId,k.methodId]),re=useCallback(async()=>{const e=k.projectId,t=k.methodId;if(t)try{const c=await s("tis.clear_cycle_config",MessageType.Request,{project_id:e,method_id:t});c?.success&&se(cycleConfigFromPayload(c.data))}catch(e){}},[s,k.projectId,k.methodId]);useEffect(()=>{ae()},[ae]),useEffect(()=>{const e=a("tis.schema_changed",()=>{ae()});return()=>{d(e)}},[a,d,ae]),useEffect(()=>{const e=a("tis.cycle_config",e=>{const t=String(e?.method_id??"");t&&k.methodId&&t!==k.methodId||se(cycleConfigFromPayload(e))});return()=>{d(e)}},[a,d,k.methodId]);const oe=useMemo(()=>({schemas:o,projectAssetRefs:n,defaultMethodId:l,schemasLoaded:f,state:m,selection:k,setSelection:M,existingProjects:F,projectKnown:G,refreshProjects:D,markProjectJustCreated:O,projectFields:J,projectFieldsLoaded:K,loadProjectFields:B,setProjectFields:V,stagedConfig:H,setStagedConfig:W,clearStagedConfig:ee,defaultsAppliedForMethod:z,markDefaultsAppliedForMethod:X,configurationName:Z,setConfigurationName:$,cycleConfig:te,cycleConfigFields:ce,setCycleConfigValues:de,clearCycleConfig:re,refreshCycleConfig:ae,fetchRuns:R,fetchRun:P,runCache:b}),[o,n,l,f,m,k,M,F,G,D,O,J,K,B,V,H,W,ee,z,X,Z,$,te,ce,de,re,ae,R,P,b]);return _jsx(TisContext.Provider,{value:oe,children:e})};export const useTis=()=>useContext(TisContext);export const useTisSchemas=()=>useContext(TisContext).schemas;export const useTisState=()=>useContext(TisContext).state;export const useTisCycleConfig=()=>{const{cycleConfig:e,cycleConfigFields:t,setCycleConfigValues:s,clearCycleConfig:c}=useContext(TisContext);return{...e,fields:t,setValues:s,clear:c}};export const useTisSelection=()=>{const{selection:e,setSelection:t}=useContext(TisContext);return[e,t]};export const useTisRuns=(e,t)=>{const{fetchRuns:s}=useContext(TisContext),[c,a]=useState([]),[d,r]=useState(!1),o=useCallback(async()=>{if(e){r(!0);try{a(await s(e,t))}finally{r(!1)}}else a([])},[e,t,s]);return useEffect(()=>{o()},[o]),{runs:c,loading:d,refresh:o}};export const useTisRun=e=>{const{selection:t,fetchRun:s,runCache:c}=useContext(TisContext),[a,d]=useState(!1),r=e??t.runId;useEffect(()=>{if(!r)return;if(c[r]?.meta)return;const e=t.projectId,a=t.methodId;e&&a&&(d(!0),s(e,a,r).finally(()=>d(!1)))},[r,t.projectId,t.methodId,s,c]);const o=r?c[r]:null;return{meta:o?.meta??null,cycles:o?.cycles??[],results:o?.results??{},rawData:o?.rawData??{},loading:a}};export{TisContext};
1
+ import{jsx as _jsx}from"react/jsx-runtime";import React,{createContext,useCallback,useContext,useEffect,useMemo,useReducer,useRef,useState}from"react";import{EventEmitterContext}from"../../core/EventEmitterContext";import{MessageType}from"../../hub/CommandMessage";const EMPTY_STATE={staged:!1,stagedProjectId:"",stagedMethodId:"",stagedSampleId:"",active:!1,activeProjectId:"",activeMethodId:"",activeSampleId:"",activeRunId:"",lastStartError:""},EMPTY_SELECTION={projectId:"",methodId:"",sampleId:"",runId:""},EMPTY_CYCLE_CONFIG={projectId:"",methodId:"",scope:"run",promptBeforeCycle:!1,values:{},latched:null,ready:!0,missing:[],promptDue:!1},cycleConfigFromPayload=e=>({projectId:String(e?.project_id??""),methodId:String(e?.method_id??""),scope:"cycle"===e?.scope?"cycle":"run",promptBeforeCycle:!!e?.prompt_before_cycle,values:e?.values&&"object"==typeof e.values?e.values:{},latched:e?.latched&&"object"==typeof e.latched?e.latched:null,ready:!1!==e?.ready,missing:Array.isArray(e?.missing)?e.missing:[],promptDue:!!e?.prompt_due}),TisContext=createContext({schemas:{},projectAssetRefs:[],defaultMethodId:"",schemasLoaded:!1,state:EMPTY_STATE,selection:EMPTY_SELECTION,setSelection:()=>{},existingProjects:[],projectKnown:()=>!1,refreshProjects:async()=>{},markProjectJustCreated:()=>{},projectFields:{},projectFieldsLoaded:!1,loadProjectFields:async()=>null,setProjectFields:()=>{},stagedConfig:{},setStagedConfig:()=>{},clearStagedConfig:()=>{},defaultsAppliedForMethod:"",markDefaultsAppliedForMethod:()=>{},configurationName:"",setConfigurationName:()=>{},cycleConfig:EMPTY_CYCLE_CONFIG,cycleConfigFields:[],setCycleConfigValues:async()=>{},clearCycleConfig:async()=>{},refreshCycleConfig:async()=>{},fetchRuns:async()=>[],fetchRun:async()=>null,runCache:{}});function liveReducer(e,t){switch(t.kind){case"staged":return{...e,staged:t.value};case"staged_project_id":return{...e,stagedProjectId:t.value};case"staged_method_id":return{...e,stagedMethodId:t.value};case"staged_sample_id":return{...e,stagedSampleId:t.value};case"active":return{...e,active:t.value};case"active_project_id":return{...e,activeProjectId:t.value};case"active_method_id":return{...e,activeMethodId:t.value};case"active_sample_id":return{...e,activeSampleId:t.value};case"active_run_id":return{...e,activeRunId:t.value};case"last_start_error":return{...e,lastStartError:t.value}}}export const TisProvider=({children:e,defaultMethodId:t})=>{const{invoke:s,read:c,subscribe:a,unsubscribe:d,isConnected:r}=useContext(EventEmitterContext),[i,o]=useState({}),[n,u]=useState([]),[l,_]=useState(t??""),[p,f]=useState(!1),[m,g]=useReducer(liveReducer,EMPTY_STATE),[h,C]=useState({projectId:null,methodId:null,sampleId:null,runId:null}),y=useCallback(async()=>{try{const e=await s("tis.list_schemas",MessageType.Request,{});if(e?.success&&e.data){const s=e.data.test_methods??{},c=e.data.default_method_id??"",a=Array.isArray(e.data.asset_refs)?e.data.asset_refs:[];o(s),u(a),!t&&c&&_(c),f(!0)}}catch(e){}},[s]);useEffect(()=>{y()},[y]),useEffect(()=>{const e=a("tis.schema_changed",()=>{y()});return()=>{d(e)}},[a,d,y]),useEffect(()=>{let e=!1;return(async()=>{try{const t=await s("gnv.ux.selected_project_id",MessageType.Read,{});if(e)return;const c=t?.success?t.data??"":"";"string"==typeof c&&c.length>0&&C(e=>null===e.projectId?{...e,projectId:c}:e)}catch{}})(),()=>{e=!0}},[]),useEffect(()=>{const e=[a("tis.staged",e=>g({kind:"staged",value:!!e})),a("tis.staged_project_id",e=>g({kind:"staged_project_id",value:String(e??"")})),a("tis.staged_method_id",e=>g({kind:"staged_method_id",value:String(e??"")})),a("tis.staged_sample_id",e=>g({kind:"staged_sample_id",value:String(e??"")})),a("tis.active",e=>g({kind:"active",value:!!e})),a("tis.active_project_id",e=>g({kind:"active_project_id",value:String(e??"")})),a("tis.active_method_id",e=>g({kind:"active_method_id",value:String(e??"")})),a("tis.active_sample_id",e=>g({kind:"active_sample_id",value:String(e??"")})),a("tis.active_run_id",e=>g({kind:"active_run_id",value:String(e??"")})),a("tis.last_start_error",e=>g({kind:"last_start_error",value:String(e??"")}))],t=[{fqdn:"gm.tis_staged",kind:"staged",bool:!0},{fqdn:"gm.tis_staged_project_id",kind:"staged_project_id"},{fqdn:"gm.tis_staged_method_id",kind:"staged_method_id"},{fqdn:"gm.tis_staged_sample_id",kind:"staged_sample_id"},{fqdn:"gm.tis_active",kind:"active",bool:!0},{fqdn:"gm.tis_active_project_id",kind:"active_project_id"},{fqdn:"gm.tis_active_method_id",kind:"active_method_id"},{fqdn:"gm.tis_active_sample_id",kind:"active_sample_id"},{fqdn:"gm.tis_active_run_id",kind:"active_run_id"}];let i,o=!1,n=!1;const u=e=>{o||n||(async()=>{if(!r())return null;const e={};let s=!1;for(const{fqdn:a,kind:d,bool:r}of t)try{const t=await c(a);if(o)return e;if(t&&!1===t.success)continue;const i=t?.data;if(null==i)continue;s=!0;const n=r?!!i:String(i);e[d]=n,g({kind:d,value:n})}catch{}return s?e:null})().then(async t=>{if(!o)return t?(n=!0,void await(async e=>{const t=e.active_project_id||e.staged_project_id;if(t&&!e.active_run_id)try{const c={project_id:t};e.active_method_id&&(c.method_id=e.active_method_id);const a=await s("tis.list_tests",MessageType.Request,c);if(o||!a?.success)return;const d=(a.data?.tests??[]).find(e=>"in_progress"===e?.status);if(!d?.run_id)return;g({kind:"active",value:!0}),g({kind:"active_run_id",value:String(d.run_id)}),d.project_id&&g({kind:"active_project_id",value:String(d.project_id)}),d.method_id&&g({kind:"active_method_id",value:String(d.method_id)}),d.sample_id&&g({kind:"active_sample_id",value:String(d.sample_id)})}catch{}})(t)):void(i=setTimeout(()=>u(Math.min(2*e,5e3)),e))})};u(250);const l=a("HUB/connected",()=>{n=!1,u(250)});return()=>{o=!0,i&&clearTimeout(i),d(l),e.forEach(d)}},[a,d,c,r]);const v=useRef({}),[I,j]=useState(0),S=useCallback(()=>j(e=>e+1),[]),k=useCallback((e,t)=>{if(!e)return;const s=v.current[e]??{meta:null,cycles:[],results:{},rawData:{}};v.current[e]={...s,cycles:[...s.cycles,t]},S()},[S]),T=useCallback((e,t)=>{if(!e)return;const s=v.current[e]??{meta:null,cycles:[],results:{},rawData:{}};v.current[e]={...s,results:t},S()},[S]);useEffect(()=>{const e=a("tis.cycle_added",e=>{e?.run_id&&e.cycle&&k(e.run_id,e.cycle)}),t=a("tis.results_updated",e=>{e?.run_id&&T(e.run_id,e.results??{})});return()=>{d(e),d(t)}},[a,d,k,T]);const E=useMemo(()=>({projectId:h.projectId??m.activeProjectId,methodId:h.methodId??(m.activeMethodId||l),sampleId:h.sampleId??m.activeSampleId,runId:h.runId??m.activeRunId}),[h,m,l]),M=useCallback(e=>{C(t=>({projectId:void 0===e.projectId?t.projectId:e.projectId,methodId:void 0===e.methodId?t.methodId:e.methodId,sampleId:void 0===e.sampleId?t.sampleId:e.sampleId,runId:void 0===e.runId?t.runId:e.runId})),void 0!==e.projectId&&s("gnv.ux.selected_project_id",MessageType.Write,e.projectId??"").catch(e=>{})},[s]),x=useRef("");useEffect(()=>{const e=m.activeRunId;e&&e!==x.current&&(x.current=e,C({projectId:null,methodId:null,sampleId:null,runId:null}))},[m.activeRunId]);const R=useCallback(async(e,t)=>{if(!e)return[];const c={project_id:e};t&&(c.method_id=t);try{const e=await s("tis.list_tests",MessageType.Request,c);if(e?.success&&e.data?.tests)return e.data.tests}catch(e){}return[]},[s]),P=useCallback(async(e,t,c)=>{if(!e||!t||!c)return null;try{const a=await s("tis.read_test",MessageType.Request,{project_id:e,method_id:t,run_id:c}),d=await s("tis.read_cycles",MessageType.Request,{project_id:e,method_id:t,run_id:c,offset:0,limit:1e3,order:"asc"});if(!a?.success)return null;const r={meta:a.data??null,cycles:d?.success?d.data?.cycles??[]:[],results:a.data?.results??{},rawData:v.current[c]?.rawData??{}};return v.current[c]=r,S(),r}catch(e){return null}},[s,S]),b=useMemo(()=>({...v.current}),[I]),[F,w]=useState([]),q=useRef(new Set),[Y,A]=useState(0),[L,N]=useState({}),D=useCallback(async()=>{try{const e=await s("tis.list_projects",MessageType.Request,{});e?.success&&e.data?.projects&&w(e.data.projects)}catch(e){}},[s]),O=useCallback(e=>{e&&(q.current.has(e)||(q.current.add(e),A(e=>e+1)))},[]),G=useCallback(e=>!!e&&(!!q.current.has(e)||F.includes(e)),[F,Y]),V=useCallback((e,t)=>{e&&N(s=>({...s,[e]:t}))},[]),B=useCallback(async e=>{if(!e)return null;try{const t=await s("tis.read_project",MessageType.Request,{project_id:e});if(t?.success){const s=t.data?.project_fields??{};return N(t=>({...t,[e]:s})),s}}catch(e){}return N(t=>({...t,[e]:{}})),{}},[s]);useEffect(()=>{D()},[D]),useEffect(()=>{const e=a("tis.project_created",()=>{D()}),t=a("tis.project_updated",e=>{const t="string"==typeof e?.project_id?e.project_id:"";t&&B(t)});return()=>{d(e),d(t)}},[a,d,D,B]),useEffect(()=>{const e=E.projectId;e&&G(e)&&void 0===L[e]&&B(e)},[E.projectId,G,L,B]);const J=L[E.projectId]??{},K=void 0!==L[E.projectId],[H,U]=useState({}),W=useCallback(e=>{U(t=>({...t,...e}))},[]),[z,Q]=useState(""),X=useCallback(e=>{Q(e)},[]),[Z,$]=useState(""),ee=useCallback(()=>{U({}),Q(""),$("")},[]),[te,se]=useState(EMPTY_CYCLE_CONFIG),ce=useMemo(()=>{const e=E.methodId?i[E.methodId]?.cycle_config_fields:void 0;return Array.isArray(e)?e:[]},[i,E.methodId]),ae=useCallback(async()=>{const e=E.projectId,t=E.methodId;if(t)try{const c=await s("tis.cycle_config",MessageType.Request,{project_id:e,method_id:t});if(c?.success)return void se(cycleConfigFromPayload(c.data));se(EMPTY_CYCLE_CONFIG)}catch(e){se(EMPTY_CYCLE_CONFIG)}else se(EMPTY_CYCLE_CONFIG)},[s,E.projectId,E.methodId]),de=useCallback(async e=>{const t=E.projectId,c=E.methodId;if(c)try{const a=await s("tis.set_cycle_config",MessageType.Request,{project_id:t,method_id:c,values:e});a?.success&&se(cycleConfigFromPayload(a.data))}catch(e){}},[s,E.projectId,E.methodId]),re=useCallback(async()=>{const e=E.projectId,t=E.methodId;if(t)try{const c=await s("tis.clear_cycle_config",MessageType.Request,{project_id:e,method_id:t});c?.success&&se(cycleConfigFromPayload(c.data))}catch(e){}},[s,E.projectId,E.methodId]);useEffect(()=>{ae()},[ae]),useEffect(()=>{const e=a("tis.schema_changed",()=>{ae()});return()=>{d(e)}},[a,d,ae]),useEffect(()=>{const e=a("tis.cycle_config",e=>{const t=String(e?.method_id??"");t&&E.methodId&&t!==E.methodId||se(cycleConfigFromPayload(e))});return()=>{d(e)}},[a,d,E.methodId]);const ie=useMemo(()=>({schemas:i,projectAssetRefs:n,defaultMethodId:l,schemasLoaded:p,state:m,selection:E,setSelection:M,existingProjects:F,projectKnown:G,refreshProjects:D,markProjectJustCreated:O,projectFields:J,projectFieldsLoaded:K,loadProjectFields:B,setProjectFields:V,stagedConfig:H,setStagedConfig:W,clearStagedConfig:ee,defaultsAppliedForMethod:z,markDefaultsAppliedForMethod:X,configurationName:Z,setConfigurationName:$,cycleConfig:te,cycleConfigFields:ce,setCycleConfigValues:de,clearCycleConfig:re,refreshCycleConfig:ae,fetchRuns:R,fetchRun:P,runCache:b}),[i,n,l,p,m,E,M,F,G,D,O,J,K,B,V,H,W,ee,z,X,Z,$,te,ce,de,re,ae,R,P,b]);return _jsx(TisContext.Provider,{value:ie,children:e})};export const useTis=()=>useContext(TisContext);export const useTisSchemas=()=>useContext(TisContext).schemas;export const useTisState=()=>useContext(TisContext).state;export const useTisCycleConfig=()=>{const{cycleConfig:e,cycleConfigFields:t,setCycleConfigValues:s,clearCycleConfig:c}=useContext(TisContext);return{...e,fields:t,setValues:s,clear:c}};export const useTisSelection=()=>{const{selection:e,setSelection:t}=useContext(TisContext);return[e,t]};export const useTisRuns=(e,t)=>{const{fetchRuns:s}=useContext(TisContext),[c,a]=useState([]),[d,r]=useState(!1),i=useCallback(async()=>{if(e){r(!0);try{a(await s(e,t))}finally{r(!1)}}else a([])},[e,t,s]);return useEffect(()=>{i()},[i]),{runs:c,loading:d,refresh:i}};export const useTisRun=e=>{const{selection:t,fetchRun:s,runCache:c}=useContext(TisContext),[a,d]=useState(!1),r=e??t.runId;useEffect(()=>{if(!r)return;if(c[r]?.meta)return;const e=t.projectId,a=t.methodId;e&&a&&(d(!0),s(e,a,r).finally(()=>d(!1)))},[r,t.projectId,t.methodId,s,c]);const i=r?c[r]:null;return{meta:i?.meta??null,cycles:i?.cycles??[],results:i?.results??{},rawData:i?.rawData??{},loading:a}};export{TisContext};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adcops/autocore-react",
3
- "version": "3.6.5",
3
+ "version": "3.6.7",
4
4
  "description": "A React component library for industrial user interfaces.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -4,6 +4,7 @@ import { Column } from 'primereact/column';
4
4
  import { Button } from 'primereact/button';
5
5
  import { Badge } from 'primereact/badge';
6
6
  import { Menu } from 'primereact/menu';
7
+ import { Toast } from 'primereact/toast';
7
8
  import { confirmDialog } from 'primereact/confirmdialog';
8
9
  import { EventEmitterContext } from '../../core/EventEmitterContext';
9
10
  import { MessageType } from '../../hub/CommandMessage';
@@ -63,6 +64,31 @@ const downloadViaUrl = (url: string, filename: string) => {
63
64
  a.remove();
64
65
  };
65
66
 
67
+ /**
68
+ * What each lifecycle action tells the operator once the server has agreed.
69
+ * A table rather than a switch so the wording for an action lives in exactly
70
+ * one place, next to the other two it has to read consistently with.
71
+ */
72
+ const LIFECYCLE_DONE: Record<
73
+ 'complete' | 'abandon' | 'reopen',
74
+ { summary: string; detail: (label: string) => string }
75
+ > = {
76
+ complete: {
77
+ summary: 'Test closed',
78
+ detail: (l) => `${l} is now Completed. It can still be reopened.`,
79
+ },
80
+ abandon: {
81
+ summary: 'Test abandoned',
82
+ detail: (l) =>
83
+ `${l} is out of the history and out of the sample averages. ` +
84
+ `Its data is still on disk — use Show abandoned to see it.`,
85
+ },
86
+ reopen: {
87
+ summary: 'Test reopened',
88
+ detail: (l) => `${l} is open again — new cycles are added to it.`,
89
+ },
90
+ };
91
+
66
92
  type DownloadKind = 'data' | 'report';
67
93
  type InFlight = { runId: string; kind: DownloadKind };
68
94
  type ProjectDownloadKind = 'report' | 'archive';
@@ -92,10 +118,23 @@ export const ResultHistoryTable: React.FC<ResultHistoryTableProps> = (props) =>
92
118
  useState<{ row: any; anchor: HTMLElement; seq: number } | null>(null);
93
119
  const menuSeqRef = useRef(0);
94
120
  const [lifecycleBusy, setLifecycleBusy] = useState<string | null>(null);
121
+ // Abandoned runs are hidden by default — see `visibleTests`. The toggle
122
+ // is how they stay auditable without cluttering the operator's list.
123
+ const [showAbandoned, setShowAbandoned] = useState(false);
124
+ const toastRef = useRef<Toast>(null);
95
125
  const { invoke } = useContext(EventEmitterContext);
96
126
 
127
+ // Guards `setTests` against a stale response. `loadTests` is called both
128
+ // directly (Refresh, and after a lifecycle action) and from an effect that
129
+ // re-fires on every active-run change, so two fetches are routinely in
130
+ // flight at once. Without this the OLDER response can land last and put
131
+ // the row the operator just closed back to "Interrupted" — which reads,
132
+ // correctly, as "the button did nothing".
133
+ const loadSeqRef = useRef(0);
134
+
97
135
  const loadTests = async () => {
98
136
  if (!projectId) { setTests([]); return; }
137
+ const seq = ++loadSeqRef.current;
99
138
  setLoading(true);
100
139
  try {
101
140
  // When the parent omits methodId, ask the server for all runs
@@ -105,13 +144,16 @@ export const ResultHistoryTable: React.FC<ResultHistoryTableProps> = (props) =>
105
144
  if (methodId) payload.method_id = methodId;
106
145
 
107
146
  const resp: any = await invoke('tis.list_tests' as any, MessageType.Request, payload as any);
147
+ // A newer fetch has already been issued (or has already landed):
148
+ // this answer is history, and applying it would undo the newer one.
149
+ if (seq !== loadSeqRef.current) return;
108
150
  if (resp.success && resp.data && resp.data.tests) {
109
151
  setTests(resp.data.tests);
110
152
  }
111
153
  } catch (err) {
112
154
  console.error("Failed to load tests", err);
113
155
  }
114
- setLoading(false);
156
+ if (seq === loadSeqRef.current) setLoading(false);
115
157
  };
116
158
 
117
159
  useEffect(() => {
@@ -227,6 +269,7 @@ export const ResultHistoryTable: React.FC<ResultHistoryTableProps> = (props) =>
227
269
  action === 'complete' ? 'tis.finish_test'
228
270
  : action === 'abandon' ? 'tis.reset_test'
229
271
  : 'tis.resume_test';
272
+ const label = rowData?.sample_id || runId;
230
273
  setLifecycleBusy(runId);
231
274
  try {
232
275
  const resp: any = await invoke(topic as any, MessageType.Request, {
@@ -241,6 +284,16 @@ export const ResultHistoryTable: React.FC<ResultHistoryTableProps> = (props) =>
241
284
  return;
242
285
  }
243
286
  await loadTests();
287
+ // Say what happened. Close and Abandon both leave the run on disk
288
+ // and change only a badge — one of them then hides the row — so
289
+ // without an acknowledgement the operator has no way to tell a
290
+ // successful action from a dead button, and reports the second.
291
+ toastRef.current?.show({
292
+ severity: action === 'abandon' ? 'warn' : 'success',
293
+ summary: LIFECYCLE_DONE[action].summary,
294
+ detail: LIFECYCLE_DONE[action].detail(label),
295
+ life: 4000,
296
+ });
244
297
  } catch (err) {
245
298
  console.error(`Failed to ${action} test`, err);
246
299
  alert(`${action} failed: ${err instanceof Error ? err.message : String(err)}`);
@@ -259,7 +312,8 @@ export const ResultHistoryTable: React.FC<ResultHistoryTableProps> = (props) =>
259
312
  * - completed but not finalized → Reopen (add more cycles under the same
260
313
  * Test ID — the multi-specimen case where a set turned out to be bigger)
261
314
  * - finalized (abandoned) → nothing; `finalized` exists precisely to
262
- * stop a deliberately-abandoned run being resurrected.
315
+ * stop a deliberately-abandoned run being resurrected. Only reachable
316
+ * at all with `Show abandoned` on.
263
317
  */
264
318
  const rowMenuItems = (rowData: any) => {
265
319
  const status = rowData?.status;
@@ -442,6 +496,19 @@ export const ResultHistoryTable: React.FC<ResultHistoryTableProps> = (props) =>
442
496
  return '';
443
497
  };
444
498
 
499
+ /**
500
+ * Abandoning a run is the operator saying "this one never happened":
501
+ * TIS drops it from the sample aggregates, and it drops out of this list
502
+ * too. Nothing is deleted — `Show abandoned` brings the rows back with an
503
+ * "Abandoned" badge — but the default view is the set of runs that still
504
+ * count for something, which is what an operator scanning the history is
505
+ * actually looking for.
506
+ */
507
+ const abandonedCount = tests.filter((t) => t?.finalized === true).length;
508
+ const visibleTests = showAbandoned
509
+ ? tests
510
+ : tests.filter((t) => t?.finalized !== true);
511
+
445
512
  // Lifecycle status badge. `status`/`finalized` are written by the TIS
446
513
  // servelet (start_test → in_progress, pause_test → paused, finish_test →
447
514
  // completed, reset_test → finalized). Runs recorded before this field
@@ -477,6 +544,23 @@ export const ResultHistoryTable: React.FC<ResultHistoryTableProps> = (props) =>
477
544
  : 'Test History (no project selected)'}
478
545
  </h3>
479
546
  <div style={{ display: 'flex', gap: '0.4rem', alignItems: 'center' }}>
547
+ {/* Only offered when there is something to reveal, so the
548
+ ordinary machine never shows a control for a state it
549
+ has never been in. */}
550
+ {abandonedCount > 0 && (
551
+ <Button
552
+ icon={showAbandoned ? 'pi pi-eye-slash' : 'pi pi-eye'}
553
+ label={
554
+ showAbandoned
555
+ ? 'Hide abandoned'
556
+ : `Show abandoned (${abandonedCount})`
557
+ }
558
+ size="small"
559
+ outlined
560
+ severity="secondary"
561
+ onClick={() => setShowAbandoned((v) => !v)}
562
+ />
563
+ )}
480
564
  <Button
481
565
  icon={projectBusy === 'report' ? 'pi pi-spin pi-spinner' : 'pi pi-file'}
482
566
  label="Download Report"
@@ -513,7 +597,7 @@ export const ResultHistoryTable: React.FC<ResultHistoryTableProps> = (props) =>
513
597
  <SampleSummaryPanel projectId={projectId} methodId={methodId} />
514
598
 
515
599
  <DataTable
516
- value={tests}
600
+ value={visibleTests}
517
601
  loading={loading}
518
602
  paginator
519
603
  rows={10}
@@ -671,6 +755,13 @@ export const ResultHistoryTable: React.FC<ResultHistoryTableProps> = (props) =>
671
755
  popup
672
756
  ref={rowMenuRef}
673
757
  />
758
+ {/* Owned by this component rather than the host app: the library
759
+ cannot assume a consumer has a global message host, and the
760
+ acknowledgement has to appear wherever the table is used.
761
+ Top-right, not bottom: on a machine HMI the bottom strip is the
762
+ control bar, and a message that covers Start/Stop for four
763
+ seconds is worse than no message at all. */}
764
+ <Toast ref={toastRef} position="top-right" />
674
765
  </div>
675
766
  );
676
767
  };
@@ -856,7 +856,10 @@ export const TestDataView: React.FC<TestDataViewProps> = (props) => {
856
856
  !runId && 'run',
857
857
  !schema && 'method definition',
858
858
  ].filter(Boolean).join(', ');
859
- const canRecover = !!tis.state.active && !!tis.state.activeRunId;
859
+ // Keyed on `active` ALONE. Requiring activeRunId here was exactly
860
+ // backwards: an empty run id is the state this button exists to escape,
861
+ // so gating on it hid the button in the only case that needed it.
862
+ const canRecover = !!tis.state.active;
860
863
  return (
861
864
  <div className="p-card" style={{ padding: '1rem', color: 'var(--text-secondary-color)' }}>
862
865
  {canRecover ? (
@@ -554,30 +554,89 @@ export const TisProvider: React.FC<TisProviderProps> = ({ children, defaultMetho
554
554
  let seeded = false;
555
555
  let timer: ReturnType<typeof setTimeout> | undefined;
556
556
 
557
- const seedOnce = async (): Promise<boolean> => {
558
- if (!isConnected()) return false;
557
+ // What the last seed actually read, so the heal below can reason about
558
+ // it `dispatch` lands in a reducer and cannot be read back here.
559
+ const seedOnce = async (): Promise<Record<string, any> | null> => {
560
+ if (!isConnected()) return null;
561
+ const got: Record<string, any> = {};
559
562
  let sawValue = false;
560
563
  for (const { fqdn, kind, bool } of SEED) {
561
564
  try {
562
565
  const resp: any = await read(fqdn);
563
- if (cancelled) return true;
566
+ if (cancelled) return got;
564
567
  if (resp && resp.success === false) continue;
565
568
  const v = resp?.data;
566
569
  if (v === undefined || v === null) continue;
567
570
  sawValue = true;
568
- dispatch({ kind, value: bool ? !!v : String(v) } as StateAction);
571
+ const value = bool ? !!v : String(v);
572
+ got[kind] = value;
573
+ dispatch({ kind, value } as StateAction);
569
574
  } catch {
570
575
  /* scalar absent on this machine — nothing to seed */
571
576
  }
572
577
  }
573
- return sawValue;
578
+ return sawValue ? got : null;
579
+ };
580
+
581
+ /**
582
+ * Ask TIS which run is open, when the GM mirror cannot say.
583
+ *
584
+ * The `tis_active_*` GM scalars are a MIRROR, not the authority. TIS
585
+ * broadcasts them once, at start_test / resume_test, and the server
586
+ * copies each broadcast into its GM variable. Nothing ever re-asserts
587
+ * them — so a broadcast that is missed for any reason (a module
588
+ * restarting mid-test is the obvious one) leaves that scalar empty for
589
+ * the rest of the run with nothing to put it back.
590
+ *
591
+ * Observed on a machine 2026-09-02, mid-test: `tis_active` true,
592
+ * project / method / sample / cycle_count all correct, and
593
+ * `tis_active_run_id` an empty string. The Test screen looked fine
594
+ * because it does not need the run id; the Data view needs it and so
595
+ * showed "No test selected" against a plainly running test.
596
+ *
597
+ * TIS itself never lost it — `tis.list_tests` reported the run as
598
+ * `in_progress` throughout. So ask the authority. This is not a
599
+ * fallback for a rare case; it is the correct source, with the GM
600
+ * scalars kept for what they are good at (zero-latency live updates).
601
+ */
602
+ const healFromTis = async (got: Record<string, any>): Promise<void> => {
603
+ const projectId = got['active_project_id'] || got['staged_project_id'];
604
+ if (!projectId) return;
605
+ // Only when the mirror is incomplete. A run id we already have is
606
+ // the operator's current selection and must not be second-guessed.
607
+ if (got['active_run_id']) return;
608
+ try {
609
+ const payload: any = { project_id: projectId };
610
+ if (got['active_method_id']) payload.method_id = got['active_method_id'];
611
+ const resp: any = await invoke('tis.list_tests' as any, MessageType.Request, payload);
612
+ if (cancelled || !resp?.success) return;
613
+ const tests: any[] = resp.data?.tests ?? [];
614
+ const open = tests.find((t) => t?.status === 'in_progress');
615
+ if (!open?.run_id) return;
616
+ console.warn(
617
+ '[TisProvider] gm.tis_active_run_id was empty while TIS reports run '
618
+ + `"${open.run_id}" in progress; recovering from TIS.`,
619
+ );
620
+ dispatch({ kind: 'active', value: true } as StateAction);
621
+ dispatch({ kind: 'active_run_id', value: String(open.run_id) } as StateAction);
622
+ if (open.project_id) dispatch({ kind: 'active_project_id', value: String(open.project_id) } as StateAction);
623
+ if (open.method_id) dispatch({ kind: 'active_method_id', value: String(open.method_id) } as StateAction);
624
+ if (open.sample_id) dispatch({ kind: 'active_sample_id', value: String(open.sample_id) } as StateAction);
625
+ } catch {
626
+ /* TIS unreachable — the retry above will come back round */
627
+ }
574
628
  };
575
629
 
576
630
  const attempt = (delayMs: number) => {
577
631
  if (cancelled || seeded) return;
578
- void seedOnce().then((ok) => {
632
+ void seedOnce().then(async (got) => {
579
633
  if (cancelled) return;
580
- if (ok) { seeded = true; return; }
634
+ if (got) {
635
+ seeded = true;
636
+ // The mirror answered; make sure it answered COMPLETELY.
637
+ await healFromTis(got);
638
+ return;
639
+ }
581
640
  // Back off, but stay bounded: an operator who refreshes while
582
641
  // the server is still coming up must not be left staring at a
583
642
  // screen that will never fill in.