@adcops/autocore-react 3.5.9 → 3.5.13

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 (76) hide show
  1. package/dist/components/index.d.ts +4 -0
  2. package/dist/components/index.d.ts.map +1 -1
  3. package/dist/components/index.js +1 -1
  4. package/dist/components/tis-editor/TisConfigEditor.css +11 -0
  5. package/dist/components/tis-editor/TisConfigEditor.d.ts.map +1 -1
  6. package/dist/components/tis-editor/TisConfigEditor.js +1 -1
  7. package/dist/components/tis-editor/editor/AuthoringContext.d.ts +37 -0
  8. package/dist/components/tis-editor/editor/AuthoringContext.d.ts.map +1 -0
  9. package/dist/components/tis-editor/editor/AuthoringContext.js +1 -0
  10. package/dist/components/tis-editor/editor/ChartViewDialog.d.ts +11 -0
  11. package/dist/components/tis-editor/editor/ChartViewDialog.d.ts.map +1 -1
  12. package/dist/components/tis-editor/editor/ChartViewDialog.js +1 -1
  13. package/dist/components/tis-editor/editor/FieldArrayEditor.d.ts.map +1 -1
  14. package/dist/components/tis-editor/editor/FieldArrayEditor.js +1 -1
  15. package/dist/components/tis-editor/editor/RawDataEditor.d.ts.map +1 -1
  16. package/dist/components/tis-editor/editor/RawDataEditor.js +1 -1
  17. package/dist/components/tis-editor/editor/TestFieldDialog.d.ts +7 -0
  18. package/dist/components/tis-editor/editor/TestFieldDialog.d.ts.map +1 -1
  19. package/dist/components/tis-editor/editor/TestFieldDialog.js +1 -1
  20. package/dist/components/tis-editor/editor/ViewsEditor.d.ts.map +1 -1
  21. package/dist/components/tis-editor/editor/ViewsEditor.js +1 -1
  22. package/dist/components/varpick/VariableInput.d.ts +41 -0
  23. package/dist/components/varpick/VariableInput.d.ts.map +1 -0
  24. package/dist/components/varpick/VariableInput.js +1 -0
  25. package/dist/components/varpick/VariablePicker.d.ts +45 -0
  26. package/dist/components/varpick/VariablePicker.d.ts.map +1 -0
  27. package/dist/components/varpick/VariablePicker.js +1 -0
  28. package/dist/components/varpick/index.d.ts +16 -0
  29. package/dist/components/varpick/index.d.ts.map +1 -0
  30. package/dist/components/varpick/index.js +1 -0
  31. package/dist/components/varpick/tisCatalogs.d.ts +85 -0
  32. package/dist/components/varpick/tisCatalogs.d.ts.map +1 -0
  33. package/dist/components/varpick/tisCatalogs.js +1 -0
  34. package/dist/components/varpick/varpick.css +167 -0
  35. package/dist/core/AutoCoreTagContext.d.ts.map +1 -1
  36. package/dist/core/AutoCoreTagContext.js +1 -1
  37. package/dist/core/AutoCoreTagTypes.d.ts +13 -0
  38. package/dist/core/AutoCoreTagTypes.d.ts.map +1 -1
  39. package/dist/hooks/index.d.ts +4 -0
  40. package/dist/hooks/index.d.ts.map +1 -1
  41. package/dist/hooks/index.js +1 -1
  42. package/dist/hooks/useGmVariables.d.ts +57 -0
  43. package/dist/hooks/useGmVariables.d.ts.map +1 -0
  44. package/dist/hooks/useGmVariables.js +1 -0
  45. package/dist/hooks/useSequenceProducers.d.ts +38 -0
  46. package/dist/hooks/useSequenceProducers.d.ts.map +1 -0
  47. package/dist/hooks/useSequenceProducers.js +1 -0
  48. package/package.json +5 -2
  49. package/src/components/index.ts +17 -0
  50. package/src/components/tis-editor/TisConfigEditor.css +11 -0
  51. package/src/components/tis-editor/TisConfigEditor.tsx +31 -0
  52. package/src/components/tis-editor/editor/AuthoringContext.tsx +43 -0
  53. package/src/components/tis-editor/editor/ChartViewDialog.tsx +24 -7
  54. package/src/components/tis-editor/editor/FieldArrayEditor.tsx +1 -0
  55. package/src/components/tis-editor/editor/RawDataEditor.tsx +7 -2
  56. package/src/components/tis-editor/editor/TestFieldDialog.tsx +66 -12
  57. package/src/components/tis-editor/editor/ViewsEditor.tsx +25 -0
  58. package/src/components/varpick/VariableInput.tsx +126 -0
  59. package/src/components/varpick/VariablePicker.tsx +168 -0
  60. package/src/components/varpick/index.ts +22 -0
  61. package/src/components/varpick/tisCatalogs.ts +235 -0
  62. package/src/components/varpick/varpick.css +167 -0
  63. package/src/core/AutoCoreTagContext.tsx +3 -1
  64. package/src/core/AutoCoreTagTypes.ts +14 -0
  65. package/src/hooks/index.ts +11 -0
  66. package/src/hooks/useGmVariables.ts +142 -0
  67. package/src/hooks/useSequenceProducers.ts +104 -0
  68. package/tools/tests/dist/TestFieldDialog-C4mKVh7q.js +32817 -0
  69. package/tools/tests/dist/autocore-react.css +257 -0
  70. package/tools/tests/dist/tis-editor.entry.js +8431 -40567
  71. package/tools/tests/dist/varpick.entry.js +113 -0
  72. package/tools/tests/live-server.probe.mjs +172 -0
  73. package/tools/tests/varpick.entry.tsx +81 -0
  74. package/tools/tests/varpick.test.mjs +208 -0
  75. package/tools/tests/vite.config.mjs +7 -2
  76. package/tools/tests/dist/tis-editor.entry.css +0 -90
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tisCatalogs.d.ts","sourceRoot":"","sources":["../../../src/components/varpick/tisCatalogs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAEH,KAAK,OAAO,EAEZ,KAAK,UAAU,EAElB,MAAM,0BAA0B,CAAC;AAElC,MAAM,WAAW,iBAAiB;IAC9B,0DAA0D;IAC1D,SAAS,EAAE,UAAU,EAAE,CAAC;IACxB,yEAAyE;IACzE,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACnD,yCAAyC;IACzC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;CAClD;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAOnE;AAED,mEAAmE;AACnE,wBAAgB,YAAY,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAM5D;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,kBAAkB,CAC9B,GAAG,EAAE,iBAAiB,EACtB,IAAI,EAAE;IACF,6EAA6E;IAC7E,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB,GACF,OAAO,CA0CT;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IACpC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,4DAA4D;IAC5D,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,OAAO,CA2CV;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAqC7D"}
@@ -0,0 +1 @@
1
+ import{gmCatalog}from"@adcops/autocore-varpick";export function configSourceCatalog(e){return gmCatalog(e.variables,{spelling:"fqdn",writableOnly:!0,unitFor:e.unitFor,liveFor:e.liveFor})}export function boundCatalog(e){return gmCatalog(e.variables,{spelling:"token",unitFor:e.unitFor,liveFor:e.liveFor})}export function cycleSourceCatalog(e,t){const n=[],i=t.producedNames??[];if(i.length>0){const e=i.map(e=>({id:`seq:${e}`,insert:"",name:e,kind:"column",description:e===t.fieldName?"The sequence stores this name every cycle, and it matches this column. Nothing else is needed — leave Source empty.":`The sequence stores this name every cycle. It only lands in this column if the column is called "${e}" too.`,note:e===t.fieldName?void 0:`Rename this field to "${e}", or the value is recorded with no column to show it in.`,keywords:["sequence","store_value"]}));n.push({id:"sequence",title:"Recorded by the sequence",hint:"Matched by NAME, not by binding. Picking one clears Source — that is correct, and is how gen4_ac records every column.",entries:e})}return n.push(...gmCatalog(e.variables,{spelling:"fqdn",unitFor:e.unitFor,liveFor:e.liveFor})),n}export function chartFieldCatalog(e){const t=[],n=(e,t)=>e.map(e=>({id:`${t}:${e}`,insert:e,name:e,kind:"column"})),i=e.rawColumns??[],o=e.cycleFields??[],r=e.resultsFields??[],s="raw_trace"===e.viewType,l={id:"raw",title:"Raw trace columns",hint:"Per-cycle trace columns declared under Raw Data.",entries:n(i,"raw")},c={id:"cycle",title:"Cycle Data columns",hint:"One value per cycle.",entries:n(o,"cycle")};return s?t.push(l,c):t.push(c,l),t.push({id:"results",title:"Results",hint:"One value per test.",entries:n(r,"result")}),t.push({id:"test",title:"Test setup values",hint:"Entered once per test, so they plot as a constant across cycles.",entries:n(e.testFields??[],"test")}),t.filter(e=>e.entries.length>0)}export function rawSourceCatalog(e){const t=[{id:"builtin",title:"Built-in",entries:[{id:"src:time",insert:"time",name:"time",kind:"column",description:"Sample timestamp, seconds from the start of the cycle."},{id:"src:derived",insert:"derived",name:"derived",kind:"column",description:"Computed from the other columns by this column’s Formula."}]}];return e&&e.length>0&&t.push({id:"channels",title:"DAQ channels",hint:"Published by the acquisition module.",entries:e.map(e=>({id:`chan:${e}`,insert:e,name:e,kind:"column"}))}),t}
@@ -0,0 +1,167 @@
1
+ /*
2
+ * Variable picker.
3
+ *
4
+ * Colours come from the PrimeReact theme's variables so the dialog matches
5
+ * whatever theme the machine is running, light or dark. Every value has a
6
+ * literal fallback: an un-themed host (the playground, a test harness) must
7
+ * still render legible text rather than black on black.
8
+ */
9
+
10
+ .ac-varpick__input {
11
+ display: flex;
12
+ align-items: stretch;
13
+ gap: 0;
14
+ min-width: 0;
15
+ }
16
+
17
+ .ac-varpick__input .p-inputtext {
18
+ flex: 1 1 auto;
19
+ min-width: 0;
20
+ border-top-right-radius: 0;
21
+ border-bottom-right-radius: 0;
22
+ }
23
+
24
+ /* Sized to the full control height, not shrunk to fit: these screens are
25
+ * touchscreens, and a button an operator has to aim at is one they mis-tap. */
26
+ .ac-varpick__input > .p-button {
27
+ flex: 0 0 auto;
28
+ border-top-left-radius: 0;
29
+ border-bottom-left-radius: 0;
30
+ margin-left: -1px;
31
+ }
32
+
33
+ .ac-varpick__hint {
34
+ font-size: 0.8125rem;
35
+ color: var(--text-color-secondary, #6b7280);
36
+ margin-bottom: 0.75rem;
37
+ line-height: 1.4;
38
+ }
39
+
40
+ .ac-varpick__search { width: 100%; }
41
+
42
+ .ac-varpick__empty {
43
+ padding: 1.5rem 0.25rem;
44
+ color: var(--text-color-secondary, #6b7280);
45
+ font-size: 0.875rem;
46
+ }
47
+
48
+ .ac-varpick__list {
49
+ display: flex;
50
+ flex-direction: column;
51
+ gap: 1rem;
52
+ margin-top: 0.75rem;
53
+ /* Bounded so the search box and the footer stay put while the list moves. */
54
+ max-height: 55vh;
55
+ overflow-y: auto;
56
+ }
57
+
58
+ .ac-varpick__group { display: flex; flex-direction: column; gap: 2px; }
59
+
60
+ .ac-varpick__grouphead {
61
+ display: flex;
62
+ flex-wrap: wrap;
63
+ align-items: baseline;
64
+ gap: 0.5rem;
65
+ padding-bottom: 0.25rem;
66
+ margin-bottom: 0.25rem;
67
+ border-bottom: 1px solid var(--surface-border, rgba(127, 127, 127, 0.25));
68
+ position: sticky;
69
+ top: 0;
70
+ background: var(--surface-overlay, #ffffff);
71
+ z-index: 1;
72
+ }
73
+
74
+ .ac-varpick__grouptitle {
75
+ font-size: 0.75rem;
76
+ font-weight: 700;
77
+ letter-spacing: 0.04em;
78
+ text-transform: uppercase;
79
+ color: var(--text-color-secondary, #6b7280);
80
+ }
81
+
82
+ .ac-varpick__grouphint {
83
+ font-size: 0.75rem;
84
+ color: var(--text-color-secondary, #8b95a1);
85
+ }
86
+
87
+ /*
88
+ * Two lines by design — the identifier, then what it MEANS. A one-line list of
89
+ * identifiers is the problem this dialog exists to solve, so the description is
90
+ * never truncated and never hidden behind a hover: there is no hover on a
91
+ * touchscreen.
92
+ */
93
+ .ac-varpick__row {
94
+ display: flex;
95
+ flex-direction: column;
96
+ align-items: flex-start;
97
+ gap: 2px;
98
+ width: 100%;
99
+ text-align: left;
100
+ min-height: 2.25rem;
101
+ padding: 0.375rem 0.75rem;
102
+ border: 1px solid transparent;
103
+ border-radius: 3px;
104
+ background: transparent;
105
+ color: var(--text-color, #111827);
106
+ font: inherit;
107
+ cursor: pointer;
108
+ }
109
+
110
+ .ac-varpick__row:hover { background: var(--surface-hover, rgba(127, 127, 127, 0.08)); }
111
+
112
+ .ac-varpick__row:focus-visible {
113
+ outline: 2px solid var(--primary-color, #2563eb);
114
+ outline-offset: -2px;
115
+ }
116
+
117
+ .ac-varpick__row--on {
118
+ background: var(--highlight-bg, rgba(37, 99, 235, 0.14));
119
+ border-color: var(--primary-color, #2563eb);
120
+ }
121
+
122
+ .ac-varpick__row--off { opacity: 0.55; cursor: default; }
123
+
124
+ .ac-varpick__line {
125
+ display: flex;
126
+ flex-wrap: wrap;
127
+ align-items: baseline;
128
+ gap: 0.5rem;
129
+ min-width: 0;
130
+ }
131
+
132
+ .ac-varpick__name {
133
+ font-family: var(--font-family-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
134
+ font-weight: 600;
135
+ }
136
+
137
+ .ac-varpick__label { font-size: 0.875rem; }
138
+
139
+ .ac-varpick__chip {
140
+ font-size: 0.75rem;
141
+ padding: 0 6px;
142
+ border-radius: 999px;
143
+ background: var(--surface-100, rgba(127, 127, 127, 0.12));
144
+ border: 1px solid var(--surface-border, rgba(127, 127, 127, 0.25));
145
+ color: var(--text-color-secondary, #6b7280);
146
+ /* A unit symbol's case is meaningful: "mm/s", "N", "MPa". */
147
+ text-transform: none;
148
+ }
149
+
150
+ /* The current reading. Nothing turns an unfamiliar name into an obvious one
151
+ * faster than seeing what it says right now. */
152
+ .ac-varpick__live {
153
+ font-family: var(--font-family-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
154
+ font-size: 0.75rem;
155
+ color: var(--green-600, #15803d);
156
+ }
157
+
158
+ .ac-varpick__desc {
159
+ font-size: 0.8125rem;
160
+ color: var(--text-color-secondary, #6b7280);
161
+ line-height: 1.35;
162
+ }
163
+
164
+ .ac-varpick__why { font-size: 0.8125rem; color: var(--orange-600, #b45309); }
165
+ .ac-varpick__note { font-size: 0.8125rem; color: var(--blue-600, #0369a1); }
166
+
167
+ .ac-varpick__foot { display: flex; justify-content: flex-end; gap: 0.5rem; }
@@ -1 +1 @@
1
- {"version":3,"file":"AutoCoreTagContext.d.ts","sourceRoot":"","sources":["../../src/core/AutoCoreTagContext.tsx"],"names":[],"mappings":"AAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAEH,OAAO,KAAK,EAAE,EAQV,KAAK,SAAS,EACjB,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EACR,gBAAgB,EAChB,SAAS,EACT,WAAW,EAGd,MAAM,oBAAoB,CAAC;AAK5B;;;GAGG;AACH,KAAK,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE3C;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,kBAAkB,8CAW7B,CAAC;AAsBH;;;;GAIG;AAIH;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC;IACvC,QAAQ,EAAE,SAAS,CAAC;IACpB,IAAI,EAAE,SAAS,SAAS,EAAE,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACrC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B,CA6uBA,CAAC"}
1
+ {"version":3,"file":"AutoCoreTagContext.d.ts","sourceRoot":"","sources":["../../src/core/AutoCoreTagContext.tsx"],"names":[],"mappings":"AAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAEH,OAAO,KAAK,EAAE,EAQV,KAAK,SAAS,EACjB,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EACR,gBAAgB,EAChB,SAAS,EACT,WAAW,EAGd,MAAM,oBAAoB,CAAC;AAK5B;;;GAGG;AACH,KAAK,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE3C;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,kBAAkB,8CAY7B,CAAC;AAsBH;;;;GAIG;AAIH;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC;IACvC,QAAQ,EAAE,SAAS,CAAC;IACpB,IAAI,EAAE,SAAS,SAAS,EAAE,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACrC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B,CA8uBA,CAAC"}
@@ -1 +1 @@
1
- import{jsx as _jsx}from"react/jsx-runtime";import React,{useRef,createContext,useCallback,useContext,useEffect,useMemo,useState}from"react";import{EventEmitterContext}from"./EventEmitterContext";import{MessageType}from"../hub/CommandMessage";import{formatScaled}from"./formatScaled";export const AutoCoreTagContext=createContext({values:{},rawValues:{},isLoading:!0,write:async()=>{},tap:async()=>{},press:async()=>{},release:async()=>{},scales:{},updateScale:async()=>{},findTagByFqdn:()=>{}});const sleep=e=>new Promise(t=>setTimeout(t,e));export const AutoCoreTagProvider=({children:e,tags:t,scales:a,eagerRead:s=!0,flushIntervalMs:n=33})=>{const c=useRef(!1),r=useMemo(()=>({}),[]),o=a??r,{invoke:u,read:l,write:i,serverSubscribe:f,isConnected:m,subscribe:y,unsubscribe:b}=useContext(EventEmitterContext),[d,p]=useState(()=>{const e={};for(const a of t)void 0!==a.initialValue&&(e[a.tagName]=a.initialValue);return e}),[g,v]=useState({}),[C,N]=useState(o),h=useRef(C),w=useRef(d);useEffect(()=>{h.current=C},[C]),useEffect(()=>{w.current=d},[d]);const[T,M]=useState(!0),[k,S]=useState(null),[E,q]=useState(null),x=useRef(null),R=useRef(null);useEffect(()=>{x.current=E},[E]),useEffect(()=>{R.current=k},[k]);const j=useCallback((e,t)=>{const a={};for(const[s,n]of Object.entries(e.scales??{})){const e=n?.[t];e&&"number"==typeof e.scalar&&(a[s]={name:s,scale:e.scalar,label:e.label??"",offset:"absolute"===n?.kind?e.offset??0:0,precision:e.precision,precisionMode:e.precision_mode})}return a},[]),_=useCallback((e,a)=>{S(e),q(a);const s=j(e,a);h.current=s,N(s),v(e=>{const a={...e};for(const e of t){const t=e.quantity??e.scale;if(!t||!s[t])continue;const n=w.current[e.tagName];if("number"!=typeof n)continue;const c=s[t];a[e.tagName]=n*c.scale+(c.offset??0)}return a})},[j,t]),$=useCallback((e,t)=>{const{valueType:a,codec:s}=e,n=e.quantity??e.scale;if("number"===a&&"number"==typeof t&&n){const e=h.current[n];return t*(e?.scale??1)+(e?.offset??0)}if("json"===a&&s?.fromServer)try{return s.fromServer(t)}catch{}return t},[]),O=useCallback((e,t)=>{const{valueType:a,codec:s}=e,n=e.quantity??e.scale;if("json"===a&&s?.toServer)try{t=s.toServer(t)}catch{}if("number"===a&&"number"==typeof t&&n){const e=h.current[n],a=e?.scale??1;return(t-(e?.offset??0))/a}return t},[]),V=useCallback(e=>{const a=t.filter(t=>(t.quantity??t.scale)===e);a.length&&v(e=>{const t={...e};for(const e of a){const a=w.current[e.tagName];if("number"!=typeof a)continue;const s=$(e,a);t[e.tagName]!==s&&(t[e.tagName]=s)}return t})},[t,$]),A=useRef(new Map),P=useRef(new Map),B=useRef(null),F=useCallback(()=>{B.current=null;const e=A.current,t=P.current;0===e.size&&0===t.size||(A.current=new Map,P.current=new Map,p(t=>{let a=t;return e.forEach((e,s)=>{a[s]!==e&&(a===t&&(a={...t}),a[s]=e)}),a}),v(e=>{let a=e;return t.forEach((t,s)=>{a[s]!==t&&(a===e&&(a={...e}),a[s]=t)}),a}))},[]),U=useCallback((e,t)=>{const a=$(e,t);if(n<=0)return p(a=>a[e.tagName]===t?a:{...a,[e.tagName]:t}),void v(t=>t[e.tagName]===a?t:{...t,[e.tagName]:a});A.current.set(e.tagName,t),P.current.set(e.tagName,a),null===B.current&&(B.current=setTimeout(F,n))},[$,n,F]);useEffect(()=>()=>{null!==B.current&&(clearTimeout(B.current),B.current=null),A.current=new Map,P.current=new Map},[]);const z=useCallback(async(e,t,a)=>{const s=a?.concurrency??4,n=a?.minDelayMs??20,c=a?.jitterMs??40;let r=0;const o=Array.from({length:s},()=>(async()=>{for(;;){const a=r++;if(a>=t.length)return;const s=t[a];try{let t=!1;try{await u(s.fqdn,MessageType.Request,{action:"refresh"}),t=!0}catch{}if(!t){const t="GNV"===e.toUpperCase()?{group:"ux"}:{};try{const e=await l(s.fqdn,t);e?.success&&U(s,e.data)}catch(e){}}}catch(e){}finally{const e=Math.floor(Math.random()*c);await sleep(n+e)}}})());await Promise.all(o)},[u,l,U]),L=useCallback(async()=>{try{const e=await u("system.get_units",MessageType.Request,{}),t=e?.data??e,a=t?.units;if(!a||!a.scales)return;const s=t?.active_system??a.default_system;_(a,s)}catch(e){}},[u,_]),D=useCallback(async e=>{await u("system.set_unit_system",MessageType.Request,{system:e});k&&_(k,e)},[u,k,_]);useEffect(()=>{if(!m)return;const e=y("system.unit_system_changed",e=>{const t=e?.value?.system??e?.system;if(!t)return;const a=R.current;a&&t!==x.current&&_(a,t)});return()=>{b(e)}},[m,y,b,_]);const G=useCallback(async()=>{for(const[e,t]of Object.entries(o)){if(!t.serverTag)continue;const{domain:a,symbolName:s}=t.serverTag;try{const t=await l(`${a}.${s}`,{group:"ux"});if(t.data&&(t.success??1)&&(t.valid??1)){const a=JSON.parse(t.data);if(a&&"number"==typeof a.scale){const{scale:t,label:s}=a;N(a=>({...a,[e]:{...a[e],scale:t,label:s??a[e]?.label??"---"}})),V(e)}}}catch{}}},[l,o,V]);useEffect(()=>{let e=!0;const a=[],n=async()=>{if(e&&!c.current){c.current=!0;try{await(async()=>{try{await L(),await G();for(const n of t){await f(n.tagName,n.fqdn,n.subscriptionOptions);const t=y(n.tagName,t=>{e&&U(n,t)});a.push(t),s&&l(n.fqdn).then(t=>{e&&t?.success&&U(n,t.data)}).catch(e=>{})}}finally{e&&setTimeout(()=>e&&M(!1),100)}})()}finally{e&&setTimeout(()=>e&&M(!1),100)}}};if(m())n();else{const e=y("HUB/connected",()=>{b(e),n()});a.push(e)}return()=>{e=!1,a.forEach(b),c.current=!1}},[y,b,m,u,f,s,t,G,z,U]);const H=useMemo(()=>Object.entries(o).filter(([,e])=>e.serverTag).map(([e,t])=>({scaleName:e,domain:t.serverTag.domain,symbolName:t.serverTag.symbolName})),[o]);useEffect(()=>{let e=!0;const t=[];for(const{scaleName:a,domain:s,symbolName:n}of H){const c=y(`${s}.${n}`,t=>{if(!e)return;const s=t?.value;if(s&&"object"==typeof s&&"number"==typeof s.scale){const{scale:e,label:t}=s;N(s=>({...s,[a]:{...s[a],scale:e,label:t??s[a]?.label??"---"}})),V(a)}});t.push(c)}return()=>{e=!1,t.forEach(b)}},[y,b,H,V]);const I=useCallback(async(e,a)=>{const s=t.find(t=>t.tagName===e);if(!s)return;const n=O(s,a);await i(s.fqdn,n)},[t,i,O]),J=useCallback(async e=>{const a=t.find(t=>t.tagName===e);a&&"boolean"===a.valueType&&(i(a.fqdn,!0).catch(e=>{}),await sleep(300),i(a.fqdn,!1).catch(e=>{}))},[t,i]),Q=useCallback(async e=>{const a=t.find(t=>t.tagName===e);a&&"boolean"===a.valueType&&await i(a.fqdn,!0)},[t,i]),K=useCallback(async e=>{const a=t.find(t=>t.tagName===e);a&&"boolean"===a.valueType&&await i(a.fqdn,!1)},[t,i]),W=useCallback(async(e,t,a)=>{const s=C[e];if(s){if(s.serverTag){const n=`${s.serverTag.domain}.${s.serverTag.symbolName}`;await i(n,{name:e,scale:t,label:a})}N(s=>({...s,[e]:{...s[e],scale:t,label:a}})),V(e)}},[C,i,V]);useEffect(()=>{v(e=>{const a={...e};for(const e of t){const t=w.current[e.tagName];if(void 0===t)continue;const s=$(e,t);a[e.tagName]!==s&&(a[e.tagName]=s)}return a})},[t,$,C]);const X=useMemo(()=>{const e=new Map;for(const a of t)e.set(a.fqdn,a);return e},[t]),Y=useCallback(e=>X.get(e),[X]),Z=useCallback((e,t)=>{const a=C[e];return a&&Number.isFinite(t)?formatScaled(t*a.scale+(a.offset??0),a):String(t)},[C]),ee=useMemo(()=>({values:g,rawValues:d,isLoading:T,write:I,tap:J,press:Q,release:K,scales:C,updateScale:W,findTagByFqdn:Y,units:k,activeSystem:E,setUnitSystem:D,formatQuantity:Z}),[g,d,T,I,J,Q,K,C,W,Y,k,E,D,Z]);return _jsx(AutoCoreTagContext.Provider,{value:ee,children:e})};
1
+ import{jsx as _jsx}from"react/jsx-runtime";import React,{useRef,createContext,useCallback,useContext,useEffect,useMemo,useState}from"react";import{EventEmitterContext}from"./EventEmitterContext";import{MessageType}from"../hub/CommandMessage";import{formatScaled}from"./formatScaled";export const AutoCoreTagContext=createContext({values:{},rawValues:{},isLoading:!0,write:async()=>{},tap:async()=>{},press:async()=>{},release:async()=>{},scales:{},updateScale:async()=>{},findTagByFqdn:()=>{},tags:[]});const sleep=e=>new Promise(t=>setTimeout(t,e));export const AutoCoreTagProvider=({children:e,tags:t,scales:a,eagerRead:s=!0,flushIntervalMs:n=33})=>{const c=useRef(!1),r=useMemo(()=>({}),[]),o=a??r,{invoke:u,read:l,write:i,serverSubscribe:f,isConnected:m,subscribe:y,unsubscribe:b}=useContext(EventEmitterContext),[d,p]=useState(()=>{const e={};for(const a of t)void 0!==a.initialValue&&(e[a.tagName]=a.initialValue);return e}),[g,v]=useState({}),[C,N]=useState(o),h=useRef(C),w=useRef(d);useEffect(()=>{h.current=C},[C]),useEffect(()=>{w.current=d},[d]);const[T,M]=useState(!0),[k,S]=useState(null),[E,q]=useState(null),x=useRef(null),R=useRef(null);useEffect(()=>{x.current=E},[E]),useEffect(()=>{R.current=k},[k]);const j=useCallback((e,t)=>{const a={};for(const[s,n]of Object.entries(e.scales??{})){const e=n?.[t];e&&"number"==typeof e.scalar&&(a[s]={name:s,scale:e.scalar,label:e.label??"",offset:"absolute"===n?.kind?e.offset??0:0,precision:e.precision,precisionMode:e.precision_mode})}return a},[]),_=useCallback((e,a)=>{S(e),q(a);const s=j(e,a);h.current=s,N(s),v(e=>{const a={...e};for(const e of t){const t=e.quantity??e.scale;if(!t||!s[t])continue;const n=w.current[e.tagName];if("number"!=typeof n)continue;const c=s[t];a[e.tagName]=n*c.scale+(c.offset??0)}return a})},[j,t]),$=useCallback((e,t)=>{const{valueType:a,codec:s}=e,n=e.quantity??e.scale;if("number"===a&&"number"==typeof t&&n){const e=h.current[n];return t*(e?.scale??1)+(e?.offset??0)}if("json"===a&&s?.fromServer)try{return s.fromServer(t)}catch{}return t},[]),O=useCallback((e,t)=>{const{valueType:a,codec:s}=e,n=e.quantity??e.scale;if("json"===a&&s?.toServer)try{t=s.toServer(t)}catch{}if("number"===a&&"number"==typeof t&&n){const e=h.current[n],a=e?.scale??1;return(t-(e?.offset??0))/a}return t},[]),V=useCallback(e=>{const a=t.filter(t=>(t.quantity??t.scale)===e);a.length&&v(e=>{const t={...e};for(const e of a){const a=w.current[e.tagName];if("number"!=typeof a)continue;const s=$(e,a);t[e.tagName]!==s&&(t[e.tagName]=s)}return t})},[t,$]),A=useRef(new Map),P=useRef(new Map),B=useRef(null),F=useCallback(()=>{B.current=null;const e=A.current,t=P.current;0===e.size&&0===t.size||(A.current=new Map,P.current=new Map,p(t=>{let a=t;return e.forEach((e,s)=>{a[s]!==e&&(a===t&&(a={...t}),a[s]=e)}),a}),v(e=>{let a=e;return t.forEach((t,s)=>{a[s]!==t&&(a===e&&(a={...e}),a[s]=t)}),a}))},[]),U=useCallback((e,t)=>{const a=$(e,t);if(n<=0)return p(a=>a[e.tagName]===t?a:{...a,[e.tagName]:t}),void v(t=>t[e.tagName]===a?t:{...t,[e.tagName]:a});A.current.set(e.tagName,t),P.current.set(e.tagName,a),null===B.current&&(B.current=setTimeout(F,n))},[$,n,F]);useEffect(()=>()=>{null!==B.current&&(clearTimeout(B.current),B.current=null),A.current=new Map,P.current=new Map},[]);const z=useCallback(async(e,t,a)=>{const s=a?.concurrency??4,n=a?.minDelayMs??20,c=a?.jitterMs??40;let r=0;const o=Array.from({length:s},()=>(async()=>{for(;;){const a=r++;if(a>=t.length)return;const s=t[a];try{let t=!1;try{await u(s.fqdn,MessageType.Request,{action:"refresh"}),t=!0}catch{}if(!t){const t="GNV"===e.toUpperCase()?{group:"ux"}:{};try{const e=await l(s.fqdn,t);e?.success&&U(s,e.data)}catch(e){}}}catch(e){}finally{const e=Math.floor(Math.random()*c);await sleep(n+e)}}})());await Promise.all(o)},[u,l,U]),L=useCallback(async()=>{try{const e=await u("system.get_units",MessageType.Request,{}),t=e?.data??e,a=t?.units;if(!a||!a.scales)return;const s=t?.active_system??a.default_system;_(a,s)}catch(e){}},[u,_]),D=useCallback(async e=>{await u("system.set_unit_system",MessageType.Request,{system:e});k&&_(k,e)},[u,k,_]);useEffect(()=>{if(!m)return;const e=y("system.unit_system_changed",e=>{const t=e?.value?.system??e?.system;if(!t)return;const a=R.current;a&&t!==x.current&&_(a,t)});return()=>{b(e)}},[m,y,b,_]);const G=useCallback(async()=>{for(const[e,t]of Object.entries(o)){if(!t.serverTag)continue;const{domain:a,symbolName:s}=t.serverTag;try{const t=await l(`${a}.${s}`,{group:"ux"});if(t.data&&(t.success??1)&&(t.valid??1)){const a=JSON.parse(t.data);if(a&&"number"==typeof a.scale){const{scale:t,label:s}=a;N(a=>({...a,[e]:{...a[e],scale:t,label:s??a[e]?.label??"---"}})),V(e)}}}catch{}}},[l,o,V]);useEffect(()=>{let e=!0;const a=[],n=async()=>{if(e&&!c.current){c.current=!0;try{await(async()=>{try{await L(),await G();for(const n of t){await f(n.tagName,n.fqdn,n.subscriptionOptions);const t=y(n.tagName,t=>{e&&U(n,t)});a.push(t),s&&l(n.fqdn).then(t=>{e&&t?.success&&U(n,t.data)}).catch(e=>{})}}finally{e&&setTimeout(()=>e&&M(!1),100)}})()}finally{e&&setTimeout(()=>e&&M(!1),100)}}};if(m())n();else{const e=y("HUB/connected",()=>{b(e),n()});a.push(e)}return()=>{e=!1,a.forEach(b),c.current=!1}},[y,b,m,u,f,s,t,G,z,U]);const H=useMemo(()=>Object.entries(o).filter(([,e])=>e.serverTag).map(([e,t])=>({scaleName:e,domain:t.serverTag.domain,symbolName:t.serverTag.symbolName})),[o]);useEffect(()=>{let e=!0;const t=[];for(const{scaleName:a,domain:s,symbolName:n}of H){const c=y(`${s}.${n}`,t=>{if(!e)return;const s=t?.value;if(s&&"object"==typeof s&&"number"==typeof s.scale){const{scale:e,label:t}=s;N(s=>({...s,[a]:{...s[a],scale:e,label:t??s[a]?.label??"---"}})),V(a)}});t.push(c)}return()=>{e=!1,t.forEach(b)}},[y,b,H,V]);const I=useCallback(async(e,a)=>{const s=t.find(t=>t.tagName===e);if(!s)return;const n=O(s,a);await i(s.fqdn,n)},[t,i,O]),J=useCallback(async e=>{const a=t.find(t=>t.tagName===e);a&&"boolean"===a.valueType&&(i(a.fqdn,!0).catch(e=>{}),await sleep(300),i(a.fqdn,!1).catch(e=>{}))},[t,i]),Q=useCallback(async e=>{const a=t.find(t=>t.tagName===e);a&&"boolean"===a.valueType&&await i(a.fqdn,!0)},[t,i]),K=useCallback(async e=>{const a=t.find(t=>t.tagName===e);a&&"boolean"===a.valueType&&await i(a.fqdn,!1)},[t,i]),W=useCallback(async(e,t,a)=>{const s=C[e];if(s){if(s.serverTag){const n=`${s.serverTag.domain}.${s.serverTag.symbolName}`;await i(n,{name:e,scale:t,label:a})}N(s=>({...s,[e]:{...s[e],scale:t,label:a}})),V(e)}},[C,i,V]);useEffect(()=>{v(e=>{const a={...e};for(const e of t){const t=w.current[e.tagName];if(void 0===t)continue;const s=$(e,t);a[e.tagName]!==s&&(a[e.tagName]=s)}return a})},[t,$,C]);const X=useMemo(()=>{const e=new Map;for(const a of t)e.set(a.fqdn,a);return e},[t]),Y=useCallback(e=>X.get(e),[X]),Z=useCallback((e,t)=>{const a=C[e];return a&&Number.isFinite(t)?formatScaled(t*a.scale+(a.offset??0),a):String(t)},[C]),ee=useMemo(()=>({values:g,rawValues:d,isLoading:T,write:I,tap:J,press:Q,release:K,scales:C,updateScale:W,findTagByFqdn:Y,tags:t,units:k,activeSystem:E,setUnitSystem:D,formatQuantity:Z}),[g,d,T,I,J,Q,K,C,W,Y,t,k,E,D,Z]);return _jsx(AutoCoreTagContext.Provider,{value:ee,children:e})};
@@ -370,6 +370,19 @@ export interface BaseContextValue<VMap extends Record<string, any>> {
370
370
  * if no tag is registered for the given FQDN.
371
371
  */
372
372
  findTagByFqdn: (fqdn: string) => TagConfig | undefined;
373
+ /**
374
+ * The tag spec this provider was built with.
375
+ *
376
+ * Exposed so a consumer can enumerate what the HMI knows about rather than
377
+ * having every host thread `acTagSpec` down by hand. The variable picker
378
+ * uses it as its fallback catalog when the server is an older build with no
379
+ * `gm.get_variables` — names and types, no descriptions.
380
+ *
381
+ * It is NOT the machine's full variable table: `acctl codegen-tags` emits
382
+ * only variables marked `ux: true`. Treat it as a floor, never as the
383
+ * authoritative list.
384
+ */
385
+ tags: readonly TagConfig[];
373
386
  }
374
387
  export {};
375
388
  //# sourceMappingURL=AutoCoreTagTypes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AutoCoreTagTypes.d.ts","sourceRoot":"","sources":["../../src/core/AutoCoreTagTypes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AutoCoreTagTypes.d.ts","sourceRoot":"","sources":["../../src/core/AutoCoreTagTypes.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,8 @@
1
1
  export { useAdsRegisterSymbols, useAdsWriteValue, useAdsTapValue } from "./adsHooks";
2
2
  export { useScaledValue, kMillimeters2Inches } from './useScaledValue';
3
3
  export * from './useServeletData';
4
+ export { useGmVariables } from './useGmVariables';
5
+ export type { UseGmVariablesResult, UseGmVariablesOptions, GmIpcInvoker } from './useGmVariables';
6
+ export { useSequenceProducers, collectStoredNames } from './useSequenceProducers';
7
+ export type { UseSequenceProducersResult, UseSequenceProducersOptions } from './useSequenceProducers';
4
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAC,qBAAqB,EAAE,gBAAgB,EAAE,cAAc,EAAC,MAAM,YAAY,CAAC;AACnF,OAAO,EAAC,cAAc,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACtE,cAAc,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAC,qBAAqB,EAAE,gBAAgB,EAAE,cAAc,EAAC,MAAM,YAAY,CAAC;AACnF,OAAO,EAAC,cAAc,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACtE,cAAc,mBAAmB,CAAC;AAKlC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAIlG,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAClF,YAAY,EAAE,0BAA0B,EAAE,2BAA2B,EAAE,MAAM,wBAAwB,CAAC"}
@@ -1 +1 @@
1
- export{useAdsRegisterSymbols,useAdsWriteValue,useAdsTapValue}from"./adsHooks";export{useScaledValue,kMillimeters2Inches}from"./useScaledValue";export*from"./useServeletData";
1
+ export{useAdsRegisterSymbols,useAdsWriteValue,useAdsTapValue}from"./adsHooks";export{useScaledValue,kMillimeters2Inches}from"./useScaledValue";export*from"./useServeletData";export{useGmVariables}from"./useGmVariables";export{useSequenceProducers,collectStoredNames}from"./useSequenceProducers";
@@ -0,0 +1,57 @@
1
+ /**
2
+ * useGmVariables — the machine's GM variable table, for the variable picker.
3
+ *
4
+ * Reads `gm.get_variables`: `gm.get_catalog` with the metadata attached — type,
5
+ * description, quantity, and whether a UI may write the variable. Everything it
6
+ * returns already lives in project.json; the verb exists because a catalog of
7
+ * bare FQDN strings cannot tell an author what a name means, which is why every
8
+ * field that asks for one has been a text box.
9
+ *
10
+ * ## Degrading on an older server
11
+ *
12
+ * `gm.get_variables` was added alongside the picker, so a machine running an
13
+ * older `autocore_server` answers with an error. That is not a failure worth
14
+ * showing an operator: the picker still works, it just lists names without
15
+ * descriptions. So the hook falls back to the generated tag spec the HMI
16
+ * already has (`acTagSpec`), which carries FQDN, type and quantity but no prose,
17
+ * and reports the degradation through `partial` rather than through `error`.
18
+ *
19
+ * The fallback covers strictly less: `acctl codegen-tags` only emits variables
20
+ * marked `ux: true`, and a `${gm.…}` bound may legitimately name one that is
21
+ * not. Hence `partial` — a caller can say so on screen instead of quietly
22
+ * offering an incomplete list.
23
+ */
24
+ import type { GmVariable } from '@adcops/autocore-varpick';
25
+ import type { TagConfig } from '../core/AutoCoreTagTypes';
26
+ export interface GmIpcInvoker {
27
+ (topic: string, payload: object): Promise<{
28
+ success: boolean;
29
+ data?: any;
30
+ error_message?: string;
31
+ }>;
32
+ }
33
+ export interface UseGmVariablesOptions {
34
+ invoker?: GmIpcInvoker;
35
+ /**
36
+ * The HMI's generated tag spec, used when the server cannot describe its
37
+ * own variables. Without it, an old server yields an empty picker.
38
+ */
39
+ fallbackTags?: readonly TagConfig[];
40
+ /** Skip the read entirely (e.g. while a dialog is closed). */
41
+ enabled?: boolean;
42
+ }
43
+ export interface UseGmVariablesResult {
44
+ variables: GmVariable[];
45
+ loading: boolean;
46
+ /**
47
+ * True when the list came from the generated tag spec rather than the
48
+ * server — names and types, no descriptions, and `ux: true` variables only.
49
+ */
50
+ partial: boolean;
51
+ /** Set only when there is nothing to show at all. */
52
+ error: string | null;
53
+ refresh: () => Promise<void>;
54
+ }
55
+ export declare function useGmVariables(options?: UseGmVariablesOptions): UseGmVariablesResult;
56
+ export default useGmVariables;
57
+ //# sourceMappingURL=useGmVariables.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useGmVariables.d.ts","sourceRoot":"","sources":["../../src/hooks/useGmVariables.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAG3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAE1D,MAAM,WAAW,YAAY;IACzB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;QACtC,OAAO,EAAE,OAAO,CAAC;QACjB,IAAI,CAAC,EAAE,GAAG,CAAC;QACX,aAAa,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC,CAAC;CACN;AAED,MAAM,WAAW,qBAAqB;IAClC,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB;;;OAGG;IACH,YAAY,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;IACpC,8DAA8D;IAC9D,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,oBAAoB;IACjC,SAAS,EAAE,UAAU,EAAE,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB,qDAAqD;IACrD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAChC;AAyBD,wBAAgB,cAAc,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,oBAAoB,CAsDpF;AAED,eAAe,cAAc,CAAC"}
@@ -0,0 +1 @@
1
+ import{useCallback,useContext,useEffect,useRef,useState}from"react";import{EventEmitterContext}from"../core/EventEmitterContext";import{MessageType}from"../hub/CommandMessage";function fromTagSpec(e){return e.filter(e=>"string"==typeof e.fqdn&&e.fqdn.toLowerCase().startsWith("gm.")).map(e=>({fqdn:e.fqdn,name:e.fqdn.slice(3),type:String(e.valueType??""),description:"",quantity:e.quantity??e.scale,ux:!0,nonvolatile:!1,writable:!0,is_signal:!1})).sort((e,t)=>e.name.localeCompare(t.name))}export function useGmVariables(e){const t=useContext(EventEmitterContext),a=!1!==e?.enabled,r=e?.invoker??(async(e,a)=>await t.invoke(e,MessageType.Request,a)),s=useRef(r);s.current=r;const n=useRef(e?.fallbackTags);n.current=e?.fallbackTags;const[o,i]=useState([]),[l,u]=useState(a),[c,f]=useState(!1),[m,g]=useState(null),p=useCallback(async()=>{u(!0);try{const e=await s.current("gm.get_variables",{}),t=e?.data?.variables;if(e?.success&&Array.isArray(t))return i(t),f(!1),void g(null);throw new Error(e?.error_message||"gm.get_variables returned no variables")}catch(e){const t=n.current;t&&t.length>0?(i(fromTagSpec(t)),f(!0),g(null)):(i([]),f(!1),g(String(e?.message??e)))}finally{u(!1)}},[]);return useEffect(()=>{a?p():u(!1)},[a,p]),{variables:o,loading:l,partial:c,error:m,refresh:p}}export default useGmVariables;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * useSequenceProducers — the names a method's sequence actually records.
3
+ *
4
+ * A TIS cycle field has two possible producers and the method editor could only
5
+ * ever see one of them:
6
+ *
7
+ * 1. `source: "gm.<var>"` — the generated `add_cycle()` reads the tag.
8
+ * 2. `source: null` — the value arrives with the row, matched by NAME. On
9
+ * gen4_ac that is the sequencer: `store_value` steps fill a row buffer and
10
+ * `tis.add_cycle` writes `cycle_data` verbatim, without checking it against
11
+ * `cycle_fields`.
12
+ *
13
+ * Because nothing checks the second one, both of its failure modes are silent:
14
+ * a declared column nothing stores is blank on every row forever, and a stored
15
+ * name with no column is recorded where nothing displays it. This hook reads
16
+ * the `.seq.json` so the editor can say so.
17
+ *
18
+ * The method id IS the sequence filename and the TIS method id — one name, set
19
+ * by the sequence workbench's New / Save As / Open. A product with no sequencer
20
+ * simply has no such file, which is why "could not read it" resolves to
21
+ * `undefined` and never to `[]`: an empty list would claim every cycle field
22
+ * has no producer.
23
+ */
24
+ export interface UseSequenceProducersOptions {
25
+ /** Override the IPC layer (tests, playground). */
26
+ invoker?: (topic: string, messageType: number, payload: object) => Promise<any>;
27
+ }
28
+ export interface UseSequenceProducersResult {
29
+ /** `store_value` names, or `undefined` when there is no sequence to read. */
30
+ producedNames: string[] | undefined;
31
+ loading: boolean;
32
+ refresh: () => Promise<void>;
33
+ }
34
+ /** Every `store_value` name in a method, `cycle` bodies included. */
35
+ export declare function collectStoredNames(method: any): string[];
36
+ export declare function useSequenceProducers(methodId: string | null, options?: UseSequenceProducersOptions): UseSequenceProducersResult;
37
+ export default useSequenceProducers;
38
+ //# sourceMappingURL=useSequenceProducers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSequenceProducers.d.ts","sourceRoot":"","sources":["../../src/hooks/useSequenceProducers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAUH,MAAM,WAAW,2BAA2B;IACxC,kDAAkD;IAClD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;CACnF;AAED,MAAM,WAAW,0BAA0B;IACvC,6EAA6E;IAC7E,aAAa,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAChC;AAED,qEAAqE;AACrE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,GAAG,GAAG,MAAM,EAAE,CAiBxD;AAED,wBAAgB,oBAAoB,CAChC,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,OAAO,CAAC,EAAE,2BAA2B,GACtC,0BAA0B,CAkC5B;AAED,eAAe,oBAAoB,CAAC"}
@@ -0,0 +1 @@
1
+ import{useCallback,useContext,useEffect,useRef,useState}from"react";import{EventEmitterContext}from"../core/EventEmitterContext";import{MessageType}from"../hub/CommandMessage";const METHOD_DIR="methods",METHOD_EXT=".seq.json";export function collectStoredNames(e){const t=[],o=e=>{if(Array.isArray(e))for(const s of e)s&&"object"==typeof s&&("cycle"===s.type&&o(s.body),"store_value"===s.type&&"string"==typeof s.name&&""!==s.name.trim()&&(t.includes(s.name)||t.push(s.name)))};return o(e?.steps),t}export function useSequenceProducers(e,t){const o=useContext(EventEmitterContext),s=t?.invoker??((e,t,s)=>o.invoke(e,t,s)),r=useRef(s);r.current=s;const[n,a]=useState(void 0),[c,u]=useState(!1),i=useCallback(async()=>{if(e){u(!0);try{const t=`datastore.methods/${e}${METHOD_EXT}`,o=await r.current(t,MessageType.Read,{});if(!1===o?.success)return void a(void 0);const s=o?.data??o;if(!s||!Array.isArray(s.steps))return void a(void 0);a(collectStoredNames(s))}catch{a(void 0)}finally{u(!1)}}else a(void 0)},[e]);return useEffect(()=>{i()},[i]),{producedNames:n,loading:c,refresh:i}}export default useSequenceProducers;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adcops/autocore-react",
3
- "version": "3.5.9",
3
+ "version": "3.5.13",
4
4
  "description": "A React component library for industrial user interfaces.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -22,7 +22,9 @@
22
22
  "release:patch": "npm version patch && npm publish",
23
23
  "release:minor": "npm version minor && npm publish",
24
24
  "release:major": "npm version major && npm publish",
25
- "convert-assets": "npx @svgr/cli --typescript --out-dir src/assets/ src/assets/svg/ --jsx-runtime automatic --ignore-existing"
25
+ "convert-assets": "npx @svgr/cli --typescript --out-dir src/assets/ src/assets/svg/ --jsx-runtime automatic --ignore-existing",
26
+ "test:varpick": "vite build --config tools/tests/vite.config.mjs && node tools/tests/varpick.test.mjs",
27
+ "probe:live": "node tools/tests/live-server.probe.mjs"
26
28
  },
27
29
  "repository": {
28
30
  "type": "git",
@@ -54,6 +56,7 @@
54
56
  }
55
57
  },
56
58
  "dependencies": {
59
+ "@adcops/autocore-varpick": "^1.0.0",
57
60
  "@monaco-editor/react": "^4.7.0",
58
61
  "@tauri-apps/api": "^2.9.1",
59
62
  "chart.js": "^4.5.1",
@@ -127,3 +127,20 @@ export { NetworkPanel } from './network/NetworkPanel';
127
127
  export type { NetworkPanelProps } from './network/NetworkPanel';
128
128
  export { StagedChangeBanner } from './network/StagedChangeBanner';
129
129
  export type { StagedChangeBannerProps } from './network/StagedChangeBanner';
130
+
131
+ // -----------------------------------------------------------------------
132
+ // Variable picker — a field with a button that opens a searchable, described
133
+ // list of the machine's variables, so nobody has to type `gm.<something>`
134
+ // from memory. Used by the TIS method editor; exported for any other
135
+ // authoring surface that asks for a machine value.
136
+ // -----------------------------------------------------------------------
137
+ export { VariablePicker, VariableInput } from './varpick';
138
+ export type { VariablePickerProps, VariableInputProps } from './varpick';
139
+ export {
140
+ boundCatalog,
141
+ chartFieldCatalog,
142
+ configSourceCatalog,
143
+ cycleSourceCatalog,
144
+ rawSourceCatalog,
145
+ } from './varpick';
146
+ export type { TisCatalogContext } from './varpick';
@@ -105,6 +105,17 @@
105
105
  font-size: 0.8rem;
106
106
  }
107
107
 
108
+ /* A degradation, not a failure: the editor works, it just knows less. Amber
109
+ * rather than the red used for a real error. */
110
+ .tis-editor__notice {
111
+ background: #fffbeb;
112
+ color: #92400e;
113
+ border-left: 3px solid #d97706;
114
+ padding: 0.5rem 1rem;
115
+ margin: 0.5rem 1rem;
116
+ font-size: 0.875rem;
117
+ }
118
+
108
119
  .tis-editor__empty {
109
120
  flex: 1;
110
121
  display: flex;
@@ -31,6 +31,10 @@ import { SaveDiffDialog } from './editor/SaveDiffDialog';
31
31
  import type { TestMethod } from './types';
32
32
 
33
33
  import './TisConfigEditor.css';
34
+ import { useGmVariables } from '../../hooks/useGmVariables';
35
+ import { useSequenceProducers } from '../../hooks/useSequenceProducers';
36
+ import { AuthoringContext } from './editor/AuthoringContext';
37
+ import { AutoCoreTagContext } from '../../core/AutoCoreTagContext';
34
38
 
35
39
  export interface TisConfigEditorProps {
36
40
  /** Project ID. Today this is informational (the server hosts one
@@ -70,6 +74,11 @@ export const TisConfigEditor: React.FC<TisConfigEditorProps> = ({ projectId, inv
70
74
  );
71
75
 
72
76
  const tis = useTisConfig(projectId, { invoker: effectiveInvoker });
77
+
78
+ // What the variable pickers offer. Read once for the editor rather than
79
+ // per dialog: the table is ~100 rows and every field dialog wants it.
80
+ const { tags } = useContext(AutoCoreTagContext);
81
+ const gm = useGmVariables({ invoker: effectiveInvoker, fallbackTags: tags });
73
82
  const ams = useAmsAssetTypes({ invoker: effectiveInvoker });
74
83
  const [selectedId, setSelectedId] = useState<string | null>(null);
75
84
  const [draftError, setDraftError] = useState<string | null>(null);
@@ -101,6 +110,15 @@ export const TisConfigEditor: React.FC<TisConfigEditorProps> = ({ projectId, inv
101
110
  // Clear errors whenever the selected method changes.
102
111
  useEffect(() => { setDraftError(null); }, [selectedId]);
103
112
 
113
+ // The sequence that fills this method's cycle columns, if it has one. Keyed
114
+ // on the selected method because the method id IS the sequence filename.
115
+ const { producedNames } = useSequenceProducers(selectedId);
116
+
117
+ const authoring = useMemo(
118
+ () => ({ variables: gm.variables, producedNames, partial: gm.partial }),
119
+ [gm.variables, producedNames, gm.partial],
120
+ );
121
+
104
122
  const onApply = async (next: TestMethod) => {
105
123
  if (!selectedId) return;
106
124
  setBusy(true);
@@ -197,6 +215,7 @@ export const TisConfigEditor: React.FC<TisConfigEditorProps> = ({ projectId, inv
197
215
  };
198
216
 
199
217
  return (
218
+ <AuthoringContext.Provider value={authoring}>
200
219
  <div className="tis-editor">
201
220
  <header className="tis-editor__header">
202
221
  <h2>
@@ -228,6 +247,17 @@ export const TisConfigEditor: React.FC<TisConfigEditorProps> = ({ projectId, inv
228
247
  </div>
229
248
  )}
230
249
 
250
+ {/* Said out loud rather than left implicit: a picker that silently
251
+ lists two thirds of the machine sends an author hunting for a
252
+ variable that is there, just not offered. */}
253
+ {gm.partial && (
254
+ <div className="tis-editor__notice">
255
+ This server cannot describe its own variables, so the pickers are
256
+ listing only the variables published to this HMI, without descriptions.
257
+ Update autocore_server to get the full list.
258
+ </div>
259
+ )}
260
+
231
261
  <div className="tis-editor__body">
232
262
  <aside className="tis-editor__sidebar">
233
263
  <div className="tis-editor__sidebar-actions">
@@ -321,6 +351,7 @@ export const TisConfigEditor: React.FC<TisConfigEditorProps> = ({ projectId, inv
321
351
  onCancel={() => setSaveDialogOpen(false)}
322
352
  />
323
353
  </div>
354
+ </AuthoringContext.Provider>
324
355
  );
325
356
  };
326
357
 
@@ -0,0 +1,43 @@
1
+ /**
2
+ * What the method editor's pickers can offer.
3
+ *
4
+ * A context rather than props because the fields that need it — a field
5
+ * dialog's Source, a bound, a chart axis, a raw column — sit three and four
6
+ * levels below the editor that fetches it, and threading the same two values
7
+ * through every intermediate component is how a prop list becomes noise.
8
+ *
9
+ * Everything here is optional. With none of it the pickers still open; they just
10
+ * have nothing to list, which is exactly the state the editor was in before they
11
+ * existed.
12
+ */
13
+
14
+ import { createContext, useContext } from 'react';
15
+ import type { GmVariable } from '@adcops/autocore-varpick';
16
+
17
+ export interface AuthoringCatalogs {
18
+ /** The machine's GM variable table, from `gm.get_variables`. */
19
+ variables: GmVariable[];
20
+
21
+ /**
22
+ * `store_value` names in the selected method's sequence.
23
+ *
24
+ * `undefined` means "not looked up" — the host could not read the
25
+ * `.seq.json`, or this product has no sequencer. That is deliberately
26
+ * different from `[]`, which means "read it, and it stores nothing": the
27
+ * first must not claim a cycle field has no producer.
28
+ */
29
+ producedNames?: string[];
30
+
31
+ /**
32
+ * True when `variables` came from the generated tag spec rather than the
33
+ * server — names and types, no descriptions, `ux: true` only.
34
+ *
35
+ * Worth surfacing: a picker that silently lists two thirds of the machine
36
+ * is worse than one that says it is listing two thirds of the machine.
37
+ */
38
+ partial?: boolean;
39
+ }
40
+
41
+ export const AuthoringContext = createContext<AuthoringCatalogs>({ variables: [] });
42
+
43
+ export const useAuthoringCatalogs = (): AuthoringCatalogs => useContext(AuthoringContext);