@adcops/autocore-react 3.3.89 → 3.3.91

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 (96) hide show
  1. package/dist/assets/JogXNeg.d.ts +4 -0
  2. package/dist/assets/JogXNeg.d.ts.map +1 -0
  3. package/dist/assets/JogXNeg.js +1 -0
  4. package/dist/assets/JogXPos.d.ts +4 -0
  5. package/dist/assets/JogXPos.d.ts.map +1 -0
  6. package/dist/assets/JogXPos.js +1 -0
  7. package/dist/assets/JogYNeg.d.ts +4 -0
  8. package/dist/assets/JogYNeg.d.ts.map +1 -0
  9. package/dist/assets/JogYNeg.js +1 -0
  10. package/dist/assets/JogYPos.d.ts +4 -0
  11. package/dist/assets/JogYPos.d.ts.map +1 -0
  12. package/dist/assets/JogYPos.js +1 -0
  13. package/dist/assets/JogZNeg.d.ts +4 -0
  14. package/dist/assets/JogZNeg.d.ts.map +1 -0
  15. package/dist/assets/JogZNeg.js +1 -0
  16. package/dist/assets/JogZPos.d.ts +4 -0
  17. package/dist/assets/JogZPos.d.ts.map +1 -0
  18. package/dist/assets/JogZPos.js +1 -0
  19. package/dist/assets/Off.d.ts +4 -0
  20. package/dist/assets/Off.d.ts.map +1 -0
  21. package/dist/assets/Off.js +1 -0
  22. package/dist/assets/On.d.ts +4 -0
  23. package/dist/assets/On.d.ts.map +1 -0
  24. package/dist/assets/On.js +1 -0
  25. package/dist/assets/index.d.ts +8 -0
  26. package/dist/assets/index.d.ts.map +1 -1
  27. package/dist/assets/index.js +1 -1
  28. package/dist/assets/svg/off.svg +2 -0
  29. package/dist/assets/svg/on.svg +11 -0
  30. package/dist/components/JogPanel.d.ts +2 -2
  31. package/dist/components/JogPanel.d.ts.map +1 -1
  32. package/dist/components/JogPanel.js +1 -1
  33. package/dist/components/ams/AssetDetailView.js +1 -1
  34. package/dist/components/ams/AssetEditDialog.d.ts.map +1 -1
  35. package/dist/components/ams/AssetEditDialog.js +1 -1
  36. package/dist/components/ams/AssetRegistryTable.css +12 -0
  37. package/dist/components/ams/AssetRegistryTable.d.ts +1 -0
  38. package/dist/components/ams/AssetRegistryTable.d.ts.map +1 -1
  39. package/dist/components/ams/AssetRegistryTable.js +1 -1
  40. package/dist/components/tis/ConfigurationDialog.d.ts +21 -0
  41. package/dist/components/tis/ConfigurationDialog.d.ts.map +1 -0
  42. package/dist/components/tis/ConfigurationDialog.js +1 -0
  43. package/dist/components/tis/ResultHistoryTable.js +1 -1
  44. package/dist/components/tis/TestDataView.d.ts +47 -0
  45. package/dist/components/tis/TestDataView.d.ts.map +1 -1
  46. package/dist/components/tis/TestDataView.js +1 -1
  47. package/dist/components/tis/TestSetupForm.d.ts +37 -0
  48. package/dist/components/tis/TestSetupForm.d.ts.map +1 -1
  49. package/dist/components/tis/TestSetupForm.js +1 -1
  50. package/dist/components/tis/TisProvider.d.ts +25 -0
  51. package/dist/components/tis/TisProvider.d.ts.map +1 -1
  52. package/dist/components/tis/TisProvider.js +1 -1
  53. package/dist/components/tis/useRawCycleData.d.ts.map +1 -1
  54. package/dist/components/tis/useRawCycleData.js +1 -1
  55. package/dist/components/tis-editor/TisConfigEditor.css +20 -0
  56. package/dist/components/tis-editor/editor/ConfigurationsEditor.d.ts +19 -0
  57. package/dist/components/tis-editor/editor/ConfigurationsEditor.d.ts.map +1 -0
  58. package/dist/components/tis-editor/editor/ConfigurationsEditor.js +1 -0
  59. package/dist/components/tis-editor/editor/MethodFormEditor.d.ts.map +1 -1
  60. package/dist/components/tis-editor/editor/MethodFormEditor.js +1 -1
  61. package/dist/components/tis-editor/types.d.ts +13 -0
  62. package/dist/components/tis-editor/types.d.ts.map +1 -1
  63. package/dist/components/tis-editor/validation.d.ts.map +1 -1
  64. package/dist/components/tis-editor/validation.js +1 -1
  65. package/dist/themes/adc-dark/blue/theme.css +17 -2
  66. package/dist/themes/adc-dark/blue/theme.css.map +1 -1
  67. package/package.json +2 -1
  68. package/src/assets/JogXNeg.tsx +30 -0
  69. package/src/assets/JogXPos.tsx +30 -0
  70. package/src/assets/JogYNeg.tsx +30 -0
  71. package/src/assets/JogYPos.tsx +30 -0
  72. package/src/assets/JogZNeg.tsx +30 -0
  73. package/src/assets/JogZPos.tsx +30 -0
  74. package/src/assets/Off.tsx +14 -0
  75. package/src/assets/On.tsx +26 -0
  76. package/src/assets/index.ts +8 -0
  77. package/src/assets/svg/off.svg +2 -0
  78. package/src/assets/svg/on.svg +11 -0
  79. package/src/components/JogPanel.tsx +18 -28
  80. package/src/components/ams/AssetDetailView.tsx +1 -1
  81. package/src/components/ams/AssetEditDialog.tsx +25 -10
  82. package/src/components/ams/AssetRegistryTable.css +12 -0
  83. package/src/components/ams/AssetRegistryTable.tsx +15 -4
  84. package/src/components/tis/ConfigurationDialog.tsx +128 -0
  85. package/src/components/tis/ResultHistoryTable.tsx +2 -2
  86. package/src/components/tis/TestDataView.tsx +270 -12
  87. package/src/components/tis/TestSetupForm.tsx +167 -10
  88. package/src/components/tis/TisProvider.tsx +53 -0
  89. package/src/components/tis/useRawCycleData.ts +22 -3
  90. package/src/components/tis-editor/TisConfigEditor.css +20 -0
  91. package/src/components/tis-editor/editor/ConfigurationsEditor.tsx +242 -0
  92. package/src/components/tis-editor/editor/MethodFormEditor.tsx +4 -0
  93. package/src/components/tis-editor/types.ts +14 -0
  94. package/src/components/tis-editor/validation.ts +29 -0
  95. package/src/themes/adc-dark/_extensions.scss +20 -0
  96. package/src/themes/theme-base/components/panel/_fieldset.scss +2 -2
