@adcops/autocore-react 3.3.48 → 3.3.54

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 (38) hide show
  1. package/dist/components/index.d.ts +10 -2
  2. package/dist/components/index.d.ts.map +1 -1
  3. package/dist/components/index.js +1 -1
  4. package/dist/components/tis/ResultHistoryTable.d.ts +19 -0
  5. package/dist/components/tis/ResultHistoryTable.d.ts.map +1 -0
  6. package/dist/components/tis/ResultHistoryTable.js +1 -0
  7. package/dist/components/{TestDataView.d.ts → tis/TestDataView.d.ts} +9 -5
  8. package/dist/components/tis/TestDataView.d.ts.map +1 -0
  9. package/dist/components/tis/TestDataView.js +1 -0
  10. package/dist/components/tis/TestRawDataView.d.ts +18 -0
  11. package/dist/components/tis/TestRawDataView.d.ts.map +1 -0
  12. package/dist/components/tis/TestRawDataView.js +1 -0
  13. package/dist/components/tis/TestSetupForm.d.ts +35 -0
  14. package/dist/components/tis/TestSetupForm.d.ts.map +1 -0
  15. package/dist/components/tis/TestSetupForm.js +1 -0
  16. package/dist/components/tis/TisProvider.d.ts +93 -0
  17. package/dist/components/tis/TisProvider.d.ts.map +1 -0
  18. package/dist/components/tis/TisProvider.js +1 -0
  19. package/package.json +1 -1
  20. package/src/components/index.ts +40 -2
  21. package/src/components/tis/ResultHistoryTable.tsx +277 -0
  22. package/src/components/{TestDataView.tsx → tis/TestDataView.tsx} +72 -38
  23. package/src/components/{TestRawDataView.tsx → tis/TestRawDataView.tsx} +41 -24
  24. package/src/components/tis/TestSetupForm.tsx +314 -0
  25. package/src/components/tis/TisProvider.tsx +404 -0
  26. package/dist/components/ResultHistoryTable.d.ts +0 -7
  27. package/dist/components/ResultHistoryTable.d.ts.map +0 -1
  28. package/dist/components/ResultHistoryTable.js +0 -1
  29. package/dist/components/TestDataView.d.ts.map +0 -1
  30. package/dist/components/TestDataView.js +0 -1
  31. package/dist/components/TestRawDataView.d.ts +0 -14
  32. package/dist/components/TestRawDataView.d.ts.map +0 -1
  33. package/dist/components/TestRawDataView.js +0 -1
  34. package/dist/components/TestSetupForm.d.ts +0 -24
  35. package/dist/components/TestSetupForm.d.ts.map +0 -1
  36. package/dist/components/TestSetupForm.js +0 -1
  37. package/src/components/ResultHistoryTable.tsx +0 -162
  38. package/src/components/TestSetupForm.tsx +0 -255
