@adcops/autocore-react 3.3.40 → 3.3.42

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;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,CA0KtD,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,CA4MtD,CAAC"}
@@ -1 +1 @@
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[d,u]=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&&u(e.data.projects)}catch(e){}})()},[h]);useEffect(()=>{if(!e)return;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 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"})})]}),_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(d.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(_)]}):_jsx("div",{className:"ac-form-grid",style:{padding:"1.25rem"},children:_jsx("h3",{className:"ac-form-section",children:"No Test Definition Selected"})})};
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,f]=useState([]),[d,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){const t=v(e.source,t=>{o(s=>s[e.name]!==t?{...s,[e.name]:t}:s)});s.push(t)}return()=>{for(const e of s)y(e)}},[e,v,y]),useEffect(()=>{(async()=>{try{const e=await h("results.list_projects",MessageType.Request,{});e.success&&e.data&&e.data.projects&&f(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:d,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,6 +1,6 @@
1
1
  {
2
2
  "name": "@adcops/autocore-react",
3
- "version": "3.3.40",
3
+ "version": "3.3.42",
4
4
  "description": "A React component library for industrial user interfaces.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -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,36 @@ 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
62
+ useEffect(() => {
63
+ if (!schema) return;
64
+
65
+ const allFields = [...schema.project_fields, ...schema.config_fields];
66
+ const subs: any[] = [];
67
+
68
+ for (const field of allFields) {
69
+ if (field.source) {
70
+ const subId = subscribe(field.source, (newVal: any) => {
71
+ setConfig((prev: any) => {
72
+ // Only update if it actually changed to prevent infinite loops
73
+ if (prev[field.name] !== newVal) {
74
+ return { ...prev, [field.name]: newVal };
75
+ }
76
+ return prev;
77
+ });
78
+ });
79
+ subs.push(subId);
80
+ }
81
+ }
82
+
83
+ return () => {
84
+ for (const subId of subs) {
85
+ unsubscribe(subId);
86
+ }
87
+ };
88
+ }, [schema, subscribe, unsubscribe]);
58
89
 
59
90
  useEffect(() => {
60
91
  const fetchProjects = async () => {
@@ -89,8 +120,8 @@ export const TestSetupForm: React.FC<TestSetupFormProps> = ({
89
120
  const allFields = [...schema.project_fields, ...schema.config_fields];
90
121
 
91
122
  for (const field of allFields) {
92
- if (field.required && !field.source) {
93
- if (config[field.name] === undefined || config[field.name] === '') {
123
+ if (field.required) {
124
+ if (config[field.name] === undefined || config[field.name] === '' || config[field.name] === null) {
94
125
  valid = false;
95
126
  break;
96
127
  }
@@ -103,8 +134,8 @@ export const TestSetupForm: React.FC<TestSetupFormProps> = ({
103
134
  }, [config, schema, projectId, definitionId, onValidationChange]);
104
135
 
105
136
  const isFieldValid = (field: TestFieldDef) => {
106
- if (!field.required || field.source) return true;
107
- return config[field.name] !== undefined && config[field.name] !== '';
137
+ if (!field.required) return true;
138
+ return config[field.name] !== undefined && config[field.name] !== '' && config[field.name] !== null;
108
139
  };
109
140
 
110
141
  const handleProjectIdChange = (value: string | null | undefined) => {
@@ -113,36 +144,45 @@ export const TestSetupForm: React.FC<TestSetupFormProps> = ({
113
144
  setProjectId(sanitized);
114
145
  };
115
146
 
116
- const renderField = (field: TestFieldDef) => {
147
+ const handleFieldChange = async (field: TestFieldDef, val: any) => {
148
+ setConfig({...config, [field.name]: val});
117
149
  if (field.source) {
118
- return (
119
- <div key={field.name} className="ac-form-span p-inputgroup">
120
- <span className="p-inputgroup-addon">{field.name}</span>
121
- <InputText value={`Auto-fetched from ${field.source}`} disabled />
122
- {field.units && <span className="p-inputgroup-addon">{field.units}</span>}
123
- <span className="p-inputgroup-addon" style={{ color: 'var(--green-500)' }}>
124
- <i className="pi pi-check"></i>
125
- </span>
126
- </div>
127
- );
150
+ try {
151
+ await write(field.source, val);
152
+ } catch(e) {
153
+ console.error("Failed to write to source:", e);
154
+ }
128
155
  }
156
+ };
129
157
 
158
+ const renderField = (field: TestFieldDef) => {
130
159
  const valid = isFieldValid(field);
160
+ const isNum = field.type !== 'string' && field.type !== 'bool';
131
161
 
132
162
  return (
133
- <div key={field.name} className="ac-form-span p-inputgroup">
134
- <span className="p-inputgroup-addon">{field.name}</span>
135
- <InputText
136
- value={config[field.name] || ''}
137
- onChange={(e) => setConfig({...config, [field.name]: e.target.value})}
138
- placeholder={`Enter ${field.name}`}
139
- className={!valid ? 'p-invalid' : ''}
140
- />
141
- {field.units && <span className="p-inputgroup-addon">{field.units}</span>}
142
- <span className="p-inputgroup-addon" style={{ color: valid ? 'var(--green-500)' : 'var(--red-500)' }}>
163
+ <React.Fragment key={field.name}>
164
+ <span className="ac-form-label">{field.name}</span>
165
+ {isNum ? (
166
+ <ValueInput
167
+ label={undefined}
168
+ value={config[field.name] != null ? Number(config[field.name]) : null}
169
+ suffix={field.units ? ` ${field.units}` : undefined}
170
+ onValueChanged={(val) => handleFieldChange(field, val)}
171
+ className={!valid ? 'p-invalid' : ''}
172
+ />
173
+ ) : (
174
+ <TextInput
175
+ label={undefined}
176
+ value={config[field.name] != null ? String(config[field.name]) : ''}
177
+ suffix={field.units ? ` ${field.units}` : undefined}
178
+ onValueChanged={(val) => handleFieldChange(field, val)}
179
+ className={!valid ? 'p-invalid' : ''}
180
+ />
181
+ )}
182
+ <span style={{ color: valid ? 'var(--green-500)' : 'var(--red-500)', display: 'flex', alignItems: 'center' }}>
143
183
  <i className={valid ? "pi pi-check" : "pi pi-times"}></i>
144
184
  </span>
145
- </div>
185
+ </React.Fragment>
146
186
  );
147
187
  };
148
188
 
@@ -163,34 +203,30 @@ export const TestSetupForm: React.FC<TestSetupFormProps> = ({
163
203
  </span>
164
204
  </h3>
165
205
 
166
- <div className="ac-form-span p-inputgroup">
167
- <span className="p-inputgroup-addon">Project ID</span>
168
- <AutoComplete
169
- value={projectId}
170
- suggestions={filteredProjects}
171
- completeMethod={searchProjects}
172
- onChange={(e) => handleProjectIdChange(e.value)}
173
- dropdown
174
- placeholder="Enter or select Project ID"
175
- className={!projectId || projectId.trim() === '' ? 'p-invalid' : ''}
176
- />
177
- <span className="p-inputgroup-addon" style={{ color: projectId && projectId.trim() !== '' ? 'var(--green-500)' : 'var(--red-500)' }}>
178
- <i className={projectId && projectId.trim() !== '' ? "pi pi-check" : "pi pi-times"}></i>
179
- </span>
180
- </div>
206
+ <span className="ac-form-label">Project ID</span>
207
+ <AutoComplete
208
+ value={projectId}
209
+ suggestions={filteredProjects}
210
+ completeMethod={searchProjects}
211
+ onChange={(e) => handleProjectIdChange(e.value)}
212
+ dropdown
213
+ placeholder="Enter or select Project ID"
214
+ className={!projectId || projectId.trim() === '' ? 'p-invalid' : ''}
215
+ />
216
+ <span style={{ color: projectId && projectId.trim() !== '' ? 'var(--green-500)' : 'var(--red-500)', display: 'flex', alignItems: 'center' }}>
217
+ <i className={projectId && projectId.trim() !== '' ? "pi pi-check" : "pi pi-times"}></i>
218
+ </span>
181
219
 
182
- <div className="ac-form-span p-inputgroup">
183
- <span className="p-inputgroup-addon">Definition ID</span>
184
- <InputText
185
- value={definitionId}
186
- onChange={(e) => handleDefinitionIdChange(e.target.value)}
187
- placeholder="Enter Definition ID"
188
- className={!definitionId || definitionId.trim() === '' ? 'p-invalid' : ''}
189
- />
190
- <span className="p-inputgroup-addon" style={{ color: definitionId && definitionId.trim() !== '' ? 'var(--green-500)' : 'var(--red-500)' }}>
191
- <i className={definitionId && definitionId.trim() !== '' ? "pi pi-check" : "pi pi-times"}></i>
192
- </span>
193
- </div>
220
+ <span className="ac-form-label">Definition ID</span>
221
+ <InputText
222
+ value={definitionId}
223
+ onChange={(e) => handleDefinitionIdChange(e.target.value)}
224
+ placeholder="Enter Definition ID"
225
+ className={!definitionId || definitionId.trim() === '' ? 'p-invalid' : ''}
226
+ />
227
+ <span style={{ color: definitionId && definitionId.trim() !== '' ? 'var(--green-500)' : 'var(--red-500)', display: 'flex', alignItems: 'center' }}>
228
+ <i className={definitionId && definitionId.trim() !== '' ? "pi pi-check" : "pi pi-times"}></i>
229
+ </span>
194
230
 
195
231
  <h3 className="ac-form-section" style={{ marginTop: '1rem' }}>Project Information</h3>
196
232
  {schema.project_fields.map(renderField)}