@adcops/autocore-react 3.3.23 → 3.3.25

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.
@@ -13,11 +13,12 @@ export interface TestDefinition {
13
13
  results_fields: TestFieldDef[];
14
14
  }
15
15
  export interface TestSetupFormProps {
16
- projectId: string;
17
- definitionId: string;
18
16
  schema: TestDefinition;
19
- onStartTest: (config: any) => void;
20
- onCancel?: () => void;
17
+ defaultProjectId?: string;
18
+ defaultDefinitionId?: string;
19
+ onProjectChange?: (projectId: string) => void;
20
+ onDefinitionChange?: (definitionId: string) => void;
21
+ onValidationChange?: (isValid: boolean, config: any) => void;
21
22
  }
22
23
  export declare const TestSetupForm: React.FC<TestSetupFormProps>;
23
24
  //# sourceMappingURL=TestSetupForm.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TestSetupForm.d.ts","sourceRoot":"","sources":["../../src/components/TestSetupForm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAInD,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,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,cAAc,CAAC;IACvB,WAAW,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IACnC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAsEtD,CAAC"}
1
+ {"version":3,"file":"TestSetupForm.d.ts","sourceRoot":"","sources":["../../src/components/TestSetupForm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA0C,MAAM,OAAO,CAAC;AAO/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,CAgKtD,CAAC"}
@@ -1 +1 @@
1
- import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React,{useState,useEffect}from"react";import{Button}from"primereact/button";import{InputText}from"primereact/inputtext";export const TestSetupForm=({schema:e,onStartTest:s,onCancel:a})=>{const[t,n]=useState({}),[r,i]=useState(!1);useEffect(()=>{let s=!0;const a=[...e.project_fields,...e.config_fields];for(const e of a)if(e.required&&!e.source&&(void 0===t[e.name]||""===t[e.name])){s=!1;break}i(s)},[t,e]);const o=e=>e.source?_jsxs("div",{className:"ac-form-span p-inputgroup",children:[_jsx("span",{className:"p-inputgroup-addon",children:e.name}),_jsx(InputText,{value:`Auto-fetched from ${e.source}`,disabled:!0}),e.units&&_jsx("span",{className:"p-inputgroup-addon",children:e.units})]},e.name):_jsxs("div",{className:"ac-form-span p-inputgroup",children:[_jsxs("span",{className:"p-inputgroup-addon",children:[e.name," ",e.required?"*":""]}),_jsx(InputText,{value:t[e.name]||"",onChange:s=>n({...t,[e.name]:s.target.value}),placeholder:`Enter ${e.name}`}),e.units&&_jsx("span",{className:"p-inputgroup-addon",children:e.units})]},e.name);return _jsxs("div",{className:"ac-form-grid",style:{padding:"1.25rem"},children:[_jsx("h3",{className:"ac-form-section",children:"Project Information"}),e.project_fields.map(o),_jsx("h3",{className:"ac-form-section",style:{marginTop:"1rem"},children:"Test Configuration"}),e.config_fields.map(o),_jsxs("div",{className:"ac-form-wide",style:{display:"flex",gap:"1rem",marginTop:"2rem"},children:[_jsx(Button,{label:"Start Test",icon:"pi pi-play",severity:"success",disabled:!r,onClick:()=>s(t)}),a&&_jsx(Button,{label:"Cancel",icon:"pi pi-times",severity:"secondary",onClick:a})]})]})};
1
+ import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React,{useState,useEffect,useContext}from"react";import{InputText}from"primereact/inputtext";import{AutoComplete}from"primereact/autocomplete";import{EventEmitterContext}from"../core/EventEmitterContext";import{MessageType}from"../hub/CommandMessage";export const TestSetupForm=({schema:e,defaultProjectId:s="",defaultDefinitionId:a="default",onProjectChange:t,onDefinitionChange:n,onValidationChange:r})=>{const[i,o]=useState({}),[c,p]=useState(s),[l,m]=useState(a);useEffect(()=>{t&&t(c)},[c,t]),useEffect(()=>{n&&n(l)},[l,n]);const[u,d]=useState([]),[f,x]=useState([]),[j,g]=useState(!1),{invoke:h}=useContext(EventEmitterContext);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(()=>{let s=!0;c&&""!==c.trim()||(s=!1),l&&""!==l.trim()||(s=!1);const a=[...e.project_fields,...e.config_fields];for(const e of a)if(e.required&&!e.source&&(void 0===i[e.name]||""===i[e.name])){s=!1;break}g(s),r&&r(s,i)},[i,e,c,l,r]);const _=e=>{if(e.source)return _jsxs("div",{className:"ac-form-span p-inputgroup",children:[_jsx("span",{className:"p-inputgroup-addon",children:e.name}),_jsx(InputText,{value:`Auto-fetched from ${e.source}`,disabled:!0}),e.units&&_jsx("span",{className:"p-inputgroup-addon",children:e.units}),_jsx("span",{className:"p-inputgroup-addon",style:{color:"var(--green-500)"},children:_jsx("i",{className:"pi pi-check"})})]},e.name);const s=(e=>!(e.required&&!e.source)||void 0!==i[e.name]&&""!==i[e.name])(e);return _jsxs("div",{className:"ac-form-span p-inputgroup",children:[_jsx("span",{className:"p-inputgroup-addon",children:e.name}),_jsx(InputText,{value:i[e.name]||"",onChange:s=>o({...i,[e.name]:s.target.value}),placeholder:`Enter ${e.name}`,className:s?"":"p-invalid"}),e.units&&_jsx("span",{className:"p-inputgroup-addon",children:e.units}),_jsx("span",{className:"p-inputgroup-addon",style:{color:s?"var(--green-500)":"var(--red-500)"},children:_jsx("i",{className:s?"pi pi-check":"pi pi-times"})})]},e.name)};return _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:j?"var(--green-500)":"var(--red-500)"},children:_jsx("i",{className:j?"pi pi-check-circle":"pi pi-exclamation-circle"})})]}),_jsxs("div",{className:"ac-form-span p-inputgroup",children:[_jsx("span",{className:"p-inputgroup-addon",children:"Project ID"}),_jsx(AutoComplete,{value:c,suggestions:f,completeMethod:e=>{const s=e.query.toLowerCase();x(u.filter(e=>e.toLowerCase().includes(s)))},onChange:e=>(e=>{const s=e.replace(/[^a-zA-Z0-9_]/g,"");p(s)})(e.value),dropdown:!0,placeholder:"Enter or select Project ID",className:c&&""!==c.trim()?"":"p-invalid"}),_jsx("span",{className:"p-inputgroup-addon",style:{color:c&&""!==c.trim()?"var(--green-500)":"var(--red-500)"},children:_jsx("i",{className:c&&""!==c.trim()?"pi pi-check":"pi pi-times"})})]}),_jsxs("div",{className:"ac-form-span p-inputgroup",children:[_jsx("span",{className:"p-inputgroup-addon",children:"Definition ID"}),_jsx(InputText,{value:l,onChange:e=>(e=>{const s=e.replace(/[^a-zA-Z0-9_]/g,"");m(s)})(e.target.value),placeholder:"Enter Definition ID",className:l&&""!==l.trim()?"":"p-invalid"}),_jsx("span",{className:"p-inputgroup-addon",style:{color:l&&""!==l.trim()?"var(--green-500)":"var(--red-500)"},children:_jsx("i",{className:l&&""!==l.trim()?"pi pi-check":"pi pi-times"})})]}),_jsx("h3",{className:"ac-form-section",style:{marginTop:"1rem"},children:"Project Information"}),e.project_fields.map(_),_jsx("h3",{className:"ac-form-section",style:{marginTop:"1rem"},children:"Test Configuration"}),e.config_fields.map(_)]})};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adcops/autocore-react",
3
- "version": "3.3.23",
3
+ "version": "3.3.25",
4
4
  "description": "A React component library for industrial user interfaces.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -40,7 +40,7 @@