@@ -0,0 +1,404 @@
1
+ /*
2
+ * Copyright (C) 2026 Automated Design Corp. All Rights Reserved.
3
+ *
4
+ * <TisProvider> — wires the four TIS HMI components into the running
5
+ * server without any manual prop-threading. It owns:
6
+ *
7
+ * 1. The schema registry (loaded once via `tis.list_schemas`).
8
+ * 2. The four live readiness scalars (`tis.staged*`, `tis.active*`).
9
+ * 3. The selection state (project, method, sample, run) — each field
10
+ * follows its `active_*` scalar by default until a component pins
11
+ * it explicitly via `setSelection`.
12
+ * 4. A run cache that tracks live cycle/results broadcasts so detail
13
+ * views re-render in place when the control program appends data.
14
+ *
15
+ * Drop it once at the top of the HMI; the four TIS components below it
16
+ * read from context and need no props.
17
+ */
18
+
19
+ import React, {
20
+ createContext,
21
+ useCallback,
22
+ useContext,
23
+ useEffect,
24
+ useMemo,
25
+ useReducer,
26
+ useRef,
27
+ useState,
28
+ type ReactNode,
29
+ } from 'react';
30
+ import { EventEmitterContext } from '../../core/EventEmitterContext';
31
+ import { MessageType } from '../../hub/CommandMessage';
32
+
33
+ // -------------------------------------------------------------------------
34
+ // Types
35
+ // -------------------------------------------------------------------------
36
+
37
+ /**
38
+ * One slot in the schema registry. Kept as an opaque object so the
39
+ * provider doesn't have to mirror every schema field — components that
40
+ * need typed access import the schema constants from the per-project
41
+ * generated `autocore/tis.ts` instead.
42
+ */
43
+ export type TisMethodSchema = any;
44
+
45
+ export type SchemaRegistry = { [methodId: string]: TisMethodSchema };
46
+
47
+ export interface TisLiveState {
48
+ staged: boolean;
49
+ stagedProjectId: string;
50
+ stagedMethodId: string;
51
+ stagedSampleId: string;
52
+
53
+ active: boolean;
54
+ activeProjectId: string;
55
+ activeMethodId: string;
56
+ activeSampleId: string;
57
+ activeRunId: string;
58
+ }
59
+
60
+ export interface TisSelection {
61
+ projectId: string;
62
+ methodId: string;
63
+ sampleId: string;
64
+ runId: string;
65
+ }
66
+
67
+ /** Partial setter — pass `null` for a field to clear the pin and let
68
+ * the active scalar drive that field again. */
69
+ export type TisSelectionPatch = {
70
+ projectId?: string | null;
71
+ methodId?: string | null;
72
+ sampleId?: string | null;
73
+ runId?: string | null;
74
+ };
75
+
76
+ export interface TisRunCacheEntry {
77
+ meta: any | null;
78
+ cycles: any[];
79
+ results: any;
80
+ rawData: { [blobName: string]: any };
81
+ }
82
+
83
+ export interface TisContextValue {
84
+ schemas: SchemaRegistry;
85
+ defaultMethodId: string;
86
+ schemasLoaded: boolean;
87
+
88
+ state: TisLiveState;
89
+
90
+ selection: TisSelection;
91
+ setSelection: (patch: TisSelectionPatch) => void;
92
+
93
+ /** Fetch the run list for a (project, method?) pair. Method may be
94
+ * omitted to aggregate runs across every method in the project —
95
+ * the History tab uses this. */
96
+ fetchRuns: (projectId: string, methodId?: string) => Promise<any[]>;
97
+ /** Fetch the full bundle (test.json + cycles + results) for one run.
98
+ * Subsequent broadcast deltas land in the cache automatically. */
99
+ fetchRun: (projectId: string, methodId: string, runId: string) => Promise<TisRunCacheEntry | null>;
100
+ runCache: { [runId: string]: TisRunCacheEntry };
101
+ }
102
+
103
+ // -------------------------------------------------------------------------
104
+ // Defaults
105
+ // -------------------------------------------------------------------------
106
+
107
+ const EMPTY_STATE: TisLiveState = {
108
+ staged: false, stagedProjectId: '', stagedMethodId: '', stagedSampleId: '',
109
+ active: false, activeProjectId: '', activeMethodId: '', activeSampleId: '', activeRunId: '',
110
+ };
111
+
112
+ const EMPTY_SELECTION: TisSelection = {
113
+ projectId: '', methodId: '', sampleId: '', runId: '',
114
+ };
115
+
116
+ const TisContext = createContext<TisContextValue>({
117
+ schemas: {},
118
+ defaultMethodId: '',
119
+ schemasLoaded: false,
120
+ state: EMPTY_STATE,
121
+ selection: EMPTY_SELECTION,
122
+ setSelection: () => {},
123
+ fetchRuns: async () => [],
124
+ fetchRun: async () => null,
125
+ runCache: {},
126
+ });
127
+
128
+ // -------------------------------------------------------------------------
129
+ // Reducer for live broadcast state
130
+ // -------------------------------------------------------------------------
131
+
132
+ type StateAction =
133
+ | { kind: 'staged'; value: boolean }
134
+ | { kind: 'staged_project_id'; value: string }
135
+ | { kind: 'staged_method_id'; value: string }
136
+ | { kind: 'staged_sample_id'; value: string }
137
+ | { kind: 'active'; value: boolean }
138
+ | { kind: 'active_project_id'; value: string }
139
+ | { kind: 'active_method_id'; value: string }
140
+ | { kind: 'active_sample_id'; value: string }
141
+ | { kind: 'active_run_id'; value: string };
142
+
143
+ function liveReducer(s: TisLiveState, a: StateAction): TisLiveState {
144
+ switch (a.kind) {
145
+ case 'staged': return { ...s, staged: a.value };
146
+ case 'staged_project_id': return { ...s, stagedProjectId: a.value };
147
+ case 'staged_method_id': return { ...s, stagedMethodId: a.value };
148
+ case 'staged_sample_id': return { ...s, stagedSampleId: a.value };
149
+ case 'active': return { ...s, active: a.value };
150
+ case 'active_project_id': return { ...s, activeProjectId: a.value };
151
+ case 'active_method_id': return { ...s, activeMethodId: a.value };
152
+ case 'active_sample_id': return { ...s, activeSampleId: a.value };
153
+ case 'active_run_id': return { ...s, activeRunId: a.value };
154
+ }
155
+ }
156
+
157
+ // -------------------------------------------------------------------------
158
+ // Provider
159
+ // -------------------------------------------------------------------------
160
+
161
+ export interface TisProviderProps {
162
+ children: ReactNode;
163
+ /**
164
+ * Initial method_id when the schemas haven't loaded yet, or when the
165
+ * server's reported `default_method_id` is empty. Falls through to
166
+ * the first key of `tis.list_schemas` if not supplied.
167
+ */
168
+ defaultMethodId?: string;
169
+ }
170
+
171
+ export const TisProvider: React.FC<TisProviderProps> = ({ children, defaultMethodId: initialDefault }) => {
172
+ const { invoke, subscribe, unsubscribe } = useContext(EventEmitterContext);
173
+
174
+ const [schemas, setSchemas] = useState<SchemaRegistry>({});
175
+ const [defaultMethodId, setDefaultMethodId] = useState<string>(initialDefault ?? '');
176
+ const [schemasLoaded, setSchemasLoaded] = useState(false);
177
+
178
+ const [state, dispatch] = useReducer(liveReducer, EMPTY_STATE);
179
+
180
+ // Selection has two layers: explicit pins (set via setSelection) and
181
+ // an "active follower" fallback. Storing pins as `null` means
182
+ // "follow active"; storing `''` means "explicitly empty" (e.g.,
183
+ // user cleared the field). Only `null` triggers the follow.
184
+ const [pins, setPins] = useState<{
185
+ projectId: string | null;
186
+ methodId: string | null;
187
+ sampleId: string | null;
188
+ runId: string | null;
189
+ }>({
190
+ projectId: null, methodId: null, sampleId: null, runId: null,
191
+ });
192
+
193
+ // -----------------------------------------------------------------
194
+ // Schema load — once on mount
195
+ // -----------------------------------------------------------------
196
+ useEffect(() => {
197
+ let cancelled = false;
198
+ (async () => {
199
+ try {
200
+ const resp: any = await invoke('tis.list_schemas' as any, MessageType.Request, {} as any);
201
+ if (cancelled) return;
202
+ if (resp?.success && resp.data) {
203
+ const methods = (resp.data.test_methods ?? {}) as SchemaRegistry;
204
+ const dflt = (resp.data.default_method_id ?? '') as string;
205
+ setSchemas(methods);
206
+ if (!initialDefault && dflt) setDefaultMethodId(dflt);
207
+ setSchemasLoaded(true);
208
+ } else {
209
+ console.warn('[TisProvider] tis.list_schemas failed:', resp?.error_message);
210
+ }
211
+ } catch (e) {
212
+ console.error('[TisProvider] tis.list_schemas threw:', e);
213
+ }
214
+ })();
215
+ return () => { cancelled = true; };
216
+ // We intentionally only run once on mount — schemas are stable.
217
+ // eslint-disable-next-line react-hooks/exhaustive-deps
218
+ }, []);
219
+
220
+ // -----------------------------------------------------------------
221
+ // Live readiness scalars — subscribe to every tis.* broadcast
222
+ // -----------------------------------------------------------------
223
+ useEffect(() => {
224
+ const subs = [
225
+ subscribe('tis.staged', (v: any) => dispatch({ kind: 'staged', value: !!v })),
226
+ subscribe('tis.staged_project_id', (v: any) => dispatch({ kind: 'staged_project_id', value: String(v ?? '') })),
227
+ subscribe('tis.staged_method_id', (v: any) => dispatch({ kind: 'staged_method_id', value: String(v ?? '') })),
228
+ subscribe('tis.staged_sample_id', (v: any) => dispatch({ kind: 'staged_sample_id', value: String(v ?? '') })),
229
+ subscribe('tis.active', (v: any) => dispatch({ kind: 'active', value: !!v })),
230
+ subscribe('tis.active_project_id', (v: any) => dispatch({ kind: 'active_project_id', value: String(v ?? '') })),
231
+ subscribe('tis.active_method_id', (v: any) => dispatch({ kind: 'active_method_id', value: String(v ?? '') })),
232
+ subscribe('tis.active_sample_id', (v: any) => dispatch({ kind: 'active_sample_id', value: String(v ?? '') })),
233
+ subscribe('tis.active_run_id', (v: any) => dispatch({ kind: 'active_run_id', value: String(v ?? '') })),
234
+ ];
235
+ return () => { subs.forEach(unsubscribe); };
236
+ }, [subscribe, unsubscribe]);
237
+
238
+ // -----------------------------------------------------------------
239
+ // Run cache — broadcasts of cycles/results land here so detail
240
+ // views can subscribe via useTisRun() instead of re-fetching.
241
+ // -----------------------------------------------------------------
242
+ const cacheRef = useRef<{ [runId: string]: TisRunCacheEntry }>({});
243
+ // bumpCacheVersion is a numeric tick; we expose `runCache` as a
244
+ // memoised value derived from the ref so React rerenders dependent
245
+ // components when any run entry changes.
246
+ const [cacheVersion, setCacheVersion] = useState(0);
247
+ const bumpCache = useCallback(() => setCacheVersion(v => v + 1), []);
248
+
249
+ const upsertCycle = useCallback((runId: string, cycle: any) => {
250
+ if (!runId) return;
251
+ const prev = cacheRef.current[runId] ?? { meta: null, cycles: [], results: {}, rawData: {} };
252
+ cacheRef.current[runId] = { ...prev, cycles: [...prev.cycles, cycle] };
253
+ bumpCache();
254
+ }, [bumpCache]);
255
+
256
+ const upsertResults = useCallback((runId: string, results: any) => {
257
+ if (!runId) return;
258
+ const prev = cacheRef.current[runId] ?? { meta: null, cycles: [], results: {}, rawData: {} };
259
+ cacheRef.current[runId] = { ...prev, results };
260
+ bumpCache();
261
+ }, [bumpCache]);
262
+
263
+ useEffect(() => {
264
+ const onCycle = (payload: any) => {
265
+ if (!payload?.run_id || !payload.cycle) return;
266
+ upsertCycle(payload.run_id, payload.cycle);
267
+ };
268
+ const onResults = (payload: any) => {
269
+ if (!payload?.run_id) return;
270
+ upsertResults(payload.run_id, payload.results ?? {});
271
+ };
272
+ const id1 = subscribe('tis.cycle_added', onCycle);
273
+ const id2 = subscribe('tis.results_updated', onResults);
274
+ return () => { unsubscribe(id1); unsubscribe(id2); };
275
+ }, [subscribe, unsubscribe, upsertCycle, upsertResults]);
276
+
277
+ // -----------------------------------------------------------------
278
+ // Selection: pins override active
279
+ // -----------------------------------------------------------------
280
+ const selection: TisSelection = useMemo(() => ({
281
+ projectId: pins.projectId ?? state.activeProjectId,
282
+ methodId: pins.methodId ?? (state.activeMethodId || defaultMethodId),
283
+ sampleId: pins.sampleId ?? state.activeSampleId,
284
+ runId: pins.runId ?? state.activeRunId,
285
+ }), [pins, state, defaultMethodId]);
286
+
287
+ const setSelection = useCallback((patch: TisSelectionPatch) => {
288
+ setPins(prev => ({
289
+ projectId: patch.projectId === undefined ? prev.projectId : patch.projectId,
290
+ methodId: patch.methodId === undefined ? prev.methodId : patch.methodId,
291
+ sampleId: patch.sampleId === undefined ? prev.sampleId : patch.sampleId,
292
+ runId: patch.runId === undefined ? prev.runId : patch.runId,
293
+ }));
294
+ }, []);
295
+
296
+ // -----------------------------------------------------------------
297
+ // Fetchers
298
+ // -----------------------------------------------------------------
299
+ const fetchRuns = useCallback(async (projectId: string, methodId?: string): Promise<any[]> => {
300
+ if (!projectId) return [];
301
+ const payload: any = { project_id: projectId };
302
+ if (methodId) payload.method_id = methodId;
303
+ try {
304
+ const resp: any = await invoke('tis.list_tests' as any, MessageType.Request, payload);
305
+ if (resp?.success && resp.data?.tests) return resp.data.tests as any[];
306
+ } catch (e) {
307
+ console.error('[TisProvider] tis.list_tests failed:', e);
308
+ }
309
+ return [];
310
+ }, [invoke]);
311
+
312
+ const fetchRun = useCallback(async (
313
+ projectId: string, methodId: string, runId: string,
314
+ ): Promise<TisRunCacheEntry | null> => {
315
+ if (!projectId || !methodId || !runId) return null;
316
+ try {
317
+ const meta: any = await invoke('tis.read_test' as any, MessageType.Request, {
318
+ project_id: projectId, method_id: methodId, run_id: runId,
319
+ } as any);
320
+ const cy: any = await invoke('tis.read_cycles' as any, MessageType.Request, {
321
+ project_id: projectId, method_id: methodId, run_id: runId,
322
+ offset: 0, limit: 1000, order: 'asc',
323
+ } as any);
324
+ if (!meta?.success) return null;
325
+ const entry: TisRunCacheEntry = {
326
+ meta: meta.data ?? null,
327
+ cycles: (cy?.success ? (cy.data?.cycles ?? []) : []) as any[],
328
+ results: meta.data?.results ?? {},
329
+ rawData: cacheRef.current[runId]?.rawData ?? {},
330
+ };
331
+ cacheRef.current[runId] = entry;
332
+ bumpCache();
333
+ return entry;
334
+ } catch (e) {
335
+ console.error('[TisProvider] fetchRun failed:', e);
336
+ return null;
337
+ }
338
+ }, [invoke, bumpCache]);
339
+
340
+ const runCache = useMemo(() => ({ ...cacheRef.current }), [cacheVersion]);
341
+
342
+ const value: TisContextValue = useMemo(() => ({
343
+ schemas, defaultMethodId, schemasLoaded,
344
+ state, selection, setSelection,
345
+ fetchRuns, fetchRun, runCache,
346
+ }), [schemas, defaultMethodId, schemasLoaded, state, selection, setSelection, fetchRuns, fetchRun, runCache]);
347
+
348
+ return <TisContext.Provider value={value}>{children}</TisContext.Provider>;
349
+ };
350
+
351
+ // -------------------------------------------------------------------------
352
+ // Hooks
353
+ // -------------------------------------------------------------------------
354
+
355
+ export const useTis = () => useContext(TisContext);
356
+ export const useTisSchemas = () => useContext(TisContext).schemas;
357
+ export const useTisState = () => useContext(TisContext).state;
358
+ export const useTisSelection = () => {
359
+ const { selection, setSelection } = useContext(TisContext);
360
+ return [selection, setSelection] as const;
361
+ };
362
+
363
+ export const useTisRuns = (projectId?: string, methodId?: string) => {
364
+ const { fetchRuns } = useContext(TisContext);
365
+ const [runs, setRuns] = useState<any[]>([]);
366
+ const [loading, setLoading] = useState(false);
367
+ const refresh = useCallback(async () => {
368
+ if (!projectId) { setRuns([]); return; }
369
+ setLoading(true);
370
+ try { setRuns(await fetchRuns(projectId, methodId)); }
371
+ finally { setLoading(false); }
372
+ }, [projectId, methodId, fetchRuns]);
373
+ useEffect(() => { void refresh(); }, [refresh]);
374
+ return { runs, loading, refresh };
375
+ };
376
+
377
+ export const useTisRun = (runId?: string) => {
378
+ const { selection, fetchRun, runCache } = useContext(TisContext);
379
+ const [loading, setLoading] = useState(false);
380
+ const targetRunId = runId ?? selection.runId;
381
+
382
+ useEffect(() => {
383
+ if (!targetRunId) return;
384
+ if (runCache[targetRunId]?.meta) return; // already cached
385
+ const projectId = selection.projectId;
386
+ const methodId = selection.methodId;
387
+ if (!projectId || !methodId) return;
388
+ setLoading(true);
389
+ void fetchRun(projectId, methodId, targetRunId).finally(() => setLoading(false));
390
+ }, [targetRunId, selection.projectId, selection.methodId, fetchRun, runCache]);
391
+
392
+ const entry = targetRunId ? runCache[targetRunId] : null;
393
+ return {
394
+ meta: entry?.meta ?? null,
395
+ cycles: entry?.cycles ?? [],
396
+ results: entry?.results ?? {},
397
+ rawData: entry?.rawData ?? {},
398
+ loading,
399
+ };
400
+ };
401
+
402
+ // Re-export the context so app code that needs direct access can grab
403
+ // it without importing the hooks (rare).
404
+ export { TisContext };
@@ -1,7 +0,0 @@
1
- import React from 'react';
2
- export interface ResultHistoryTableProps {
3
- projectId: string;
4
- definitionId: string;
5
- }
6
- export declare const ResultHistoryTable: React.FC<ResultHistoryTableProps>;
7
- //# sourceMappingURL=ResultHistoryTable.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ResultHistoryTable.d.ts","sourceRoot":"","sources":["../../src/components/ResultHistoryTable.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA0C,MAAM,OAAO,CAAC;AAO/D,MAAM,WAAW,uBAAuB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACxB;AAqDD,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CAkGhE,CAAC"}
@@ -1 +0,0 @@
1
- import{jsxs as _jsxs,jsx as _jsx}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";const rawBlobToCsv=e=>{if(!e||"object"!=typeof e)return"";const t=Object.entries(e).filter(([,e])=>Array.isArray(e));if(0===t.length)return"";t.sort(([e],[t])=>"t"===e?-1:"t"===t?1:0);const s=t.map(([e])=>e),r=t.reduce((e,[,t])=>Math.min(e,t.length),1/0),o=e=>{if(null==e)return"";const t=String(e);return/[",\n\r]/.test(t)?`"${t.replace(/"/g,'""')}"`:t},n=[s.join(",")];for(let e=0;e<r;e++)n.push(t.map(([,t])=>o(t[e])).join(","));return n.join("\n")},downloadCsv=(e,t)=>{const s=new Blob([t],{type:"text/csv;charset=utf-8;"}),r=URL.createObjectURL(s),o=document.createElement("a");o.href=r,o.download=e,document.body.appendChild(o),o.click(),o.remove(),URL.revokeObjectURL(r)};export const ResultHistoryTable=({projectId:e,definitionId:t})=>{const[s,r]=useState([]),[o,n]=useState(!1),[a,i]=useState(null),{invoke:l}=useContext(EventEmitterContext),c=async()=>{n(!0);try{const s=await l("results.list_tests",MessageType.Request,{project_id:e,definition_id:t});s.success&&s.data&&s.data.tests&&r(s.data.tests)}catch(e){}n(!1)};useEffect(()=>{c()},[e,t]);return _jsxs("div",{children:[_jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:"1rem"},children:[_jsxs("h3",{children:["Test History: ",t]}),_jsx(Button,{icon:"pi pi-refresh",label:"Refresh",onClick:c,disabled:o})]}),_jsxs(DataTable,{value:s,loading:o,paginator:!0,rows:10,emptyMessage:"No tests found.",children:[_jsx(Column,{field:"run_id",header:"Run ID",sortable:!0}),_jsx(Column,{field:"start_time",header:"Date/Time",body:e=>{return(t=e.start_time)?new Date(t).toLocaleString():"";var t},sortable:!0}),_jsx(Column,{header:"Config / Results",body:e=>_jsxs("div",{style:{fontSize:"0.85em",color:"var(--text-secondary-color)"},children:[_jsxs("div",{children:[_jsx("strong",{children:"Config:"})," ",JSON.stringify(e.config)]}),_jsxs("div",{children:[_jsx("strong",{children:"Results:"})," ",JSON.stringify(e.results)]})]})}),_jsx(Column,{header:"Raw Data",style:{width:"8rem"},body:s=>_jsx(Button,{icon:a===s.run_id?"pi pi-spin pi-spinner":"pi pi-download",label:"CSV",size:"small",outlined:!0,disabled:null!==a,onClick:()=>(async s=>{const r=s?.run_id;if(r){i(r);try{const s=await l("results.read_raw",MessageType.Request,{project_id:e,definition_id:t,run_id:r,name:"trace"});if(!s?.success||!s.data)return void alert(`No raw trace available for ${r}${s?.error_message?`: ${s.error_message}`:""}`);const o=rawBlobToCsv(s.data);if(!o)return void alert(`Raw trace for ${r} is empty or has no array columns.`);downloadCsv(`${e}_${t}_${r}.csv`,o)}catch(e){alert(`Download failed: ${e instanceof Error?e.message:String(e)}`)}finally{i(null)}}})(s),tooltip:"Download raw_data/trace.json as CSV",tooltipOptions:{position:"left"}})})]})]})};
@@ -1 +0,0 @@
1
- {"version":3,"file":"TestDataView.d.ts","sourceRoot":"","sources":["../../src/components/TestDataView.tsx"],"names":[],"mappings":"AAUA,OAAO,KAA2D,MAAM,OAAO,CAAC;AA4BhF,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;CACnB;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,MAAM,WAAW,SAAS;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,eAAe,GAAG,WAAW,CAAC;IACpC,CAAC,EAAE,SAAS,CAAC;IACb,CAAC,EAAE,WAAW,EAAE,CAAC;CACpB;AACD,MAAM,WAAW,YAAY;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;CACrC;AACD,MAAM,WAAW,cAAc;IAC3B,cAAc,EAAG,YAAY,EAAE,CAAC;IAChC,aAAa,EAAI,YAAY,EAAE,CAAC;IAChC,YAAY,EAAK,YAAY,EAAE,CAAC;IAChC,cAAc,EAAG,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;CAClD;AAED,MAAM,WAAW,iBAAiB;IAC9B,SAAS,EAAK,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAS,MAAM,CAAC;IACrB,MAAM,EAAQ,cAAc,CAAC;IAC7B,8EAA8E;IAC9E,UAAU,CAAC,EAAG,MAAM,CAAC;IACrB,wDAAwD;IACxD,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAID,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAkOpD,CAAC"}
@@ -1 +0,0 @@
1
- import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import React,{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{Chart as ChartJS,CategoryScale,LinearScale,PointElement,LineElement,Title,Tooltip,Legend}from"chart.js";import zoomPlugin from"chartjs-plugin-zoom";import{Line}from"react-chartjs-2";import{EventEmitterContext}from"../core/EventEmitterContext";import{MessageType}from"../hub/CommandMessage";import{TestRawDataView}from"./TestRawDataView";ChartJS.register(CategoryScale,LinearScale,PointElement,LineElement,Title,Tooltip,Legend,zoomPlugin);export const TestDataView=({projectId:e,definitionId:t,runId:i,schema:r,throttleMs:a=100,cycleTableHeight:s="400px"})=>{const{invoke:l,subscribe:n,unsubscribe:o}=useContext(EventEmitterContext),[c,d]=useState(null),[m,u]=useState([]),[p,f]=useState({}),[x,h]=useState(!1),g=useMemo(()=>{const e=[];for(const[t,i]of Object.entries(r.views??{}))"cycle_scatter"===i.type&&e.push({name:t,view:i});return e},[r]),[y,_]=useState(g.length>0?g[0].name:null),j=useRef([]),v=useRef(null),b=useRef(null),w=()=>{b.current||(b.current=setTimeout(()=>{if(b.current=null,j.current.length>0){const e=j.current;j.current=[],u(t=>[...e.slice().reverse(),...t])}v.current&&(f(v.current),v.current=null)},a))};useEffect(()=>{let r=!1;return(async()=>{try{const a=await l("results.read_test",MessageType.Request,{project_id:e,definition_id:t,run_id:i});!r&&a?.success&&(d(a.data),f(a.data.results??{}));const s=await l("results.read_cycles",MessageType.Request,{project_id:e,definition_id:t,run_id:i,offset:0,limit:200,order:"desc"});!r&&s?.success&&u(s.data.cycles??[])}catch(e){}})(),()=>{r=!0}},[e,t,i,l]),useEffect(()=>{const r=r=>r?.project_id===e&&r?.definition_id===t&&r?.run_id===i,a=n("results.cycle_added",e=>{r(e)&&e.cycle&&(j.current.push(e.cycle),w())}),s=n("results.results_updated",e=>{r(e)&&(v.current=e.results??{},w())});return()=>{o(a),o(s),b.current&&(clearTimeout(b.current),b.current=null)}},[e,t,i,a]);const C=useMemo(()=>{if(!y||0===g.length)return null;const e=g.find(e=>e.name===y)?.view;if(!e)return null;const t=e.x.field,i=[...m].reverse();return{labels:i.map(e=>e[t]),datasets:e.y.map((e,t)=>({label:e.label??e.field,data:i.map(t=>t[e.field]),yAxisID:"right"===e.y_axis?"y1":"y",borderColor:palette(t),backgroundColor:palette(t),tension:.1,pointRadius:2}))}},[m,y,g]),R=g.find(e=>e.name===y)?.view,S=R?.y.some(e=>"right"===e.y_axis)??!1,T=useMemo(()=>({responsive:!0,maintainAspectRatio:!1,scales:{x:{title:{display:!!R?.x.label,text:R?.x.label}},y:{position:"left",title:{display:!0,text:leftAxisLabel(R)}},...S?{y1:{position:"right",grid:{drawOnChartArea:!1},title:{display:!0,text:rightAxisLabel(R)}}}:{}},plugins:{legend:{display:!0},zoom:{pan:{enabled:!0,mode:"xy"},zoom:{wheel:{enabled:!0},pinch:{enabled:!0},mode:"xy"}}}}),[R,S]);return _jsxs("div",{className:"vblock",style:{display:"flex",flexDirection:"column",gap:"1rem"},children:[_jsx(Header,{meta:c,config:c?.config,runId:i,projectId:e,definitionId:t,canViewRaw:!!r.raw_data,onViewRaw:()=>h(!0)}),g.length>0&&_jsxs("div",{className:"p-card",style:{padding:"1rem"},children:[_jsxs("div",{className:"flex",style:{gap:"1rem",alignItems:"center",marginBottom:"0.5rem"},children:[_jsx(Dropdown,{value:y,options:g.map(e=>({label:e.view.title??e.name,value:e.name})),onChange:e=>_(e.value),placeholder:"Select a view"}),_jsx("h3",{style:{margin:0},children:R?.title??""})]}),_jsx("div",{style:{height:320},children:C&&_jsx(Line,{data:C,options:T})})]}),_jsxs("div",{className:"p-card",style:{padding:"1rem"},children:[_jsxs("h3",{style:{marginTop:0},children:["Cycle Data (",m.length,")"]}),_jsx(DataTable,{value:m,scrollable:!0,scrollHeight:s,virtualScrollerOptions:{itemSize:38},emptyMessage:"No cycles yet.",children:r.cycle_fields.map(e=>_jsx(Column,{field:e.name,header:e.units?`${e.name} (${e.units})`:e.name,body:t=>formatCell(t[e.name],e.type)},e.name))})]}),_jsxs("div",{className:"p-card",style:{padding:"1rem"},children:[_jsx("h3",{style:{marginTop:0},children:"Results"}),_jsx(ResultsGrid,{schema:r.results_fields,values:p})]}),r.raw_data&&_jsx(Dialog,{visible:x,onHide:()=>h(!1),header:"Raw Data",style:{width:"90vw",height:"80vh"},maximizable:!0,children:_jsx(TestRawDataView,{projectId:e,definitionId:t,runId:i,schema:r})})]})};const Header=({meta:e,config:t,runId:i,projectId:r,definitionId:a,canViewRaw:s,onViewRaw:l})=>_jsxs("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},children:[a," — ",i]}),_jsxs("div",{style:{color:"var(--text-secondary-color)",fontSize:"0.85em"},children:["project: ",r,e?.start_time&&_jsxs(_Fragment,{children:[" · started: ",new Date(e.start_time).toLocaleString()]})]})]}),s&&_jsx(Button,{icon:"pi pi-chart-line",label:"View Raw Data",onClick:l,outlined:!0})]}),t&&Object.keys(t).length>0&&_jsx("div",{style:{marginTop:"0.75rem",display:"grid",gridTemplateColumns:"repeat(auto-fill, minmax(220px, 1fr))",gap:"0.25rem 1rem",fontSize:"0.9em"},children:Object.entries(t).map(([e,t])=>_jsxs("div",{children:[_jsxs("strong",{children:[e,":"]})," ",formatCell(t,"string")]},e))})]}),ResultsGrid=({schema:e,values:t})=>t&&0!==Object.keys(t).length?_jsx("div",{style:{display:"grid",gridTemplateColumns:"repeat(auto-fill, minmax(220px, 1fr))",gap:"0.5rem 1rem"},children:e.map(e=>_jsxs("div",{children:[_jsxs("div",{style:{fontSize:"0.8em",color:"var(--text-secondary-color)"},children:[e.name,e.units?` (${e.units})`:""]}),_jsx("div",{children:formatCell(t[e.name],e.type)})]},e.name))}):_jsx("div",{style:{color:"var(--text-secondary-color)"},children:"No results yet."}),CHART_COLORS=["#4ea8de","#f59e0b","#22c55e","#a855f7","#ef4444","#14b8a6","#eab308","#ec4899"],palette=e=>CHART_COLORS[e%CHART_COLORS.length],leftAxisLabel=e=>e?.y.filter(e=>"right"!==e.y_axis).map(e=>e.label??e.field).join(" / ")??"",rightAxisLabel=e=>e?.y.filter(e=>"right"===e.y_axis).map(e=>e.label??e.field).join(" / ")??"",formatCell=(e,t)=>null==e?"":"f32"===t||"f64"===t?"number"==typeof e?e.toFixed(4):String(e):"object"==typeof e?JSON.stringify(e):String(e);
@@ -1,14 +0,0 @@
1
- import React from 'react';
2
- import type { TestDefinition } from './TestDataView';
3
- export interface TestRawDataViewProps {
4
- projectId: string;
5
- definitionId: string;
6
- runId: string;
7
- schema: TestDefinition;
8
- /** Override the blob name (default: schema.raw_data.blob_name). */
9
- blobName?: string;
10
- /** Fixed chart height. Default "60vh". */
11
- chartHeight?: string;
12
- }
13
- export declare const TestRawDataView: React.FC<TestRawDataViewProps>;
14
- //# sourceMappingURL=TestRawDataView.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"TestRawDataView.d.ts","sourceRoot":"","sources":["../../src/components/TestRawDataView.tsx"],"names":[],"mappings":"AAYA,OAAO,KAA2D,MAAM,OAAO,CAAC;AAahF,OAAO,KAAK,EAAa,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAOhE,MAAM,WAAW,oBAAoB;IACjC,SAAS,EAAK,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAS,MAAM,CAAC;IACrB,MAAM,EAAQ,cAAc,CAAC;IAC7B,mEAAmE;IACnE,QAAQ,CAAC,EAAK,MAAM,CAAC;IACrB,0CAA0C;IAC1C,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CA2I1D,CAAC"}
@@ -1 +0,0 @@
1
- import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React,{useContext,useEffect,useMemo,useRef,useState}from"react";import{Button}from"primereact/button";import{Dropdown}from"primereact/dropdown";import{Chart as ChartJS,CategoryScale,LinearScale,PointElement,LineElement,Title,Tooltip,Legend}from"chart.js";import zoomPlugin from"chartjs-plugin-zoom";import{Line}from"react-chartjs-2";import{EventEmitterContext}from"../core/EventEmitterContext";import{MessageType}from"../hub/CommandMessage";ChartJS.register(CategoryScale,LinearScale,PointElement,LineElement,Title,Tooltip,Legend,zoomPlugin);export const TestRawDataView=({projectId:e,definitionId:t,runId:a,schema:i,blobName:n,chartHeight:r="60vh"})=>{const{invoke:o}=useContext(EventEmitterContext),[s,l]=useState(null),[m,d]=useState(!0),[c,p]=useState(null),u=useRef(null),x=useMemo(()=>{const e=[];for(const[t,a]of Object.entries(i.views??{}))"raw_trace"===a.type&&e.push({name:t,view:a});return e},[i]),[h,y]=useState(x.length>0?x[0].name:null),f=n??i.raw_data?.blob_name??"trace";useEffect(()=>{let i=!1;return d(!0),p(null),(async()=>{try{const n=await o("results.read_raw",MessageType.Request,{project_id:e,definition_id:t,run_id:a,name:f});if(i)return;n?.success?l(n.data??{}):p(n?.error_message??"Failed to read raw data")}catch(e){i||p(String(e?.message??e))}finally{i||d(!1)}})(),()=>{i=!0}},[e,t,a,f,o]);const g=useMemo(()=>{if(!s||!h)return null;const e=x.find(e=>e.name===h)?.view;if(!e)return null;const t=e.x.column,a=s[t]??[];return{datasets:e.y.map((e,t)=>({label:e.label??e.column,data:(s[e.column]??[]).map((e,t)=>({x:a[t],y:e})),yAxisID:"right"===e.y_axis?"y1":"y",borderColor:palette(t),backgroundColor:palette(t),pointRadius:0,borderWidth:1.5,showLine:!0}))}},[s,h,x]),_=x.find(e=>e.name===h)?.view,v=_?.y.some(e=>"right"===e.y_axis)??!1,b=useMemo(()=>({responsive:!0,maintainAspectRatio:!1,parsing:!1,scales:{x:{type:"linear",title:{display:!!_?.x.label,text:_?.x.label}},y:{position:"left",title:{display:!0,text:axisLabel(_,"left")}},...v?{y1:{position:"right",grid:{drawOnChartArea:!1},title:{display:!0,text:axisLabel(_,"right")}}}:{}},plugins:{legend:{display:!0},zoom:{pan:{enabled:!0,mode:"xy"},zoom:{wheel:{enabled:!0},pinch:{enabled:!0},drag:{enabled:!0,modifierKey:"shift"},mode:"xy"}}}}),[_,v]);return i.raw_data?0===x.length?_jsx(EmptyState,{message:"No raw_trace views declared. Add one to schema.views in project.json."}):_jsxs("div",{className:"vblock",style:{display:"flex",flexDirection:"column",gap:"1rem",height:"100%"},children:[_jsxs("div",{className:"flex",style:{gap:"1rem",alignItems:"center"},children:[_jsx(Dropdown,{value:h,options:x.map(e=>({label:e.view.title??e.name,value:e.name})),onChange:e=>y(e.value),placeholder:"Select a view"}),_jsx("h3",{style:{margin:0},children:_?.title??""}),_jsx("div",{style:{flex:1}}),_jsx(Button,{icon:"pi pi-refresh",label:"Reset Zoom",outlined:!0,onClick:()=>u.current?.resetZoom?.()})]}),_jsxs("div",{style:{flex:1,minHeight:0,height:r,position:"relative"},children:[m&&_jsx(Overlay,{children:"Loading raw data…"}),c&&_jsx(Overlay,{children:c}),g&&!m&&!c&&_jsx(Line,{ref:u,data:g,options:b})]})]}):_jsx(EmptyState,{message:"No raw_data is declared for this test definition."})};const Overlay=({children:e})=>_jsx("div",{style:{position:"absolute",inset:0,display:"flex",alignItems:"center",justifyContent:"center",color:"var(--text-secondary-color)",pointerEvents:"none"},children:e}),EmptyState=({message:e})=>_jsx("div",{style:{padding:"1rem",color:"var(--text-secondary-color)"},children:e}),CHART_COLORS=["#4ea8de","#f59e0b","#22c55e","#a855f7","#ef4444","#14b8a6","#eab308","#ec4899"],palette=e=>CHART_COLORS[e%CHART_COLORS.length],axisLabel=(e,t)=>e?.y.filter(e=>(e.y_axis??"left")===t).map(e=>e.label??e.column).join(" / ")??"";
@@ -1,24 +0,0 @@
1
- import React from 'react';
2
- export interface TestFieldDef {
3
- name: string;
4
- type: string;
5
- units?: string;
6
- required?: boolean;
7
- source?: string;
8
- }
9
- export interface TestDefinition {
10
- project_fields: TestFieldDef[];
11
- config_fields: TestFieldDef[];
12
- cycle_fields: TestFieldDef[];
13
- results_fields: TestFieldDef[];
14
- }
15
- export interface TestSetupFormProps {
16
- schema: TestDefinition;
17
- defaultProjectId?: string;
18
- defaultDefinitionId?: string;
19
- onProjectChange?: (projectId: string) => void;
20
- onDefinitionChange?: (definitionId: string) => void;
21
- onValidationChange?: (isValid: boolean, config: any) => void;
22
- }
23
- export declare const TestSetupForm: React.FC<TestSetupFormProps>;
24
- //# sourceMappingURL=TestSetupForm.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"TestSetupForm.d.ts","sourceRoot":"","sources":["../../src/components/TestSetupForm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA0C,MAAM,OAAO,CAAC;AAU/D,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;CACnB;AAED,MAAM,WAAW,cAAc;IAC3B,cAAc,EAAE,YAAY,EAAE,CAAC;IAC/B,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,YAAY,EAAE,YAAY,EAAE,CAAC;IAC7B,cAAc,EAAE,YAAY,EAAE,CAAC;CAClC;AAED,MAAM,WAAW,kBAAkB;IAC/B,MAAM,EAAE,cAAc,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,eAAe,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,kBAAkB,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;CAChE;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA4NtD,CAAC"}
@@ -1 +0,0 @@
1
- import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React,{useState,useEffect,useContext}from"react";import{AutoComplete}from"primereact/autocomplete";import{EventEmitterContext}from"../core/EventEmitterContext";import{AutoCoreTagContext}from"../core/AutoCoreTagContext";import{MessageType}from"../hub/CommandMessage";import{ValueInput}from"./ValueInput";import{TextInput}from"./TextInput";import{InputText}from"primereact/inputtext";export const TestSetupForm=({schema:e,defaultProjectId:t="",defaultDefinitionId:a="default",onProjectChange:s,onDefinitionChange:n,onValidationChange:r})=>{const[i,o]=useState({}),[c,l]=useState(t),[m,p]=useState(a);useEffect(()=>{s&&s(c)},[c,s]),useEffect(()=>{n&&n(m)},[m,n]);const[u,d]=useState([]),[f,x]=useState([]),[g,j]=useState(!1),{invoke:h,write:_}=useContext(EventEmitterContext),{rawValues:v,findTagByFqdn:C}=useContext(AutoCoreTagContext);useEffect(()=>{if(!e)return;const t=[...e.project_fields,...e.config_fields];o(e=>{let a=e;for(const s of t){if(!s.source)continue;const t=C(s.source);if(!t)continue;const n=v[t.tagName];null!=n&&(a[s.name]!==n&&(a===e&&(a={...e}),a[s.name]=n))}return a})},[e,v,C]),useEffect(()=>{(async()=>{try{const e=await h("results.list_projects",MessageType.Request,{});e.success&&e.data&&e.data.projects&&d(e.data.projects)}catch(e){}})()},[h]);useEffect(()=>{if(!e)return;let t=!0;c&&""!==c.trim()||(t=!1),m&&""!==m.trim()||(t=!1);const a=[...e.project_fields,...e.config_fields];for(const e of a)if(e.required&&(void 0===i[e.name]||""===i[e.name]||null===i[e.name])){t=!1;break}j(t),r&&r(t,i)},[i,e,c,m,r]);const y=async(e,t)=>{if(o({...i,[e.name]:t}),e.source)try{await _(e.source,t)}catch(e){}},N=e=>{const t=(e=>!e.required||void 0!==i[e.name]&&""!==i[e.name]&&null!==i[e.name])(e),a="string"!==e.type&&"bool"!==e.type;return _jsxs(React.Fragment,{children:[_jsx("span",{className:"ac-form-label",children:e.name}),a?_jsx(ValueInput,{label:void 0,value:null!=i[e.name]?Number(i[e.name]):null,onValueChanged:t=>y(e,t),className:t?"":"p-invalid"}):_jsx(TextInput,{label:void 0,value:null!=i[e.name]?String(i[e.name]):"",onValueChanged:t=>y(e,t),className:t?"":"p-invalid"}),_jsx("span",{className:"ac-form-units",children:e.units??""}),_jsx("span",{style:{color:t?"var(--green-500)":"var(--red-500)",display:"flex",alignItems:"center"},children:_jsx("i",{className:t?"pi pi-check":"pi pi-times"})})]},e.name)};return e?_jsxs("div",{className:"ac-form-grid",style:{padding:"1.25rem"},children:[_jsxs("h3",{className:"ac-form-section",style:{display:"flex",alignItems:"center",gap:"10px"},children:["Project & Definition",_jsx("span",{style:{color:g?"var(--green-500)":"var(--red-500)"},children:_jsx("i",{className:g?"pi pi-check-circle":"pi pi-exclamation-circle"})})]}),_jsx("span",{className:"ac-form-label",children:"Project ID"}),_jsx(AutoComplete,{value:c,suggestions:f,completeMethod:e=>{const t=e.query.toLowerCase();x(u.filter(e=>e.toLowerCase().includes(t)))},onChange:e=>(e=>{const t=(e||"").replace(/[^a-zA-Z0-9_]/g,"");l(t)})(e.value),dropdown:!0,placeholder:"Enter or select Project ID",className:c&&""!==c.trim()?"":"p-invalid"}),_jsx("span",{}),_jsx("span",{style:{color:c&&""!==c.trim()?"var(--green-500)":"var(--red-500)",display:"flex",alignItems:"center"},children:_jsx("i",{className:c&&""!==c.trim()?"pi pi-check":"pi pi-times"})}),_jsx("span",{className:"ac-form-label",children:"Definition ID"}),_jsx(InputText,{value:m,onChange:e=>(e=>{const t=e.replace(/[^a-zA-Z0-9_]/g,"");p(t)})(e.target.value),placeholder:"Enter Definition ID",className:m&&""!==m.trim()?"":"p-invalid"}),_jsx("span",{}),_jsx("span",{style:{color:m&&""!==m.trim()?"var(--green-500)":"var(--red-500)",display:"flex",alignItems:"center"},children:_jsx("i",{className:m&&""!==m.trim()?"pi pi-check":"pi pi-times"})}),_jsx("h3",{className:"ac-form-section",style:{marginTop:"1rem"},children:"Project Information"}),e.project_fields.map(N),_jsx("h3",{className:"ac-form-section",style:{marginTop:"1rem"},children:"Test Configuration"}),e.config_fields.map(N)]}):_jsx("div",{className:"ac-form-grid",style:{padding:"1.25rem"},children:_jsx("h3",{className:"ac-form-section",children:"No Test Definition Selected"})})};