@adcops/autocore-react 3.3.109 → 3.3.112

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/assets/JogXLeft.d.ts +4 -0
  2. package/dist/assets/JogXLeft.d.ts.map +1 -0
  3. package/dist/assets/JogXLeft.js +1 -0
  4. package/dist/assets/JogXRight.d.ts +4 -0
  5. package/dist/assets/JogXRight.d.ts.map +1 -0
  6. package/dist/assets/JogXRight.js +1 -0
  7. package/dist/assets/JogYDownLeft.d.ts +4 -0
  8. package/dist/assets/JogYDownLeft.d.ts.map +1 -0
  9. package/dist/assets/JogYDownLeft.js +1 -0
  10. package/dist/assets/JogYUpRight.d.ts +4 -0
  11. package/dist/assets/JogYUpRight.d.ts.map +1 -0
  12. package/dist/assets/JogYUpRight.js +1 -0
  13. package/dist/assets/index.d.ts +4 -4
  14. package/dist/assets/index.d.ts.map +1 -1
  15. package/dist/assets/index.js +1 -1
  16. package/dist/components/JogPanel.d.ts +29 -4
  17. package/dist/components/JogPanel.d.ts.map +1 -1
  18. package/dist/components/JogPanel.js +1 -1
  19. package/dist/components/ValueInput.d.ts.map +1 -1
  20. package/dist/components/ValueInput.js +1 -1
  21. package/dist/components/network/StagedChangeBanner.d.ts.map +1 -1
  22. package/dist/components/network/StagedChangeBanner.js +1 -1
  23. package/dist/components/tis/ResultHistoryTable.d.ts.map +1 -1
  24. package/dist/components/tis/ResultHistoryTable.js +1 -1
  25. package/dist/components/tis/ScienceTable.css +87 -0
  26. package/dist/components/tis/ScienceTable.d.ts +35 -0
  27. package/dist/components/tis/ScienceTable.d.ts.map +1 -0
  28. package/dist/components/tis/ScienceTable.js +1 -0
  29. package/dist/components/tis/TestDataView.d.ts.map +1 -1
  30. package/dist/components/tis/TestDataView.js +1 -1
  31. package/dist/components/tis/TestSetupForm.d.ts.map +1 -1
  32. package/dist/components/tis/TestSetupForm.js +1 -1
  33. package/package.json +1 -1
  34. package/src/assets/{JogXNeg.tsx → JogXLeft.tsx} +6 -3
  35. package/src/assets/{JogXPos.tsx → JogXRight.tsx} +6 -3
  36. package/src/assets/{JogYPos.tsx → JogYDownLeft.tsx} +2 -2
  37. package/src/assets/{JogYNeg.tsx → JogYUpRight.tsx} +3 -2
  38. package/src/assets/index.ts +4 -4
  39. package/src/components/JogPanel.tsx +64 -59
  40. package/src/components/ValueInput.tsx +10 -3
  41. package/src/components/network/StagedChangeBanner.tsx +22 -3
  42. package/src/components/tis/ResultHistoryTable.tsx +19 -8
  43. package/src/components/tis/ScienceTable.css +87 -0
  44. package/src/components/tis/ScienceTable.tsx +114 -0
  45. package/src/components/tis/TestDataView.tsx +49 -54
  46. package/src/components/tis/TestSetupForm.tsx +6 -2
  47. package/dist/assets/JogXNeg.d.ts +0 -4
  48. package/dist/assets/JogXNeg.d.ts.map +0 -1
  49. package/dist/assets/JogXNeg.js +0 -1
  50. package/dist/assets/JogXPos.d.ts +0 -4
  51. package/dist/assets/JogXPos.d.ts.map +0 -1
  52. package/dist/assets/JogXPos.js +0 -1
  53. package/dist/assets/JogYNeg.d.ts +0 -4
  54. package/dist/assets/JogYNeg.d.ts.map +0 -1
  55. package/dist/assets/JogYNeg.js +0 -1
  56. package/dist/assets/JogYPos.d.ts +0 -4
  57. package/dist/assets/JogYPos.d.ts.map +0 -1
  58. package/dist/assets/JogYPos.js +0 -1