@@ -19,6 +19,7 @@ import { Distance, JogShort, JogMedium, JogLong } from '../assets';
19
19
  import { Speed, SpeedSlow, SpeedMedium, SpeedFast } from '../assets';
20
20
  import { RotationCcwA, RotationCcwB, RotationCcwC } from '../assets';
21
21
  import { RotationCwA, RotationCwB, RotationCwC } from '../assets';
22
+ import { JogXPos, JogXNeg, JogYPos, JogYNeg, JogZPos, JogZNeg } from '../assets';
22
23
 
23
24
  /**
24
25
  * Enumerates the source button or action when an event occurs.
@@ -125,9 +126,9 @@ interface JogPanelState {
125
126
  * A default jog button configuration for linear 3D motion.
126
127
  */
127
128
  export const DefaultLinearJogButtons : (JogPanelButtonDefinition | undefined)[][] = [
128
- [{ icon: "pi pi-arrow-up-left", action: JogPanelAction.yPositive, alt: "Y Positive" }, { icon: "pi pi-arrow-up", action: JogPanelAction.zPositive, alt: "Z Positive" }, undefined],
129
+ [undefined, { icon: "pi pi-arrow-up", action: JogPanelAction.zPositive, alt: "Z Positive" }, { icon: "pi pi-arrow-down-left", action: JogPanelAction.yNegative, alt: "Y Negative" }],
129
130
  [{ icon: "pi pi-arrow-left", action: JogPanelAction.xNegative, alt: "X Negative" }, undefined, { icon: "pi pi-arrow-right", action: JogPanelAction.xPositive, alt: "X Positive" }],
130
- [undefined, { icon: "pi pi-arrow-down", action: JogPanelAction.zNegative, alt: "Z Negative" }, { icon: "pi pi-arrow-down-right", action: JogPanelAction.yNegative, alt: "Y Negative" }],
131
+ [{ icon: "pi pi-arrow-up-right", action: JogPanelAction.yPositive, alt: "Y Positive" }, { icon: "pi pi-arrow-down", action: JogPanelAction.zNegative, alt: "Z Negative" }, undefined],
131
132
  ];
