@adcops/autocore-react 3.3.40 → 3.3.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TestSetupForm.d.ts","sourceRoot":"","sources":["../../src/components/TestSetupForm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA0C,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"TestSetupForm.d.ts","sourceRoot":"","sources":["../../src/components/TestSetupForm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA0C,MAAM,OAAO,CAAC;AAS/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,CAsOtD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React,{useState,useEffect,useContext}from"react";import{
|
|
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{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:s="default",onProjectChange:a,onDefinitionChange:n,onValidationChange:i})=>{const[r,o]=useState({}),[c,l]=useState(t),[m,p]=useState(s);useEffect(()=>{a&&a(c)},[c,a]),useEffect(()=>{n&&n(m)},[m,n]);const[u,d]=useState([]),[f,x]=useState([]),[j,g]=useState(!1),{invoke:h,write:_,subscribe:v,unsubscribe:y}=useContext(EventEmitterContext);useEffect(()=>{if(!e)return;const t=[...e.project_fields,...e.config_fields],s=[];for(const e of t){if(!e.source)continue;const t=e.source,a=e.name,n=v(t,e=>{o(t=>t[a]!==e?{...t,[a]:e}:t)});s.push(n),(async()=>{try{const e=await h(t,MessageType.Read,{}),s=void 0!==e?.data?e.data:e;null!=s&&o(e=>void 0===e[a]||null===e[a]||""===e[a]?{...e,[a]:s}:e)}catch(e){}})()}return()=>{for(const e of s)y(e)}},[e,v,y,h]),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 s=[...e.project_fields,...e.config_fields];for(const e of s)if(e.required&&(void 0===r[e.name]||""===r[e.name]||null===r[e.name])){t=!1;break}g(t),i&&i(t,r)},[r,e,c,m,i]);const I=async(e,t)=>{if(o({...r,[e.name]:t}),e.source)try{await _(e.source,t)}catch(e){}},N=e=>{const t=(e=>!e.required||void 0!==r[e.name]&&""!==r[e.name]&&null!==r[e.name])(e),s="string"!==e.type&&"bool"!==e.type;return _jsxs(React.Fragment,{children:[_jsx("span",{className:"ac-form-label",children:e.name}),s?_jsx(ValueInput,{label:void 0,value:null!=r[e.name]?Number(r[e.name]):null,suffix:e.units?` ${e.units}`:void 0,onValueChanged:t=>I(e,t),className:t?"":"p-invalid"}):_jsx(TextInput,{label:void 0,value:null!=r[e.name]?String(r[e.name]):"",suffix:e.units?` ${e.units}`:void 0,onValueChanged:t=>I(e,t),className:t?"":"p-invalid"}),_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:j?"var(--green-500)":"var(--red-500)"},children:_jsx("i",{className:j?"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",{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",{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"})})};
|
package/package.json
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import React, { useState, useEffect, useContext } from 'react';
|
|
2
|
-
import { InputText } from 'primereact/inputtext';
|
|
3
2
|
import { AutoComplete } from 'primereact/autocomplete';
|
|
4
3
|
import type { AutoCompleteCompleteEvent } from 'primereact/autocomplete';
|
|
5
4
|
import { EventEmitterContext } from '../core/EventEmitterContext';
|
|
6
5
|
import { MessageType } from '../hub/CommandMessage';
|
|
6
|
+
import { ValueInput } from './ValueInput';
|
|
7
|
+
import { TextInput } from './TextInput';
|
|
8
|
+
import { InputText } from 'primereact/inputtext';
|
|
7
9
|
|
|
8
10
|
export interface TestFieldDef {
|
|
9
11
|
name: string;
|
|
@@ -54,7 +56,62 @@ export const TestSetupForm: React.FC<TestSetupFormProps> = ({
|
|
|
54
56
|
const [filteredProjects, setFilteredProjects] = useState<string[]>([]);
|
|
55
57
|
|
|
56
58
|
const [isValid, setIsValid] = useState(false);
|
|
57
|
-
const { invoke } = useContext(EventEmitterContext);
|
|
59
|
+
const { invoke, write, subscribe, unsubscribe } = useContext(EventEmitterContext);
|
|
60
|
+
|
|
61
|
+
// Subscribe to external tags if a field defines a source, and seed the
|
|
62
|
+
// current value once on mount so the form reflects existing GM state
|
|
63
|
+
// instead of staying blank until the next broadcast.
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
if (!schema) return;
|
|
66
|
+
|
|
67
|
+
const allFields = [...schema.project_fields, ...schema.config_fields];
|
|
68
|
+
const subs: any[] = [];
|
|
69
|
+
|
|
70
|
+
for (const field of allFields) {
|
|
71
|
+
if (!field.source) continue;
|
|
72
|
+
|
|
73
|
+
const source = field.source;
|
|
74
|
+
const fieldName = field.name;
|
|
75
|
+
|
|
76
|
+
const subId = subscribe(source, (newVal: any) => {
|
|
77
|
+
setConfig((prev: any) => {
|
|
78
|
+
if (prev[fieldName] !== newVal) {
|
|
79
|
+
return { ...prev, [fieldName]: newVal };
|
|
80
|
+
}
|
|
81
|
+
return prev;
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
subs.push(subId);
|
|
85
|
+
|
|
86
|
+
// Pub/sub only delivers future changes, not the current value.
|
|
87
|
+
// Fetch it explicitly so reloading the page doesn't blank the form.
|
|
88
|
+
(async () => {
|
|
89
|
+
try {
|
|
90
|
+
const resp: any = await invoke(
|
|
91
|
+
source as any,
|
|
92
|
+
MessageType.Read as any,
|
|
93
|
+
{} as any,
|
|
94
|
+
);
|
|
95
|
+
const current = resp?.data !== undefined ? resp.data : resp;
|
|
96
|
+
if (current !== undefined && current !== null) {
|
|
97
|
+
setConfig((prev: any) => (
|
|
98
|
+
prev[fieldName] === undefined || prev[fieldName] === null || prev[fieldName] === ''
|
|
99
|
+
? { ...prev, [fieldName]: current }
|
|
100
|
+
: prev
|
|
101
|
+
));
|
|
102
|
+
}
|
|
103
|
+
} catch (err) {
|
|
104
|
+
console.warn(`TestSetupForm: failed to seed "${fieldName}" from "${source}":`, err);
|
|
105
|
+
}
|
|
106
|
+
})();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return () => {
|
|
110
|
+
for (const subId of subs) {
|
|
111
|
+
unsubscribe(subId);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
}, [schema, subscribe, unsubscribe, invoke]);
|
|
58
115
|
|
|
59
116
|
useEffect(() => {
|
|
60
117
|
const fetchProjects = async () => {
|
|
@@ -89,8 +146,8 @@ export const TestSetupForm: React.FC<TestSetupFormProps> = ({
|
|
|
89
146
|
const allFields = [...schema.project_fields, ...schema.config_fields];
|
|
90
147
|
|
|
91
148
|
for (const field of allFields) {
|
|
92
|
-
if (field.required
|
|
93
|
-
if (config[field.name] === undefined || config[field.name] === '') {
|
|
149
|
+
if (field.required) {
|
|
150
|
+
if (config[field.name] === undefined || config[field.name] === '' || config[field.name] === null) {
|
|
94
151
|
valid = false;
|
|
95
152
|
break;
|
|
96
153
|
}
|
|
@@ -103,8 +160,8 @@ export const TestSetupForm: React.FC<TestSetupFormProps> = ({
|
|
|
103
160
|
}, [config, schema, projectId, definitionId, onValidationChange]);
|
|
104
161
|
|
|
105
162
|
const isFieldValid = (field: TestFieldDef) => {
|
|
106
|
-
if (!field.required
|
|
107
|
-
return config[field.name] !== undefined && config[field.name] !== '';
|
|
163
|
+
if (!field.required) return true;
|
|
164
|
+
return config[field.name] !== undefined && config[field.name] !== '' && config[field.name] !== null;
|
|
108
165
|
};
|
|
109
166
|
|
|
110
167
|
const handleProjectIdChange = (value: string | null | undefined) => {
|
|
@@ -113,36 +170,45 @@ export const TestSetupForm: React.FC<TestSetupFormProps> = ({
|
|
|
113
170
|
setProjectId(sanitized);
|
|
114
171
|
};
|
|
115
172
|
|
|
116
|
-
const
|
|
173
|
+
const handleFieldChange = async (field: TestFieldDef, val: any) => {
|
|
174
|
+
setConfig({...config, [field.name]: val});
|
|
117
175
|
if (field.source) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
<span className="p-inputgroup-addon" style={{ color: 'var(--green-500)' }}>
|
|
124
|
-
<i className="pi pi-check"></i>
|
|
125
|
-
</span>
|
|
126
|
-
</div>
|
|
127
|
-
);
|
|
176
|
+
try {
|
|
177
|
+
await write(field.source, val);
|
|
178
|
+
} catch(e) {
|
|
179
|
+
console.error("Failed to write to source:", e);
|
|
180
|
+
}
|
|
128
181
|
}
|
|
182
|
+
};
|
|
129
183
|
|
|
184
|
+
const renderField = (field: TestFieldDef) => {
|
|
130
185
|
const valid = isFieldValid(field);
|
|
186
|
+
const isNum = field.type !== 'string' && field.type !== 'bool';
|
|
131
187
|
|
|
132
188
|
return (
|
|
133
|
-
<
|
|
134
|
-
<span className="
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
189
|
+
<React.Fragment key={field.name}>
|
|
190
|
+
<span className="ac-form-label">{field.name}</span>
|
|
191
|
+
{isNum ? (
|
|
192
|
+
<ValueInput
|
|
193
|
+
label={undefined}
|
|
194
|
+
value={config[field.name] != null ? Number(config[field.name]) : null}
|
|
195
|
+
suffix={field.units ? ` ${field.units}` : undefined}
|
|
196
|
+
onValueChanged={(val) => handleFieldChange(field, val)}
|
|
197
|
+
className={!valid ? 'p-invalid' : ''}
|
|
198
|
+
/>
|
|
199
|
+
) : (
|
|
200
|
+
<TextInput
|
|
201
|
+
label={undefined}
|
|
202
|
+
value={config[field.name] != null ? String(config[field.name]) : ''}
|
|
203
|
+
suffix={field.units ? ` ${field.units}` : undefined}
|
|
204
|
+
onValueChanged={(val) => handleFieldChange(field, val)}
|
|
205
|
+
className={!valid ? 'p-invalid' : ''}
|
|
206
|
+
/>
|
|
207
|
+
)}
|
|
208
|
+
<span style={{ color: valid ? 'var(--green-500)' : 'var(--red-500)', display: 'flex', alignItems: 'center' }}>
|
|
143
209
|
<i className={valid ? "pi pi-check" : "pi pi-times"}></i>
|
|
144
210
|
</span>
|
|
145
|
-
</
|
|
211
|
+
</React.Fragment>
|
|
146
212
|
);
|
|
147
213
|
};
|
|
148
214
|
|
|
@@ -163,34 +229,30 @@ export const TestSetupForm: React.FC<TestSetupFormProps> = ({
|
|
|
163
229
|
</span>
|
|
164
230
|
</h3>
|
|
165
231
|
|
|
166
|
-
<
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
<
|
|
178
|
-
|
|
179
|
-
</span>
|
|
180
|
-
</div>
|
|
232
|
+
<span className="ac-form-label">Project ID</span>
|
|
233
|
+
<AutoComplete
|
|
234
|
+
value={projectId}
|
|
235
|
+
suggestions={filteredProjects}
|
|
236
|
+
completeMethod={searchProjects}
|
|
237
|
+
onChange={(e) => handleProjectIdChange(e.value)}
|
|
238
|
+
dropdown
|
|
239
|
+
placeholder="Enter or select Project ID"
|
|
240
|
+
className={!projectId || projectId.trim() === '' ? 'p-invalid' : ''}
|
|
241
|
+
/>
|
|
242
|
+
<span style={{ color: projectId && projectId.trim() !== '' ? 'var(--green-500)' : 'var(--red-500)', display: 'flex', alignItems: 'center' }}>
|
|
243
|
+
<i className={projectId && projectId.trim() !== '' ? "pi pi-check" : "pi pi-times"}></i>
|
|
244
|
+
</span>
|
|
181
245
|
|
|
182
|
-
<
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
<
|
|
191
|
-
|
|
192
|
-
</span>
|
|
193
|
-
</div>
|
|
246
|
+
<span className="ac-form-label">Definition ID</span>
|
|
247
|
+
<InputText
|
|
248
|
+
value={definitionId}
|
|
249
|
+
onChange={(e) => handleDefinitionIdChange(e.target.value)}
|
|
250
|
+
placeholder="Enter Definition ID"
|
|
251
|
+
className={!definitionId || definitionId.trim() === '' ? 'p-invalid' : ''}
|
|
252
|
+
/>
|
|
253
|
+
<span style={{ color: definitionId && definitionId.trim() !== '' ? 'var(--green-500)' : 'var(--red-500)', display: 'flex', alignItems: 'center' }}>
|
|
254
|
+
<i className={definitionId && definitionId.trim() !== '' ? "pi pi-check" : "pi pi-times"}></i>
|
|
255
|
+
</span>
|
|
194
256
|
|
|
195
257
|
<h3 className="ac-form-section" style={{ marginTop: '1rem' }}>Project Information</h3>
|
|
196
258
|
{schema.project_fields.map(renderField)}
|