@@ -0,0 +1,114 @@
1
+ /*
2
+ * Copyright (C) 2026 Automated Design Corp. All Rights Reserved.
3
+ *
4
+ * ScienceTable — a presentational wrapper around PrimeReact's DataTable that
5
+ * gives cycle-data and results tables the crisp, "instrument report" look of
6
+ * a materials-testing readout (à la Instron Bluehill): a dark title bar, a
7
+ * dark column-header band with the unit in brackets on a second line, a dark
8
+ * row-index column, and pale data cells with thin gridlines and centered,
9
+ * tabular-aligned values.
10
+ *
11
+ * Purely visual — it takes rows + a column spec and renders them; it holds no
12
+ * data-fetching or business logic. Styling lives in ScienceTable.css, scoped
13
+ * to `.p-datatable.ac-science-table` so it never leaks onto other DataTables.
14
+ */
15
+
16
+ import React from 'react';
17
+ import { DataTable } from 'primereact/datatable';
18
+ import { Column } from 'primereact/column';
19
+ import type { ColumnBodyOptions } from 'primereact/column';
20
+ import './ScienceTable.css';
21
+
22
+ export interface ScienceColumn {
23
+ /** Row property to read. */
24
+ field: string;
25
+ /** Header label (unit rendered separately in brackets). */
26
+ label: string;
27
+ /** Optional unit, shown as `[unit]` on a second header line. */
28
+ units?: string;
29
+ /** Cell text alignment. Default 'center' (report style). */
30
+ align?: 'left' | 'center' | 'right';
31
+ /** Optional custom cell renderer (e.g. numeric formatting). */
32
+ body?: (row: any) => React.ReactNode;
33
+ /** Optional per-column style (e.g. minWidth). */
34
+ style?: React.CSSProperties;
35
+ }
36
+
37
+ export interface ScienceTableProps {
38
+ /** Title shown in the dark bar above the table. Omit for no bar. */
39
+ title?: React.ReactNode;
40
+ columns: ScienceColumn[];
41
+ rows: any[];
42
+ /** Leading 1-based row-index column, like the Bluehill "1". Default true. */
43
+ showIndex?: boolean;
44
+ /** Header for the index column. Default "#". */
45
+ indexHeader?: string;
46
+ emptyMessage?: string;
47
+ /** Enable virtual scrolling; pair with `scrollHeight` for large runs. */
48
+ scrollable?: boolean;
49
+ scrollHeight?: string;
50
+ /** Virtual-scroll row height in px. Default 38. */
51
+ virtualItemSize?: number;
52
+ }
53
+
54
+ const HeaderCell: React.FC<{ column: ScienceColumn }> = ({ column }) => (
55
+ <div className="ac-sci-th">
56
+ <span className="ac-sci-th-name">{column.label}</span>
57
+ {column.units ? <span className="ac-sci-th-unit">[{column.units}]</span> : null}
58
+ </div>
59
+ );
60
+
61
+ export const ScienceTable: React.FC<ScienceTableProps> = ({
62
+ title,
63
+ columns,
64
+ rows,
65
+ showIndex = true,
66
+ indexHeader = '#',
67
+ emptyMessage = 'No data.',
68
+ scrollable = false,
69
+ scrollHeight,
70
+ virtualItemSize = 38,
71
+ }) => {
72
+ const virtual = scrollable && !!scrollHeight;
73
+ return (
74
+ <div className="ac-science-table-wrap">
75
+ {title != null && <div className="ac-science-table-title">{title}</div>}
76
+ <div className="ac-science-table-scroll">
77
+ <DataTable
78
+ className="ac-science-table"
79
+ value={rows}
80
+ scrollable={scrollable}
81
+ scrollHeight={scrollHeight}
82
+ virtualScrollerOptions={virtual ? { itemSize: virtualItemSize } : undefined}
83
+ emptyMessage={emptyMessage}
84
+ >
85
+ {showIndex ? (
86
+ <Column
87
+ header={indexHeader}
88
+ headerClassName="ac-sci-index"
89
+ bodyClassName="ac-sci-index"
90
+ align="center"
91
+ alignHeader="center"
92
+ style={{ width: '3.5rem', maxWidth: '3.5rem' }}
93
+ body={(_data: any, options: ColumnBodyOptions) => options.rowIndex + 1}
94
+ />
95
+ ) : null}
96
+ {columns.map((c) => (
97
+ <Column
98
+ key={c.field}
99
+ field={c.field}
100
+ header={<HeaderCell column={c} />}
101
+ align={c.align ?? 'center'}
102
+ alignHeader="center"
103
+ style={c.style}
104
+ bodyClassName="ac-sci-cell"
105
+ body={c.body ? (row: any) => c.body!(row) : undefined}
106
+ />
107
+ ))}
108
+ </DataTable>
109
+ </div>
110
+ </div>
111
+ );
112
+ };
113
+
114
+ export default ScienceTable;
@@ -44,6 +44,8 @@ import { EventEmitterContext } from '../../core/EventEmitterContext';
44
44
  import { MessageType } from '../../hub/CommandMessage';
