@adcops/autocore-react 3.3.97 → 3.3.100
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,KAA0C,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"ResultHistoryTable.d.ts","sourceRoot":"","sources":["../../../src/components/tis/ResultHistoryTable.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA0C,MAAM,OAAO,CAAC;AAS/D,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,CAoThE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React,{useState,useEffect,useContext}from"react";import{DataTable}from"primereact/datatable";import{Column}from"primereact/column";import{Button}from"primereact/button";import{EventEmitterContext}from"../../core/EventEmitterContext";import{MessageType}from"../../hub/CommandMessage";import{useTis}from"./TisProvider";const downloadCsvBlob=(e,t)=>{const o=new Blob([t],{type:"text/csv;charset=utf-8;"}),r=URL.createObjectURL(o),
|
|
1
|
+
import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React,{useState,useEffect,useContext}from"react";import{DataTable}from"primereact/datatable";import{Column}from"primereact/column";import{Button}from"primereact/button";import{Tag}from"primereact/tag";import{EventEmitterContext}from"../../core/EventEmitterContext";import{MessageType}from"../../hub/CommandMessage";import{useTis}from"./TisProvider";const downloadCsvBlob=(e,t)=>{const o=new Blob([t],{type:"text/csv;charset=utf-8;"}),r=URL.createObjectURL(o),s=document.createElement("a");s.href=r,s.download=e,document.body.appendChild(s),s.click(),s.remove(),URL.revokeObjectURL(r)},downloadViaUrl=(e,t)=>{const o=document.createElement("a");o.href=e,o.download=t,document.body.appendChild(o),o.click(),o.remove()};export const ResultHistoryTable=e=>{const t=useTis(),o=e.projectId??t.selection.projectId,r=e.methodId,[s,i]=useState([]),[a,n]=useState(!1),[l,d]=useState(null),[c,p]=useState(null),{invoke:u}=useContext(EventEmitterContext),m=async()=>{if(o){n(!0);try{const e={project_id:o};r&&(e.method_id=r);const t=await u("tis.list_tests",MessageType.Request,e);t.success&&t.data&&t.data.tests&&i(t.data.tests)}catch(e){}n(!1)}else i([])};useEffect(()=>{m()},[o,r,t.state.activeRunId,t.state.active]);const f=async(e,t)=>{const s=e?.run_id,i=e?.method_id??r;if(!s||!i||!o)return;const a="report"===t?"tis.export_test_csv":"tis.export_test_data_csv",n="report"===t?"test report":"test data";d({runId:s,kind:t});try{const e=await u(a,MessageType.Request,{project_id:o,method_id:i,run_id:s});if(!e?.success)return void alert(`Failed to build ${n} for ${s}`+(e?.error_message?`: ${e.error_message}`:""));const r="string"==typeof e.data?.filename&&e.data.filename?e.data.filename:`${o}_${i}_${s}_${t}.csv`;if("report"===t){const t="string"==typeof e.data?.csv?e.data.csv:"";if(!t)return void alert(`${n} for ${s} is empty.`);downloadCsvBlob(r,t)}else{const t="string"==typeof e.data?.download_url?e.data.download_url:"";if(!t)return void alert(`Server did not return a download URL for ${n}.`);downloadViaUrl(t,r)}}catch(e){alert(`Download failed: ${e instanceof Error?e.message:String(e)}`)}finally{d(null)}},_=async e=>{if(!o)return;const t="report"===e?"tis.export_project_csv":"tis.export_project_zip",r="report"===e?"project report":"project archive";p(e);try{const s=await u(t,MessageType.Request,{project_id:o});if(!s?.success)return void alert(`Failed to build ${r}`+(s?.error_message?`: ${s.error_message}`:""));const i="string"==typeof s.data?.download_url?s.data.download_url:"";if(!i)return void alert(`Server did not return a download URL for ${r}.`);const a="report"===e?`${o}_project_report.csv`:`${o}_project_archive.zip`,n="string"==typeof s.data?.filename&&s.data.filename?s.data.filename:a;downloadViaUrl(i,n)}catch(e){alert(`Download failed: ${e instanceof Error?e.message:String(e)}`)}finally{p(null)}},y=e=>{const t="string"==typeof e?.sample_id?e.sample_id:"";if(t)return t;const o=e?.config;return o&&"object"==typeof o&&"string"==typeof o.sample_id?o.sample_id:""};return _jsxs("div",{style:{width:"100%",maxWidth:"100%",overflow:"hidden",boxSizing:"border-box"},children:[_jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:"1rem",gap:"0.5rem",flexWrap:"wrap"},children:[_jsx("h3",{style:{margin:0},children:o?`Test History: ${o}${r?` / ${r}`:""}`:"Test History (no project selected)"}),_jsxs("div",{style:{display:"flex",gap:"0.4rem",alignItems:"center"},children:[_jsx(Button,{icon:"report"===c?"pi pi-spin pi-spinner":"pi pi-file",label:"Download Report",size:"small",outlined:!0,disabled:!o||null!==c,onClick:()=>_("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:()=>_("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:m,disabled:a})]})]}),_jsxs(DataTable,{value:s,loading:a,paginator:!0,rows:10,emptyMessage:"No tests found.",scrollable:!0,scrollHeight:"flex",tableStyle:{minWidth:0},style:{width:"100%"},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:y,sortFunction:e=>{const t=[...e.data];return t.sort((t,o)=>y(t).localeCompare(y(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,{field:"run_id",header:"Run ID",sortable:!0,style:{minWidth:"12rem"}}),_jsx(Column,{header:"Status",field:"status",sortable:!0,body:e=>{const t=(e=>{if(!0===e?.finalized)return{label:"Abandoned",severity:"danger"};const t="string"==typeof e?.status?e.status:"completed";switch(t){case"in_progress":return{label:"In Progress",severity:"info"};case"paused":return{label:"Paused",severity:"warning"};case"completed":return{label:"Completed",severity:"success"};default:return{label:t,severity:void 0}}})(e);return _jsx(Tag,{value:t.label,severity:t.severity})},style:{minWidth:"8rem"}}),_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,r=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:r,onClick:()=>f(e,"data"),tooltip:"Download raw + filtered trace data as one CSV",tooltipOptions:{position:"left"}}),_jsx(Button,{icon:o?"pi pi-spin pi-spinner":"pi pi-file",label:"Results",size:"small",outlined:!0,disabled:r,onClick:()=>f(e,"report"),tooltip:"Download a CSV report (metadata + cycles + results) for this test",tooltipOptions:{position:"left"}})]})}})]})]})};
|
package/package.json
CHANGED
|
@@ -2,6 +2,7 @@ import React, { useState, useEffect, useContext } from 'react';
|
|
|
2
2
|
import { DataTable } from 'primereact/datatable';
|
|
3
3
|
import { Column } from 'primereact/column';
|
|
4
4
|
import { Button } from 'primereact/button';
|
|
5
|
+
import { Tag } from 'primereact/tag';
|
|
5
6
|
import { EventEmitterContext } from '../../core/EventEmitterContext';
|
|
6
7
|
import { MessageType } from '../../hub/CommandMessage';
|
|
7
8
|
import { useTis } from './TisProvider';
|
|
@@ -95,12 +96,17 @@ export const ResultHistoryTable: React.FC<ResultHistoryTableProps> = (props) =>
|
|
|
95
96
|
|
|
96
97
|
useEffect(() => {
|
|
97
98
|
loadTests();
|
|
98
|
-
//
|
|
99
|
-
//
|
|
100
|
-
//
|
|
101
|
-
//
|
|
99
|
+
// Refresh whenever the live run changes state, so the Status column
|
|
100
|
+
// tracks the run without a manual click:
|
|
101
|
+
// • activeRunId — a fresh Start opens a new run_id we want to surface.
|
|
102
|
+
// • active (the bool) — finish/pause/resume flip this. On finish the
|
|
103
|
+
// server keeps broadcasting the SAME active_run_id (only `active`
|
|
104
|
+
// goes false), so depending on activeRunId alone misses end-of-test
|
|
105
|
+
// and the row stays stuck on "In Progress" until a manual refresh.
|
|
106
|
+
// The server patches test.json BEFORE broadcasting active=false, so
|
|
107
|
+
// this refetch reads the already-stamped completed/paused status.
|
|
102
108
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
103
|
-
}, [projectId, methodId, tis.state.activeRunId]);
|
|
109
|
+
}, [projectId, methodId, tis.state.activeRunId, tis.state.active]);
|
|
104
110
|
|
|
105
111
|
const formatDate = (dateStr: string) => {
|
|
106
112
|
if (!dateStr) return '';
|
|
@@ -220,6 +226,21 @@ export const ResultHistoryTable: React.FC<ResultHistoryTableProps> = (props) =>
|
|
|
220
226
|
return '';
|
|
221
227
|
};
|
|
222
228
|
|
|
229
|
+
// Lifecycle status badge. `status`/`finalized` are written by the TIS
|
|
230
|
+
// servelet (start_test → in_progress, pause_test → paused, finish_test →
|
|
231
|
+
// completed, reset_test → finalized). Runs recorded before this field
|
|
232
|
+
// existed have neither; treat them as completed (they're long since done).
|
|
233
|
+
const statusOf = (rowData: any): { label: string; severity: 'success' | 'info' | 'warning' | 'danger' | undefined } => {
|
|
234
|
+
if (rowData?.finalized === true) return { label: 'Abandoned', severity: 'danger' };
|
|
235
|
+
const status = typeof rowData?.status === 'string' ? rowData.status : 'completed';
|
|
236
|
+
switch (status) {
|
|
237
|
+
case 'in_progress': return { label: 'In Progress', severity: 'info' };
|
|
238
|
+
case 'paused': return { label: 'Paused', severity: 'warning' };
|
|
239
|
+
case 'completed': return { label: 'Completed', severity: 'success' };
|
|
240
|
+
default: return { label: status, severity: undefined };
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
|
|
223
244
|
return (
|
|
224
245
|
// Outer wrapper pins the whole component to its container's width.
|
|
225
246
|
// `overflow: hidden` keeps a wide row from pushing the table past the
|
|
@@ -307,6 +328,13 @@ export const ResultHistoryTable: React.FC<ResultHistoryTableProps> = (props) =>
|
|
|
307
328
|
/>
|
|
308
329
|
<Column field="method_id" header="Test Method" sortable style={{ minWidth: '10rem' }} />
|
|
309
330
|
<Column field="run_id" header="Run ID" sortable style={{ minWidth: '12rem' }} />
|
|
331
|
+
<Column header="Status" field="status" sortable
|
|
332
|
+
body={(rowData) => {
|
|
333
|
+
const s = statusOf(rowData);
|
|
334
|
+
return <Tag value={s.label} severity={s.severity} />;
|
|
335
|
+
}}
|
|
336
|
+
style={{ minWidth: '8rem' }}
|
|
337
|
+
/>
|
|
310
338
|
<Column
|
|
311
339
|
header="Download"
|
|
312
340
|
style={{ width: '14rem' }}
|