40
40
  "homepage": "https://automateddesign.com",
41
41
  "peerDependencies": {
42
42
  "@types/react": "^18",
43
- "primereact": ">=10.6.3",
43
+ "primereact": ">=10.9.7",
44
44
  "react": "^18",
45
45
  "react-dom": "^18"
46
46
  },
@@ -1,6 +1,9 @@
1
- import React, { useState, useEffect } from 'react';
2
- import { Button } from 'primereact/button';
1
+ import React, { useState, useEffect, useContext } from 'react';
3
2
  import { InputText } from 'primereact/inputtext';
3
+ import { AutoComplete } from 'primereact/autocomplete';
4
+ import type { AutoCompleteCompleteEvent } from 'primereact/autocomplete';
5
+ import { EventEmitterContext } from '../core/EventEmitterContext';
6
+ import { MessageType } from '../hub/CommandMessage';
4
7
 
5
8
  export interface TestFieldDef {
6
9
  name: string;
@@ -18,19 +21,75 @@ export interface TestDefinition {
18
21
  }
19
22
 
20
23
  export interface TestSetupFormProps {
21
- projectId: string;
22
- definitionId: string;
23
24
  schema: TestDefinition;
24
- onStartTest: (config: any) => void;
25
- onCancel?: () => void;
25
+ defaultProjectId?: string;
26
+ defaultDefinitionId?: string;
27
+ onProjectChange?: (projectId: string) => void;
28
+ onDefinitionChange?: (definitionId: string) => void;
29
+ onValidationChange?: (isValid: boolean, config: any) => void;
26
30
  }
27
31
 
28
- export const TestSetupForm: React.FC<TestSetupFormProps> = ({ schema, onStartTest, onCancel }) => {
32
+ export const TestSetupForm: React.FC<TestSetupFormProps> = ({
33
+ schema,
34
+ defaultProjectId = "",
35
+ defaultDefinitionId = "default",
36
+ onProjectChange,
37
+ onDefinitionChange,
38
+ onValidationChange
39
+ }) => {
29
40
  const [config, setConfig] = useState<any>({});
41
+ const [projectId, setProjectId] = useState<string>(defaultProjectId);
42
+ const [definitionId, setDefinitionId] = useState<string>(defaultDefinitionId);
43
+
44
+ // Notify parent when projectId or definitionId changes
45
+ useEffect(() => {
46
+ if (onProjectChange) onProjectChange(projectId);
47
+ }, [projectId, onProjectChange]);
48
+
49
+ useEffect(() => {
50
+ if (onDefinitionChange) onDefinitionChange(definitionId);
51
+ }, [definitionId, onDefinitionChange]);
52
+
53
+ const [existingProjects, setExistingProjects] = useState<string[]>([]);
54
+ const [filteredProjects, setFilteredProjects] = useState<string[]>([]);
55
+
30
56
  const [isValid, setIsValid] = useState(false);
57
+ const { invoke } = useContext(EventEmitterContext);
58
+
59
+ useEffect(() => {
60
+ const fetchProjects = async () => {
61
+ try {
62
+ const resp: any = await invoke('results.list_projects' as any, MessageType.Request as any, {} as any);
63
+ if (resp.success && resp.data && resp.data.projects) {
64
+ setExistingProjects(resp.data.projects);
65
+ }
66
+ } catch (err) {
67
+ console.error("Failed to list projects", err);
68
+ }
69
+ };
70
+ fetchProjects();
71
+ }, [invoke]);
72
+
73
+ const searchProjects = (event: AutoCompleteCompleteEvent) => {
74
+ const query = event.query.toLowerCase();
75
+ setFilteredProjects(existingProjects.filter(p => p.toLowerCase().includes(query)));
76
+ };
77
+
78
+ const handleProjectIdChange = (value: string) => {
79
+ const sanitized = value.replace(/[^a-zA-Z0-9_]/g, '');
80
+ setProjectId(sanitized);
81
+ };
82
+
83
+ const handleDefinitionIdChange = (value: string) => {
84
+ const sanitized = value.replace(/[^a-zA-Z0-9_]/g, '');
85
+ setDefinitionId(sanitized);
86
+ };
31
87
 
32
88
  useEffect(() => {
33
89
  let valid = true;
90
+ if (!projectId || projectId.trim() === '') valid = false;
91
+ if (!definitionId || definitionId.trim() === '') valid = false;
92
+
34
93
  const allFields = [...schema.project_fields, ...schema.config_fields];
35
94
 
36
95
  for (const field of allFields) {
@@ -42,7 +101,15 @@ export const TestSetupForm: React.FC<TestSetupFormProps> = ({ schema, onStartTes
42
101
  }
43
102
  }
44
103
  setIsValid(valid);
45
- }, [config, schema]);
104
+ if (onValidationChange) {
105
+ onValidationChange(valid, config);
106
+ }
107
+ }, [config, schema, projectId, definitionId, onValidationChange]);
108
+
109
+ const isFieldValid = (field: TestFieldDef) => {
110
+ if (!field.required || field.source) return true;
111
+ return config[field.name] !== undefined && config[field.name] !== '';
112
+ };
46
113
 
47
114
  const renderField = (field: TestFieldDef) => {
48
115
  if (field.source) {
@@ -51,48 +118,75 @@ export const TestSetupForm: React.FC<TestSetupFormProps> = ({ schema, onStartTes
51
118
  <span className="p-inputgroup-addon">{field.name}</span>
52
119
  <InputText value={`Auto-fetched from ${field.source}`} disabled />
53
120
  {field.units && <span className="p-inputgroup-addon">{field.units}</span>}
121
+ <span className="p-inputgroup-addon" style={{ color: 'var(--green-500)' }}>
122
+ <i className="pi pi-check"></i>
123
+ </span>
54
124
  </div>
55
125
  );
56
126
  }
57
127
 
128
+ const valid = isFieldValid(field);
129
+
58
130
  return (
59
131
  <div key={field.name} className="ac-form-span p-inputgroup">
60
- <span className="p-inputgroup-addon">{field.name} {field.required ? '*' : ''}</span>
132
+ <span className="p-inputgroup-addon">{field.name}</span>
61
133
  <InputText
62
134
  value={config[field.name] || ''}
63
135
  onChange={(e) => setConfig({...config, [field.name]: e.target.value})}
64
136
  placeholder={`Enter ${field.name}`}
137
+ className={!valid ? 'p-invalid' : ''}
65
138
  />
66
139
  {field.units && <span className="p-inputgroup-addon">{field.units}</span>}
140
+ <span className="p-inputgroup-addon" style={{ color: valid ? 'var(--green-500)' : 'var(--red-500)' }}>
141
+ <i className={valid ? "pi pi-check" : "pi pi-times"}></i>
142
+ </span>
67
143
  </div>
68
144
  );
69
145
  };
70
146
 
71
147
  return (
72
148
  <div className="ac-form-grid" style={{ padding: '1.25rem' }}>
73
- <h3 className="ac-form-section">Project Information</h3>
149
+ <h3 className="ac-form-section" style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
150
+ Project & Definition
151
+ <span style={{ color: isValid ? 'var(--green-500)' : 'var(--red-500)' }}>
152
+ <i className={isValid ? "pi pi-check-circle" : "pi pi-exclamation-circle"}></i>
153
+ </span>
154
+ </h3>
155
+
156
+ <div className="ac-form-span p-inputgroup">
157
+ <span className="p-inputgroup-addon">Project ID</span>
158
+ <AutoComplete
159
+ value={projectId}
160
+ suggestions={filteredProjects}
161
+ completeMethod={searchProjects}
162
+ onChange={(e) => handleProjectIdChange(e.value)}
163
+ dropdown
164
+ placeholder="Enter or select Project ID"
165
+ className={!projectId || projectId.trim() === '' ? 'p-invalid' : ''}
166
+ />
167
+ <span className="p-inputgroup-addon" style={{ color: projectId && projectId.trim() !== '' ? 'var(--green-500)' : 'var(--red-500)' }}>
168
+ <i className={projectId && projectId.trim() !== '' ? "pi pi-check" : "pi pi-times"}></i>
169
+ </span>
170
+ </div>
171
+
172
+ <div className="ac-form-span p-inputgroup">
173
+ <span className="p-inputgroup-addon">Definition ID</span>
174
+ <InputText
175
+ value={definitionId}
176
+ onChange={(e) => handleDefinitionIdChange(e.target.value)}
177
+ placeholder="Enter Definition ID"
178
+ className={!definitionId || definitionId.trim() === '' ? 'p-invalid' : ''}
179
+ />
180
+ <span className="p-inputgroup-addon" style={{ color: definitionId && definitionId.trim() !== '' ? 'var(--green-500)' : 'var(--red-500)' }}>
181
+ <i className={definitionId && definitionId.trim() !== '' ? "pi pi-check" : "pi pi-times"}></i>
182
+ </span>
183
+ </div>
184
+
185
+ <h3 className="ac-form-section" style={{ marginTop: '1rem' }}>Project Information</h3>
74
186
  {schema.project_fields.map(renderField)}
75
187
 
76
188
  <h3 className="ac-form-section" style={{ marginTop: '1rem' }}>Test Configuration</h3>
77
189
  {schema.config_fields.map(renderField)}
78
-
79
- <div className="ac-form-wide" style={{ display: 'flex', gap: '1rem', marginTop: '2rem' }}>
80
- <Button
81
- label="Start Test"
82
- icon="pi pi-play"
83
- severity="success"
84
- disabled={!isValid}
85
- onClick={() => onStartTest(config)}
86
- />
87
- {onCancel && (
88
- <Button
89
- label="Cancel"
90
- icon="pi pi-times"
91
- severity="secondary"
92
- onClick={onCancel}
93
- />
94
- )}
95
- </div>
96
190
  </div>
97
191
  );
98
192
  };