45
45
  import { useTis } from './TisProvider';
46
46
  import { useRawCycleData } from './useRawCycleData';
47
+ import { ScienceTable } from './ScienceTable';
48
+ import type { ScienceColumn } from './ScienceTable';
47
49
 
48
50
  ChartJS.register(
49
51
  CategoryScale, LinearScale, PointElement, LineElement,
@@ -733,42 +735,53 @@ export const TestDataView: React.FC<TestDataViewProps> = (props) => {
733
735
  </div>
734
736
  </div>
735
737
 
736
- <div className="p-card" style={{ padding: '1rem' }}>
737
- <h3 style={{ marginTop: 0 }}>Cycle Data ({cycles.length})</h3>
738
- {/* Size-to-content for small runs (≤ CYCLE_VIRTUAL_THRESHOLD
739
- rows) so the Results panel below isn't pushed off-screen
740
- on tests with one or two cycles. Larger runs flip to
741
- virtual scrolling against `cycleTableHeight` so a
742
- 1000-cycle test doesn't render 1000 row elements at
743
- once. Operators on test methods that always run a
744
- fixed-size short cycle list see no scrollbar at all. */}
745
- {(() => {
746
- const useVirtual = cycles.length > CYCLE_VIRTUAL_THRESHOLD;
747
- return (
748
- <DataTable
749
- value={cycles}
750
- scrollable={useVirtual}
751
- scrollHeight={useVirtual ? cycleTableHeight : undefined}
752
- virtualScrollerOptions={useVirtual ? { itemSize: 38 } : undefined}
753
- emptyMessage="No cycles yet."
754
- >
755
- {schema.cycle_fields.map(f => (
756
- <Column key={f.name} field={f.name}
757
- header={f.units ? `${f.name} (${f.units})` : f.name}
758
- body={(row) => formatCell(row[f.name], f.type, f.scale)} />
759
- ))}
760
- </DataTable>
761
- );
762
- })()}
763
- </div>
764
-
765
- <div className="p-card" style={{ padding: '1rem' }}>
766
- <h3 style={{ marginTop: 0 }}>Results</h3>
767
- {/* Overlay the server-derived cross-test rollup (avg/min/max/
768
- stddev/count) onto this run's own results. Aggregate fields
769
- are never in `results` — the summary is their only source. */}
770
- <ResultsGrid schema={schema.results_fields} values={{ ...results, ...sampleSummary }} />
771
- </div>
738
+ {/* Size-to-content for small runs (≤ CYCLE_VIRTUAL_THRESHOLD
739
+ rows) so the Results panel below isn't pushed off-screen on
740
+ tests with one or two cycles. Larger runs flip to virtual
741
+ scrolling against `cycleTableHeight` so a 1000-cycle test
742
+ doesn't render 1000 row elements at once. */}
743
+ {(() => {
744
+ const useVirtual = cycles.length > CYCLE_VIRTUAL_THRESHOLD;
745
+ const cycleColumns: ScienceColumn[] = schema.cycle_fields.map(f => ({
746
+ field: f.name,
747
+ label: f.name,
748
+ units: f.units,
749
+ body: (row) => formatCell(row[f.name], f.type, f.scale),
750
+ }));
751
+ return (
752
+ <ScienceTable
753
+ title={`Cycle Data (${cycles.length})`}
754
+ columns={cycleColumns}
755
+ rows={cycles}
756
+ scrollable={useVirtual}
757
+ scrollHeight={useVirtual ? cycleTableHeight : undefined}
758
+ emptyMessage="No cycles yet."
759
+ />
760
+ );
761
+ })()}
762
+
763
+ {/* Overlay the server-derived cross-test rollup (avg/min/max/
764
+ stddev/count) onto this run's own results. Aggregate fields
765
+ are never in `results` — the summary is their only source.
766
+ Rendered as a single-row report table (Bluehill style). */}
767
+ {(() => {
768
+ const values = { ...results, ...sampleSummary };
769
+ const hasValues = Object.keys(values).length > 0;
770
+ const resultColumns: ScienceColumn[] = schema.results_fields.map(f => ({
771
+ field: f.name,
772
+ label: f.name,
773
+ units: f.units,
774
+ body: (row) => formatCell(row[f.name], f.type, f.scale),
775
+ }));
776
+ return (
777
+ <ScienceTable
778
+ title="Results"
779
+ columns={resultColumns}
780
+ rows={hasValues ? [values] : []}
781
+ emptyMessage="No results yet."
782
+ />
783
+ );
784
+ })()}
772
785
 
773
786
  {/*
774
787
  * View Raw Data dialog — tabular listing of the raw and
@@ -1134,24 +1147,6 @@ const formatNumeric = (v: any): string => {
1134
1147
  return String(v);
1135
1148
  };
1136
1149
 
1137
- const ResultsGrid: React.FC<{ schema: TestFieldDef[]; values: any }> = ({ schema, values }) => {
1138
- if (!values || Object.keys(values).length === 0) {
1139
- return <div style={{ color: 'var(--text-secondary-color)' }}>No results yet.</div>;
1140
- }
1141
- return (
1142
- <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(220px, 1fr))', gap: '0.5rem 1rem' }}>
1143
- {schema.map(f => (
1144
- <div key={f.name}>
1145
- <div style={{ fontSize: '0.8em', color: 'var(--text-secondary-color)' }}>
1146
- {f.name}{f.units ? ` (${f.units})` : ''}
1147
- </div>
1148
- <div>{formatCell(values[f.name], f.type, f.scale)}</div>
1149
- </div>
1150
- ))}
1151
- </div>
1152
- );
1153
- };
1154
-
1155
1150
  /** Row count above which the Cycle Data table switches into virtual-
1156
1151
  * scroll mode with a fixed `cycleTableHeight`. At or below the
1157
1152
  * threshold the table sizes to its content so the Results panel
@@ -242,8 +242,12 @@ const rangeIssue = (f: TestFieldDef, raw: any): string | null => {
242
242
  if (f.min == null && f.max == null) return null;
243
243
  const disp = Number(rawToDisplay(Number(raw), f.scale));
244
244
  if (!Number.isFinite(disp)) return null;
245
- if (f.min != null && disp < f.min) return `must be ${f.min}`;
246
- if (f.max != null && disp > f.max) return `must be ≤ ${f.max}`;
245
+ // Bounds form an unordered interval an author may write the range in
246
+ // magnitude order (min:-50, max:-1000), which is numerically inverted.
247
+ const lo = f.min != null && f.max != null ? Math.min(f.min, f.max) : f.min;
248
+ const hi = f.min != null && f.max != null ? Math.max(f.min, f.max) : f.max;
249
+ if (lo != null && disp < lo) return `must be ≥ ${lo}`;
250
+ if (hi != null && disp > hi) return `must be ≤ ${hi}`;
247
251
  return null;
248
252
  };
249
253
 
@@ -1,4 +0,0 @@
1
- import type { SVGProps } from "react";
2
- export declare const SvgJogXNeg: (props: SVGProps<SVGSVGElement>) => import("react/jsx-runtime").JSX.Element;
3
- export default SvgJogXNeg;
4
- //# sourceMappingURL=JogXNeg.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"JogXNeg.d.ts","sourceRoot":"","sources":["../../src/assets/JogXNeg.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEtC,eAAO,MAAM,UAAU,GAAI,OAAO,QAAQ,CAAC,aAAa,CAAC,4CAkBxD,CAAC;AAEF,eAAe,UAAU,CAAC"}
@@ -1 +0,0 @@
1
- import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";export const SvgJogXNeg=o=>_jsxs("svg",{xmlns:"http://www.w3.org/2000/svg",width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",...o,children:[_jsx("path",{d:"M10 6 3 12 10 18Z",fill:"currentColor"}),_jsx("path",{d:"M14 6l8 12M22 6l-8 12"})]});export default SvgJogXNeg;
@@ -1,4 +0,0 @@
1
- import type { SVGProps } from "react";
2
- export declare const SvgJogXPos: (props: SVGProps<SVGSVGElement>) => import("react/jsx-runtime").JSX.Element;
3
- export default SvgJogXPos;
4
- //# sourceMappingURL=JogXPos.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"JogXPos.d.ts","sourceRoot":"","sources":["../../src/assets/JogXPos.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEtC,eAAO,MAAM,UAAU,GAAI,OAAO,QAAQ,CAAC,aAAa,CAAC,4CAkBxD,CAAC;AAEF,eAAe,UAAU,CAAC"}
@@ -1 +0,0 @@
1
- import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";export const SvgJogXPos=o=>_jsxs("svg",{xmlns:"http://www.w3.org/2000/svg",width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",...o,children:[_jsx("path",{d:"M2 6l8 12M10 6l-8 12"}),_jsx("path",{d:"M14 6 21 12 14 18Z",fill:"currentColor"})]});export default SvgJogXPos;
@@ -1,4 +0,0 @@
1
- import type { SVGProps } from "react";
2
- export declare const SvgJogYPos: (props: SVGProps<SVGSVGElement>) => import("react/jsx-runtime").JSX.Element;
3
- export default SvgJogYPos;
4
- //# sourceMappingURL=JogYNeg.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"JogYNeg.d.ts","sourceRoot":"","sources":["../../src/assets/JogYNeg.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEtC,eAAO,MAAM,UAAU,GAAI,OAAO,QAAQ,CAAC,aAAa,CAAC,4CAkBxD,CAAC;AAEF,eAAe,UAAU,CAAC"}
@@ -1 +0,0 @@
1
- import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";export const SvgJogYPos=o=>_jsxs("svg",{xmlns:"http://www.w3.org/2000/svg",width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",...o,children:[_jsx("path",{d:"M21 3 21 11 13 3Z",fill:"currentColor"}),_jsx("path",{d:"M4 12l3 4 3-4M7 16v5"})]});export default SvgJogYPos;
@@ -1,4 +0,0 @@
1
- import type { SVGProps } from "react";
2
- export declare const SvgJogYNeg: (props: SVGProps<SVGSVGElement>) => import("react/jsx-runtime").JSX.Element;
3
- export default SvgJogYNeg;
4
- //# sourceMappingURL=JogYPos.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"JogYPos.d.ts","sourceRoot":"","sources":["../../src/assets/JogYPos.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEtC,eAAO,MAAM,UAAU,GAAI,OAAO,QAAQ,CAAC,aAAa,CAAC,4CAkBxD,CAAC;AAEF,eAAe,UAAU,CAAC"}
@@ -1 +0,0 @@
1
- import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";export const SvgJogYNeg=o=>_jsxs("svg",{xmlns:"http://www.w3.org/2000/svg",width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",...o,children:[_jsx("path",{d:"M20 3l-3 4-3-4M17 7v5"}),_jsx("path",{d:"M3 21 3 13 11 21Z",fill:"currentColor"})]});export default SvgJogYNeg;