132
133
 
133
134
  /**
@@ -156,9 +157,9 @@ export const DefaultRotationJogButtons : (JogPanelButtonDefinition | undefined)[
156
157
  * Example:
157
158
  * ```
158
159
  * export const kDefaultButtonDefinitions : (JogPanelButtonDefinition | undefined)[][] = [
159
- * [{ icon: "pi pi-arrow-up-left", action: JogPanelAction.yPositive, alt: "Y Positive" }, { icon: "pi pi-arrow-up", action: JogPanelAction.zPositive, alt: "Z Positive" }, undefined],
160
+ * [undefined, { icon: "pi pi-arrow-up", action: JogPanelAction.zPositive, alt: "Z Positive" }, { icon: "pi pi-arrow-down-left", action: JogPanelAction.yNegative, alt: "Y Negative" }],
160
161
  * [{ icon: "pi pi-arrow-left", action: JogPanelAction.xNegative, alt: "X Negative" }, undefined, { icon: "pi pi-arrow-right", action: JogPanelAction.xPositive, alt: "X Positive" }],
161
- * [undefined, { icon: "pi pi-arrow-down", action: JogPanelAction.zNegative, alt: "Z Negative" }, { icon: "pi pi-arrow-down-right", action: JogPanelAction.yNegative, alt: "Y Negative" }],
162
+ * [{ icon: "pi pi-arrow-up-right", action: JogPanelAction.yPositive, alt: "Y Positive" }, { icon: "pi pi-arrow-down", action: JogPanelAction.zNegative, alt: "Z Negative" }, undefined],
162
163
  * ];
163
164
  * ```
164
165
  *
@@ -249,22 +250,22 @@ export class JogPanel extends React.Component<JogPanelProps, JogPanelState> {
249
250
  return <i/>
250
251
  }
251
252
  else if (action == JogPanelAction.xNegative) {
252
- return <i className="pi pi-arrow-left" />
253
+ return <JogXNeg />
253
254
  }
254
255
  else if (action == JogPanelAction.xPositive) {
255
- return <i className="pi pi-arrow-right" />
256
+ return <JogXPos />
256
257
  }
257
258
  else if (action == JogPanelAction.yNegative) {
258
- return <i className="pi pi-arrow-up-left" />
259
+ return <JogYNeg />
259
260
  }
260
261
  else if (action == JogPanelAction.yPositive) {
261
- return <i className="pi pi-arrow-down-right" />
262
+ return <JogYPos />
262
263
  }
263
264
  else if (action == JogPanelAction.zNegative) {
264
- return <i className="pi pi-up" />
265
+ return <JogZNeg />
265
266
  }
266
267
  else if (action == JogPanelAction.zPositive) {
267
- return <i className="pi pi-down" />
268
+ return <JogZPos />
268
269
  }
269
270
  else if (action == JogPanelAction.aNegative) {
270
271
  return <RotationCcwA />
@@ -299,24 +300,13 @@ export class JogPanel extends React.Component<JogPanelProps, JogPanelState> {
299
300
 
300
301
  const action = this.props.buttonDefinitions[row][col]?.action;
301
302
 
302
- if (action !== undefined && action < JogPanelAction.aPositive ) {
303
- return <Button
304
- key={`${row}-${col}`}
305
- icon={this.props.buttonDefinitions[row][col]?.icon}
306
- tooltip={this.props.buttonDefinitions[row][col]?.alt}
307
- onClick={() => this.handleClicked(action)}
308
- className="button-item"
309
- />
310
- }
311
- else {
312
- return <Button
313
- key={`${row}-${col}`}
314
- tooltip={this.props.buttonDefinitions[row][col]?.alt}
315
- onClick={() => this.handleClicked(action)}
316
- className="button-item"
317
- icon={() => this.actionToIcon(action)}/>
318
- }
319
-
303
+ return <Button
304
+ key={`${row}-${col}`}
305
+ tooltip={this.props.buttonDefinitions[row][col]?.alt}
306
+ onClick={() => this.handleClicked(action)}
307
+ className="button-item"
308
+ icon={() => this.actionToIcon(action)}/>
309
+
320
310
  }
321
311
  else {
322
312
  return <Button icon="pi" key={`${row}-${col}`} disabled={true} className="button-item empty-slot" />
@@ -235,7 +235,7 @@ export const AssetDetailView: React.FC = () => {
235
235
  <Button label="Edit" icon="pi pi-pencil"
236
236
  outlined
237
237
  onClick={() => setEditDialogOpen(true)}
238
- tooltip="Edit role, nameplate, and per-axis values. Type, serial, and install date are immutable."
238
+ tooltip="Edit serial, role, nameplate, and per-axis values. Type and install date are immutable."
239
239
  tooltipOptions={{ position: 'left' }}
240
240
  />
241
241
  {asset.status === 'active' && (
@@ -9,12 +9,13 @@
9
9
  * `asset.current_calibration_id` is non-null. Posts via
10
10
  * `ams.update_calibration` (server enforces "current only"). Tab
11
11
  * is hidden entirely for assets that never had a calibration —
12
- * "+ Calibration" on <AssetDetailView> is the path to add one.
12
+ * "Calibration" on <AssetDetailView> is the path to add one.
13
13
  *
14
- * The server treats `asset_id`, `asset_type`, `serial`, and
15
- * `install_date` as immutable; the read-only header strip mirrors
16
- * that. Status stays out of this dialog because the Retire button on
17
- * <AssetDetailView> already owns that transition.
14
+ * The server treats `asset_id`, `asset_type`, and `install_date` as
15
+ * immutable; the read-only header strip mirrors that. `serial` is
16
+ * editable (free-form traceability metadata) so a mis-keyed serial can
17
+ * be corrected here. Status stays out of this dialog because the Retire
18
+ * button on <AssetDetailView> already owns that transition.
18
19
  *
19
20
  * Save commits the Asset tab first, then (if a calibration is loaded)
20
21
  * the Calibration tab. Either failure surfaces inline and stops; the
@@ -175,6 +176,7 @@ export const AssetEditDialog: React.FC<AssetEditDialogProps> = ({
175
176
  // effect below.
176
177
  const [roleSelection, setRoleSelection] = useState<string>('');
177
178
  const [location, setLocation] = useState<string>('');
179
+ const [serial, setSerial] = useState<string>('');
178
180
  const [customFields, setCustomFields] =
179
181
  useState<Record<string, string>>({});
180
182
  const [subLocationFields, setSubLocationFields] =
@@ -215,6 +217,9 @@ export const AssetEditDialog: React.FC<AssetEditDialogProps> = ({
215
217
  setSubmitting(false);
216
218
  setActiveTab(0);
217
219
 
220
+ // Serial: free-form, editable so operators can correct a typo.
221
+ setSerial(typeof asset.serial === 'string' ? asset.serial : '');
222
+
218
223
  // Role: pick the dropdown option when the asset's location
219
224
  // matches a declared role; otherwise route into ROLE_OTHER so
220
225
  // the operator can keep the current custom string.
@@ -365,6 +370,7 @@ export const AssetEditDialog: React.FC<AssetEditDialogProps> = ({
365
370
  const payload: any = {
366
371
  asset_id: asset.asset_id,
367
372
  location,
373
+ serial,
368
374
  custom,
369
375
  };
370
376
  if (subLocations) payload.sub_locations = subLocations;
@@ -481,10 +487,11 @@ export const AssetEditDialog: React.FC<AssetEditDialogProps> = ({
481
487
  </>
482
488
  }
483
489
  >
484
- {/* Read-only context strip — type, serial, install_date.
485
- The server treats these as immutable; surfacing them
486
- here keeps the operator oriented without inviting an
487
- edit that would silently no-op. */}
490
+ {/* Read-only context strip — type, install_date. The server
491
+ treats these as immutable; surfacing them here keeps the
492
+ operator oriented without inviting an edit that would
493
+ silently no-op. Serial moved into the editable Asset tab
494
+ below so operators can correct a mis-entered serial. */}
488
495
  <div style={{ display: 'grid',
489
496
  gridTemplateColumns: 'auto 1fr',
490
497
  gap: '0.25rem 1rem',
@@ -492,7 +499,6 @@ export const AssetEditDialog: React.FC<AssetEditDialogProps> = ({
492
499
  color: 'var(--text-secondary-color)',
493
500
  marginBottom: '0.75rem' }}>
494
501
  <span>Type</span> <span>{typeLabel}</span>
495
- <span>Serial</span> <span>{asset.serial || <em>(none)</em>}</span>
496
502
  {asset.install_date && (
497
503
  <>
498
504
  <span>Installed</span>
@@ -507,6 +513,15 @@ export const AssetEditDialog: React.FC<AssetEditDialogProps> = ({
507
513
  gridTemplateColumns: 'auto 1fr',
508
514
  gap: '0.5rem 1rem',
509
515
  alignItems: 'center' }}>
516
+ {/* Serial — free-form manufacturer metadata. Editable so
517
+ a mis-entered serial can be corrected after the fact. */}
518
+ <label>Serial</label>
519
+ <InputText
520
+ value={serial}
521
+ placeholder="(none)"
522
+ onChange={(e) => setSerial(e.target.value)}
523
+ />
524
+
510
525
  {/* Role field. Asset types referenced only by_id_field
511
526
  (no by_location asset_ref) come back with an empty
512
527
  role list — we hide the row entirely so the operator
@@ -0,0 +1,12 @@
1
+ /*
2
+ * Touch-friendly row sizing for the AMS asset list.
3
+ *
4
+ * The shop-floor HMI is a touchscreen and operators were mis-tapping
5
+ * the dense default DataTable rows. Adding vertical padding to each
6
+ * body cell enlarges the per-row touch target without changing the
7
+ * column layout or text size.
8
+ */
9
+ .ams-asset-table .p-datatable-tbody > tr > td {
10
+ padding-top: 0.9rem;
11
+ padding-bottom: 0.9rem;
12
+ }
@@ -15,6 +15,7 @@ import { Dialog } from 'primereact/dialog';
15
15
  import { EventEmitterContext } from '../../core/EventEmitterContext';
16
16
  import { MessageType } from '../../hub/CommandMessage';
17
17
  import { useAms, type AmsAssetEntry, type AmsRole } from './AmsProvider';
18
+ import './AssetRegistryTable.css';
18
19
 
19
20
  // Sentinel value for the "Other..." dropdown option, which lets the
20
21
  // operator type a free-form role for the rare case (custom builds,
@@ -433,8 +434,11 @@ export const AssetRegistryTable: React.FC = () => {
433
434
  ? 'AMS not enabled in this project (no asset_types declared).'
434
435
  : 'No assets registered yet.'
435
436
  }
436
- size="small"
437
437
  stripedRows
438
+ /* Extra vertical padding on body cells (see the CSS) enlarges
439
+ the touch target for each row — operators on the shop-floor
440
+ touchscreen were mis-tapping the dense default rows. */
441
+ className="ams-asset-table"
438
442
  >
439
443
  <Column field="asset_id" header="Asset ID" />
440
444
  <Column field="asset_type" header="Type"
@@ -481,9 +485,16 @@ export const AssetRegistryTable: React.FC = () => {
481
485
  onChange={(e) => onAssetTypeChange(e.value)}
482
486
  placeholder="Choose asset type"
483
487
  />
484
- <label>Serial</label>
485
- <InputText value={addState.serial}
486
- onChange={(e) => setAddState(s => ({ ...s, serial: e.target.value }))} />
488
+ {/* Serial: hidden until a type is chosen. Showing it
489
+ before the type led operators to fill it in for a
490
+ not-yet-selected asset, which read as confusing. */}
491
+ {addState.assetType && (
492
+ <>
493
+ <label>Serial</label>
494
+ <InputText value={addState.serial}
495
+ onChange={(e) => setAddState(s => ({ ...s, serial: e.target.value }))} />
496
+ </>
497
+ )}
487
498
 
488
499
  {/* Role field: only shown when this asset_type has at
489
500
  least one declared role in project.json. Asset
@@ -0,0 +1,128 @@
1
+ /*
2
+ * Copyright (C) 2026 Automated Design Corp. All Rights Reserved.
3
+ *
4
+ * <ConfigurationDialog> — picker UI for choosing a method's named
5
+ * configuration (see `TestMethod.configurations`). Mirrors
6
+ * <TestMethodDialog>: a dropdown of the configurations declared on the
7
+ * active method plus the long-form description for whichever entry is
8
+ * highlighted. OK applies the choice via the supplied callback (which
9
+ * writes the configuration's `defaults` into the config_fields); Cancel
10
+ * discards.
11
+ *
12
+ * Only mounted by <TestSetupForm> when the active method declares one or
13
+ * more configurations, so the empty case is informational only.
14
+ */
15
+
16
+ import React, { useEffect, useMemo, useState } from 'react';
17
+ import { Button } from 'primereact/button';
18
+ import { Dialog } from 'primereact/dialog';
19
+ import { Dropdown } from 'primereact/dropdown';
20
+ import type { TestConfiguration } from './TestSetupForm';
21
+
22
+ /** Display name for one configuration: prefer `label`, fall back to `name`. */
23
+ export const configLabelOf = (cfg: TestConfiguration | undefined): string =>
24
+ (cfg?.label && cfg.label.length > 0) ? cfg.label : (cfg?.name ?? '');
25
+
26
+ export interface ConfigurationDialogProps {
27
+ visible: boolean;
28
+ onHide: () => void;
29
+ /** Configurations declared on the active method. */
30
+ configurations: TestConfiguration[];
31
+ /** `name` of the configuration currently applied on the form. The
32
+ * dropdown opens pointing at this so the dialog reflects state. */
33
+ currentConfigName: string;
34
+ /**
35
+ * Called with the chosen configuration `name` when the operator
36
+ * clicks OK. Cancel does not fire this. The parent applies the
37
+ * configuration's defaults to the fields.
38
+ */
39
+ onSelected: (configName: string) => void;
40
+ }
41
+
42
+ export const ConfigurationDialog: React.FC<ConfigurationDialogProps> = ({
43
+ visible, onHide, configurations, currentConfigName, onSelected,
44
+ }) => {
45
+ // Local "draft" selection — the dropdown writes here; OK applies it,
46
+ // so a Cancel really cancels (matches <TestMethodDialog>).
47
+ const [draftName, setDraftName] = useState<string>(currentConfigName);
48
+
49
+ useEffect(() => {
50
+ if (visible) setDraftName(currentConfigName);
51
+ }, [visible, currentConfigName]);
52
+
53
+ const options = useMemo(
54
+ () => configurations.map(cfg => ({ label: configLabelOf(cfg), value: cfg.name })),
55
+ [configurations],
56
+ );
57
+
58
+ const draftCfg = configurations.find(c => c.name === draftName);
59
+ const draftDescription =
60
+ (draftCfg?.description && draftCfg.description.length > 0)
61
+ ? draftCfg.description
62
+ : null;
63
+
64
+ const handleOk = () => {
65
+ if (draftName && draftName !== currentConfigName) {
66
+ onSelected(draftName);
67
+ }
68
+ onHide();
69
+ };
70
+
71
+ const footer = (
72
+ <div style={{ display: 'flex', justifyContent: 'flex-end', gap: '0.5rem' }}>
73
+ <Button label="Cancel" icon="pi pi-times" onClick={onHide} text />
74
+ <Button label="OK" icon="pi pi-check" onClick={handleOk} disabled={!draftName} />
75
+ </div>
76
+ );
77
+
78
+ return (
79
+ <Dialog
80
+ header="Select Configuration"
81
+ visible={visible}
82
+ onHide={onHide}
83
+ footer={footer}
84
+ modal
85
+ style={{ width: 'min(560px, 90vw)' }}
86
+ >
87
+ {options.length === 0 ? (
88
+ <p style={{ color: 'var(--text-secondary-color)' }}>
89
+ This test method declares no configurations.
90
+ </p>
91
+ ) : (
92
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
93
+ <div style={{ display: 'flex', alignItems: 'center', gap: '0.75rem' }}>
94
+ <label htmlFor="acConfigurationDropdown" style={{ flexShrink: 0 }}>
95
+ Configuration:
96
+ </label>
97
+ <Dropdown
98
+ inputId="acConfigurationDropdown"
99
+ value={draftName}
100
+ options={options}
101
+ onChange={(e) => setDraftName(e.value)}
102
+ placeholder="Select a configuration"
103
+ style={{ flex: 1 }}
104
+ />
105
+ </div>
106
+ {/* Stable-height description region, matching
107
+ <TestMethodDialog>: render a muted placeholder
108
+ rather than collapsing the dialog. */}
109
+ <div
110
+ style={{
111
+ padding: '0.75rem 1rem',
112
+ background: 'var(--surface-100)',
113
+ borderRadius: '6px',
114
+ minHeight: '4.5rem',
115
+ color: draftDescription
116
+ ? 'var(--text-color)'
117
+ : 'var(--text-secondary-color)',
118
+ fontStyle: draftDescription ? 'normal' : 'italic',
119
+ whiteSpace: 'pre-wrap',
120
+ }}
121
+ >
122
+ {draftDescription ?? 'No description provided for this configuration.'}
123
+ </div>
124
+ </div>
125
+ )}
126
+ </Dialog>
127
+ );
128
+ };
@@ -300,7 +300,7 @@ export const ResultHistoryTable: React.FC<ResultHistoryTableProps> = (props) =>
300
300
  <div style={{ display: 'flex', gap: '0.4rem' }}>
301
301
  <Button
302
302
  icon={isDataBusy ? 'pi pi-spin pi-spinner' : 'pi pi-download'}
303
- label="Data"
303
+ label="Raw"
304
304
  size="small"
305
305
  outlined
306
306
  disabled={anyBusy}
@@ -310,7 +310,7 @@ export const ResultHistoryTable: React.FC<ResultHistoryTableProps> = (props) =>
310
310
  />
311
311
  <Button
312
312
  icon={isReportBusy ? 'pi pi-spin pi-spinner' : 'pi pi-file'}
313
- label="Report"
313
+ label="Results"
314
314
  size="small"
315
315
  outlined
316
316
  disabled={anyBusy}