@adcops/autocore-react 3.1.1 → 3.3.5

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 (252) hide show
  1. package/additional-docs/react_performance_notes.md +94 -0
  2. package/dist/components/AutoCoreDevPanel.d.ts.map +1 -1
  3. package/dist/components/AutoCoreDevPanel.js +1 -1
  4. package/dist/components/FileList.d.ts.map +1 -1
  5. package/dist/components/FileList.js +1 -1
  6. package/dist/components/FileSelect.d.ts.map +1 -1
  7. package/dist/components/FileSelect.js +1 -1
  8. package/dist/core/AutoCoreTagContext.d.ts +59 -185
  9. package/dist/core/AutoCoreTagContext.d.ts.map +1 -1
  10. package/dist/core/AutoCoreTagContext.js +1 -1
  11. package/dist/core/AutoCoreTagTypes.d.ts +127 -6
  12. package/dist/core/AutoCoreTagTypes.d.ts.map +1 -1
  13. package/dist/core/CoreStreamTypes.d.ts +345 -0
  14. package/dist/core/CoreStreamTypes.d.ts.map +1 -0
  15. package/dist/core/CoreStreamTypes.js +1 -0
  16. package/dist/core/EventEmitterContext.d.ts +91 -473
  17. package/dist/core/EventEmitterContext.d.ts.map +1 -1
  18. package/dist/core/EventEmitterContext.js +1 -1
  19. package/dist/hooks/adsHooks.d.ts.map +1 -1
  20. package/dist/hooks/adsHooks.js +1 -1
  21. package/dist/hooks/commandHooks.d.ts +3 -3
  22. package/dist/hooks/commandHooks.d.ts.map +1 -1
  23. package/dist/hooks/commandHooks.js +1 -1
  24. package/dist/hooks/useAutoCoreTag.js +1 -1
  25. package/dist/hub/CommandMessage.d.ts +18 -9
  26. package/dist/hub/CommandMessage.d.ts.map +1 -1
  27. package/dist/hub/CommandMessage.js +1 -1
  28. package/dist/hub/DebugPanel.d.ts +31 -0
  29. package/dist/hub/DebugPanel.d.ts.map +1 -0
  30. package/dist/hub/DebugPanel.js +1 -0
  31. package/dist/hub/HubBase.d.ts +83 -129
  32. package/dist/hub/HubBase.d.ts.map +1 -1
  33. package/dist/hub/HubBase.js +1 -1
  34. package/dist/hub/HubSimulate.d.ts +41 -8
  35. package/dist/hub/HubSimulate.d.ts.map +1 -1
  36. package/dist/hub/HubSimulate.js +1 -1
  37. package/dist/hub/HubTauri.d.ts +24 -60
  38. package/dist/hub/HubTauri.d.ts.map +1 -1
  39. package/dist/hub/HubTauri.js +1 -1
  40. package/dist/hub/HubWebSocket.d.ts +33 -17
  41. package/dist/hub/HubWebSocket.d.ts.map +1 -1
  42. package/dist/hub/HubWebSocket.js +1 -1
  43. package/dist/hub/debug.d.ts +23 -0
  44. package/dist/hub/debug.d.ts.map +1 -0
  45. package/dist/hub/debug.js +1 -0
  46. package/dist/hub/index.d.ts +19 -4
  47. package/dist/hub/index.d.ts.map +1 -1
  48. package/dist/hub/index.js +1 -1
  49. package/package.json +8 -4
  50. package/src/components/AutoCoreDevPanel.tsx +14 -11
  51. package/src/components/FileList.tsx +5 -4
  52. package/src/components/FileSelect.tsx +2 -1
  53. package/src/core/ActionMode.ts +1 -1
  54. package/src/core/AutoCoreTagContext.tsx +247 -330
  55. package/src/core/AutoCoreTagTypes.ts +236 -104
  56. package/src/core/CoreStreamTypes.ts +512 -0
  57. package/src/core/EventEmitterContext.tsx +182 -520
  58. package/src/core/IndicatorButtonState.ts +1 -1
  59. package/src/core/hoc.tsx +1 -1
  60. package/src/hooks/adsHooks.tsx +21 -22
  61. package/src/hooks/commandHooks.tsx +23 -19
  62. package/src/hooks/index.ts +1 -1
  63. package/src/hooks/useAutoCoreTag.ts +2 -2
  64. package/src/hooks/useScaledValue.tsx +1 -1
  65. package/src/hub/CommandMessage.ts +71 -19
  66. package/src/hub/DebugPanel.ts +280 -0
  67. package/src/hub/HubBase.ts +147 -223
  68. package/src/hub/HubSimulate.ts +93 -24
  69. package/src/hub/HubTauri.ts +87 -96
  70. package/src/hub/HubWebSocket.ts +118 -140
  71. package/src/hub/debug.ts +211 -0
  72. package/src/hub/index.ts +49 -39
  73. package/docs/.nojekyll +0 -1
  74. package/docs/assets/hierarchy.js +0 -1
  75. package/docs/assets/highlight.css +0 -134
  76. package/docs/assets/icons.js +0 -18
  77. package/docs/assets/icons.svg +0 -1
  78. package/docs/assets/main.js +0 -60
  79. package/docs/assets/navigation.js +0 -1
  80. package/docs/assets/search.js +0 -1
  81. package/docs/assets/style.css +0 -1633
  82. package/docs/classes/components_CodeEditor.CodeEditor.html +0 -135
  83. package/docs/classes/components_Indicator.Indicator.html +0 -122
  84. package/docs/classes/components_IndicatorRect.IndicatorRect.html +0 -121
  85. package/docs/classes/components_JogPanel.JogPanel.html +0 -136
  86. package/docs/classes/components_Lamp.Lamp.html +0 -122
  87. package/docs/classes/components_OskDialog.OskDialog.html +0 -125
  88. package/docs/classes/components_TextInput.TextInput.html +0 -125
  89. package/docs/classes/components_ValueDisplay.ValueDisplay.html +0 -148
  90. package/docs/classes/components_ValueIndicator.ValueIndicator.html +0 -126
  91. package/docs/classes/core_ValueSimulator.ValueSimulator.html +0 -51
  92. package/docs/classes/hub_HubBase.HubBase.html +0 -106
  93. package/docs/classes/hub_HubSimulate.HubSimulate.html +0 -75
  94. package/docs/classes/hub_HubTauri.HubTauri.html +0 -93
  95. package/docs/classes/hub_HubWebSocket.HubWebSocket.html +0 -112
  96. package/docs/documents/core_AutoCoreTagContext.AutoCoreTagContext.html +0 -148
  97. package/docs/enums/components_JogPanel.JogDistanceAction.html +0 -5
  98. package/docs/enums/components_JogPanel.JogPanelAction.html +0 -18
  99. package/docs/enums/components_JogPanel.JogSpeedAction.html +0 -5
  100. package/docs/enums/core_ActionMode.ActionMode.html +0 -6
  101. package/docs/enums/core_IndicatorColor.IndicatorColor.html +0 -23
  102. package/docs/functions/assets.BlocklyLogo.html +0 -1
  103. package/docs/functions/assets.Distance.html +0 -1
  104. package/docs/functions/assets.JogLong.html +0 -1
  105. package/docs/functions/assets.JogMedium.html +0 -1
  106. package/docs/functions/assets.JogShort.html +0 -1
  107. package/docs/functions/assets.PythonLogo.html +0 -1
  108. package/docs/functions/assets.Rotation3D.html +0 -1
  109. package/docs/functions/assets.RotationCcw.html +0 -1
  110. package/docs/functions/assets.RotationCcwA.html +0 -1
  111. package/docs/functions/assets.RotationCcwB.html +0 -1
  112. package/docs/functions/assets.RotationCcwC.html +0 -1
  113. package/docs/functions/assets.RotationCw.html +0 -1
  114. package/docs/functions/assets.RotationCwA.html +0 -1
  115. package/docs/functions/assets.RotationCwB.html +0 -1
  116. package/docs/functions/assets.RotationCwC.html +0 -1
  117. package/docs/functions/assets.Run.html +0 -1
  118. package/docs/functions/assets.Speed.html +0 -1
  119. package/docs/functions/assets.SpeedFast.html +0 -1
  120. package/docs/functions/assets.SpeedMedium.html +0 -1
  121. package/docs/functions/assets.SpeedNone.html +0 -1
  122. package/docs/functions/assets.SpeedSlow.html +0 -1
  123. package/docs/functions/assets.Walk.html +0 -1
  124. package/docs/functions/components_BlocklyEditor.createCustomToolbox.html +0 -6
  125. package/docs/functions/core_UniqueId.UniqueId.html +0 -9
  126. package/docs/functions/core_hoc.hocAddSubscription.html +0 -6
  127. package/docs/functions/hooks_adsHooks.useAdsRegisterSymbols.html +0 -16
  128. package/docs/functions/hooks_adsHooks.useAdsTapValue.html +0 -8
  129. package/docs/functions/hooks_adsHooks.useAdsWriteScaledValue.html +0 -18
  130. package/docs/functions/hooks_adsHooks.useAdsWriteValue.html +0 -9
  131. package/docs/functions/hooks_commandHooks.useRegisterSymbols.html +0 -16
  132. package/docs/functions/hooks_commandHooks.useTapValue.html +0 -10
  133. package/docs/functions/hooks_commandHooks.useWriteScaledValue.html +0 -18
  134. package/docs/functions/hooks_commandHooks.useWriteValue.html +0 -11
  135. package/docs/functions/hooks_useAutoCoreTag.ts.makeAutoCoreTagHooks.html +0 -12
  136. package/docs/functions/hooks_useScaledValue.useScaledValue.html +0 -18
  137. package/docs/functions/hub.createHub.html +0 -3
  138. package/docs/hierarchy.html +0 -1
  139. package/docs/index.html +0 -148
  140. package/docs/interfaces/components_IndicatorButton.IndicatorButtonProps.html +0 -654
  141. package/docs/interfaces/components_IndicatorRect.IndicatorRectProps.html +0 -37
  142. package/docs/interfaces/components_JogPanel.JogPanelButtonDefinition.html +0 -5
  143. package/docs/interfaces/components_ToggleGroup.ToggleGroupProps.html +0 -644
  144. package/docs/interfaces/core_AutoCoreTagTypes.BaseContextValue.html +0 -12
  145. package/docs/interfaces/core_AutoCoreTagTypes.ScaleConfig.html +0 -13
  146. package/docs/interfaces/core_EventEmitterContext.Action.html +0 -8
  147. package/docs/interfaces/core_EventEmitterContext.EventEmitterContextType.html +0 -33
  148. package/docs/interfaces/core_EventEmitterContext.State.html +0 -8
  149. package/docs/interfaces/core_EventEmitterContext.Subscription.html +0 -6
  150. package/docs/interfaces/core_IndicatorButtonState.IndicatorButtonState.html +0 -10
  151. package/docs/interfaces/core_PositionContext.IPositionContext.html +0 -17
  152. package/docs/interfaces/hub_CommandMessage.CommandMessage.html +0 -6
  153. package/docs/interfaces/hub_CommandMessage.CommandMessageResult.html +0 -4
  154. package/docs/modules/assets.html +0 -1
  155. package/docs/modules/assets_BlocklyLogo.html +0 -1
  156. package/docs/modules/assets_Distance.html +0 -1
  157. package/docs/modules/assets_JogLong.html +0 -1
  158. package/docs/modules/assets_JogMedium.html +0 -1
  159. package/docs/modules/assets_JogShort.html +0 -1
  160. package/docs/modules/assets_PythonLogo.html +0 -1
  161. package/docs/modules/assets_Rotation3D.html +0 -1
  162. package/docs/modules/assets_RotationCcw.html +0 -1
  163. package/docs/modules/assets_RotationCcwA.html +0 -1
  164. package/docs/modules/assets_RotationCcwB.html +0 -1
  165. package/docs/modules/assets_RotationCcwC.html +0 -1
  166. package/docs/modules/assets_RotationCw.html +0 -1
  167. package/docs/modules/assets_RotationCwA.html +0 -1
  168. package/docs/modules/assets_RotationCwB.html +0 -1
  169. package/docs/modules/assets_RotationCwC.html +0 -1
  170. package/docs/modules/assets_Run.html +0 -1
  171. package/docs/modules/assets_Speed.html +0 -1
  172. package/docs/modules/assets_SpeedFast.html +0 -1
  173. package/docs/modules/assets_SpeedMedium.html +0 -1
  174. package/docs/modules/assets_SpeedNone.html +0 -1
  175. package/docs/modules/assets_SpeedSlow.html +0 -1
  176. package/docs/modules/assets_Walk.html +0 -1
  177. package/docs/modules/components_AutoCoreDevPanel.html +0 -20
  178. package/docs/modules/components_BlocklyEditor.html +0 -1
  179. package/docs/modules/components_CodeEditor.html +0 -1
  180. package/docs/modules/components_FileList.html +0 -1
  181. package/docs/modules/components_FileSelect.html +0 -1
  182. package/docs/modules/components_FitText.html +0 -1
  183. package/docs/modules/components_Indicator.html +0 -1
  184. package/docs/modules/components_IndicatorButton.html +0 -1
  185. package/docs/modules/components_IndicatorRect.html +0 -1
  186. package/docs/modules/components_JogPanel.html +0 -1
  187. package/docs/modules/components_Lamp.html +0 -1
  188. package/docs/modules/components_Osk.html +0 -1
  189. package/docs/modules/components_OskDialog.html +0 -1
  190. package/docs/modules/components_ProgressBarWithValue.html +0 -1
  191. package/docs/modules/components_TextInput.html +0 -1
  192. package/docs/modules/components_ToggleGroup.html +0 -1
  193. package/docs/modules/components_ValueDisplay.html +0 -1
  194. package/docs/modules/components_ValueIndicator.html +0 -1
  195. package/docs/modules/components_ValueInput.html +0 -1
  196. package/docs/modules/core_ActionMode.html +0 -1
  197. package/docs/modules/core_AutoCoreTagContext.html +0 -11
  198. package/docs/modules/core_AutoCoreTagTypes.html +0 -1
  199. package/docs/modules/core_EventEmitterContext.html +0 -53
  200. package/docs/modules/core_IndicatorButtonState.html +0 -1
  201. package/docs/modules/core_IndicatorColor.html +0 -1
  202. package/docs/modules/core_MaskPatterns.html +0 -1
  203. package/docs/modules/core_NumerableTypes.html +0 -1
  204. package/docs/modules/core_PositionContext.html +0 -1
  205. package/docs/modules/core_UniqueId.html +0 -1
  206. package/docs/modules/core_ValueSimulator.html +0 -1
  207. package/docs/modules/core_hoc.html +0 -1
  208. package/docs/modules/hooks.html +0 -1
  209. package/docs/modules/hooks_adsHooks.html +0 -1
  210. package/docs/modules/hooks_commandHooks.html +0 -1
  211. package/docs/modules/hooks_useAutoCoreTag.ts.html +0 -52
  212. package/docs/modules/hooks_useScaledValue.html +0 -1
  213. package/docs/modules/hub.html +0 -1
  214. package/docs/modules/hub_CommandMessage.html +0 -1
  215. package/docs/modules/hub_HubBase.html +0 -1
  216. package/docs/modules/hub_HubSimulate.html +0 -1
  217. package/docs/modules/hub_HubTauri.html +0 -1
  218. package/docs/modules/hub_HubWebSocket.html +0 -1
  219. package/docs/modules.html +0 -23
  220. package/docs/types/components_IndicatorButton.IndicatorButtonOptionsType.html +0 -1
  221. package/docs/types/core_AutoCoreTagTypes.ExtractByTag.html +0 -2
  222. package/docs/types/core_AutoCoreTagTypes.PrimitiveKind.html +0 -1
  223. package/docs/types/core_AutoCoreTagTypes.TagConfig.html +0 -16
  224. package/docs/types/core_AutoCoreTagTypes.TagValueMap.html +0 -1
  225. package/docs/types/core_AutoCoreTagTypes.TagValueOf.html +0 -1
  226. package/docs/types/core_EventEmitterContext.EmitterDispatchFunction.html +0 -3
  227. package/docs/types/core_EventEmitterContext.EmitterSubscribeFunction.html +0 -3
  228. package/docs/types/core_EventEmitterContext.EmitterUnsubscribeFunction.html +0 -3
  229. package/docs/types/core_NumerableTypes.NumerableFormatOptions.html +0 -4
  230. package/docs/types/core_hoc.HocAddSubscriptionProps.html +0 -6
  231. package/docs/variables/components_AutoCoreDevPanel.AutoCoreDevPanel.html +0 -43
  232. package/docs/variables/components_BlocklyEditor.BlocklyEditor.html +0 -13
  233. package/docs/variables/components_BlocklyEditor.StandardToolbox.html +0 -1
  234. package/docs/variables/components_FileList.FileList.html +0 -23
  235. package/docs/variables/components_FileSelect.FileSelect.html +0 -1
  236. package/docs/variables/components_FitText.FitText.html +0 -4
  237. package/docs/variables/components_IndicatorButton.IndicatorButton.html +0 -1
  238. package/docs/variables/components_JogPanel.DefaultLinearJogButtons.html +0 -2
  239. package/docs/variables/components_JogPanel.DefaultRotationJogButtons.html +0 -2
  240. package/docs/variables/components_Osk.Osk.html +0 -1
  241. package/docs/variables/components_ProgressBarWithValue.ProgressBarWithValue.html +0 -1
  242. package/docs/variables/components_ToggleGroup.ToggleGroup.html +0 -1
  243. package/docs/variables/components_ValueInput.ValueInput.html +0 -4
  244. package/docs/variables/core_AutoCoreTagContext.AutoCoreTagContext.html +0 -1
  245. package/docs/variables/core_AutoCoreTagContext.AutoCoreTagProvider.html +0 -7
  246. package/docs/variables/core_EventEmitterContext.EventEmitterContext.html +0 -64
  247. package/docs/variables/core_EventEmitterContext.EventEmitterProvider.html +0 -10
  248. package/docs/variables/core_MaskPatterns.PrimeReactMaskPatterns.html +0 -14
  249. package/docs/variables/core_MaskPatterns.RegExMaskPatterns.html +0 -15
  250. package/docs/variables/core_PositionContext.DimensionsContext.html +0 -6
  251. package/docs/variables/hooks_useScaledValue.kMillimeters2Inches.html +0 -2
  252. package/docs/variables/hooks_useScaledValue.kNewtons2Pounds.html +0 -2
@@ -0,0 +1,94 @@
1
+ # AutoCore React Performance & Architecture Notes
2
+
3
+ ## Overview
4
+
5
+ This document details the architectural decisions and performance optimizations implemented in the `autocore-react` library, specifically regarding the `EventEmitterContext` and `AutoCoreTagContext`. These changes were made to solve issues with infinite re-render loops and performance bottlenecks when handling high-frequency sensor data (e.g., 50Hz+ updates).
6
+
7
+ ## Key Performance Rules
8
+
9
+ ### 1. Avoid Global Context State Updates for High-Frequency Data
10
+
11
+ **The Problem:**
12
+ Originally, `EventEmitterContext` stored the latest event payload in its state (`state.eventData`).
13
+ Every time a WebSocket message arrived (e.g., a sensor value update), `setState` was called.
14
+ Since `EventEmitterContext` wraps the entire application, **every single component in the app re-rendered** on every sensor update.
15
+
16
+ **The Fix:**
17
+ We removed the `setState` call from the `dispatch` function.
18
+ - **Old way:** `dispatch` -> `setState` -> `Context Value Change` -> `App Re-render`.
19
+ - **New way:** `dispatch` -> Iterate Subscribers -> `callback(payload)`.
20
+
21
+ **Rule:**
22
+ > Do NOT store high-frequency data (like sensor readings) in a global Context's `value` or `state` property if that Context is consumed by the root component. Use a subscription model (observers/listeners) instead.
23
+
24
+ ### 2. Stable Object References (Memoization)
25
+
26
+ **The Problem:**
27
+ In `AutoCoreTagContext`, the `scales` prop was defaulted using a destructuring assignment: `scales = {}`.
28
+ This created a **new object reference** on every render.
29
+ This unstable reference was used in `useEffect` dependency arrays, causing effects to re-run infinitely, leading to subscription storms and infinite loops.
30
+
31
+ **The Fix:**
32
+ We memoized the default empty object:
33
+ ```typescript
34
+ const defaultScales = useMemo(() => ({}), []);
35
+ const actualScales = scales ?? defaultScales;
36
+ ```
37
+ And used `actualScales` everywhere.
38
+
39
+ **Rule:**
40
+ > Always ensure objects passed to Context Providers or used in `useEffect` dependencies are referentially stable. Use `useMemo` for derived objects and constants.
41
+
42
+ ### 3. Side-Effects in Render Phase
43
+
44
+ **The Problem:**
45
+ `EventEmitterProvider` was calling `hub.setContext(contextValue)` directly in the component body (during the render phase).
46
+ React's Concurrent Mode or Strict Mode can call the render function multiple times without committing, leading to unpredictable state in the `Hub` singleton.
47
+
48
+ **The Fix:**
49
+ Moved the side-effect to `useEffect`:
50
+ ```typescript
51
+ useEffect(() => {
52
+ hub.setContext(contextValue);
53
+ }, [hub, contextValue]);
54
+ ```
55
+
56
+ **Rule:**
57
+ > Never mutate external Singletons or perform side-effects in the main body of a React Functional Component. Always use `useEffect`.
58
+
59
+ ---
60
+
61
+ ## Data Flow Architecture
62
+
63
+ ### 1. Tag Name vs. FQDN
64
+
65
+ To decouple the UI from the backend implementation:
66
+ - **FQDN (Fully Qualified Domain Name)**: The backend address (e.g., `ADS.Main.bStart`). Used only for wire communication.
67
+ - **TagName**: The local UI alias (e.g., `startCmd`). Used by React components.
68
+
69
+ **The Flow:**
70
+ 1. **Component**: Calls `useAutoCoreTag("startCmd")`.
71
+ 2. **Context**: Looks up config, finds FQDN `ADS.Main.bStart`.
72
+ 3. **Context**: Calls `hub.subscribe("startCmd", "ADS.Main.bStart")`.
73
+ 4. **Hub**: Maps `ADS.Main.bStart` -> `startCmd`.
74
+ 5. **Backend**: Sends update for `ADS.Main.bStart`.
75
+ 6. **Hub**: Receives update, translates topic to `startCmd`, dispatches event.
76
+ 7. **Context**: Listens for `startCmd`, updates state.
77
+ 8. **Component**: Re-renders with new value.
78
+
79
+ ### 2. Dual-State Storage
80
+
81
+ `AutoCoreTagContext` stores two versions of every value:
82
+ 1. **`rawValues`**: The exact JSON received from the server. **(Source of Truth)**
83
+ 2. **`values`**: The scaled/decoded value for display.
84
+
85
+ When a scale changes (e.g., mm to inches), we recompute `values` from `rawValues`. We never rescale a previously scaled value to avoid floating-point drift.
86
+
87
+ ---
88
+
89
+ ## Best Practices for Team
90
+
91
+ 1. **Use Hooks**: Always use `useAutoCoreTag` or `useAutoCoreTags`. Do not consume the Context directly unless necessary.
92
+ 2. **Key by TagName**: When adding features, always prefer `tagName` over `fqdn` for local logic.
93
+ 3. **Console Logs**: Avoid leaving `console.log` in render paths (components). It floods the console and slows down the browser.
94
+ 4. **Strict Mode**: Be aware that React Strict Mode mounts components twice. Your `useEffect` cleanup functions must be robust.
@@ -1 +1 @@
1
- {"version":3,"file":"AutoCoreDevPanel.d.ts","sourceRoot":"","sources":["../../src/components/AutoCoreDevPanel.tsx"],"names":[],"mappings":"AASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgFG;AAEH,OAAO,KAAqD,MAAM,OAAO,CAAC;AAC1E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAG1D;;GAEG;AACH,UAAU,qBAAqB;IAC7B;;;OAGG;IACH,IAAI,EAAE,SAAS,SAAS,EAAE,CAAC;IAE3B;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAsK5D,CAAC"}
1
+ {"version":3,"file":"AutoCoreDevPanel.d.ts","sourceRoot":"","sources":["../../src/components/AutoCoreDevPanel.tsx"],"names":[],"mappings":"AASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgFG;AAEH,OAAO,KAAqD,MAAM,OAAO,CAAC;AAC1E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAM1D;;GAEG;AACH,UAAU,qBAAqB;IAC7B;;;OAGG;IACH,IAAI,EAAE,SAAS,SAAS,EAAE,CAAC;IAE3B;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAsK5D,CAAC"}
@@ -1 +1 @@
1
- import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React,{useContext,useMemo,useState,useCallback}from"react";import{AutoCoreTagContext}from"../core/AutoCoreTagContext";export const AutoCoreDevPanel=({tags:e,title:t="AutoCore Dev Panel",className:n=""})=>{const{values:a,rawValues:o,isLoading:l,write:r,tap:s,scales:i}=useContext(AutoCoreTagContext),[d,c]=useState({}),[u,h]=useState({}),m=useMemo(()=>e.map(e=>{const t=a[e.tagName],n=o[e.tagName],l=e.scale??"",r=l?i[l]:void 0;return{tag:e,display:t,raw:n,scaleName:l,factor:r?.scale,label:r?.label}}),[e,a,o,i]),x=useCallback((e,t)=>{c(n=>({...n,[e]:t})),h(t=>({...t,[e]:""}))},[]),p=useCallback((e,t)=>{h(n=>({...n,[e]:t}))},[]),g=useCallback(async e=>{const t=e.tagName,n=d[t];try{if("boolean"===e.valueType){const e="true"===n||"false"!==n&&!a[t];return await r(t,e),void x(t,"")}if("number"===e.valueType){if(null==n||""===n.trim())return void p(t,"Enter a number.");const e=Number(n);return Number.isNaN(e)?void p(t,"Invalid number."):(await r(t,e),void x(t,""))}if("string"===e.valueType)return await r(t,n??""),void x(t,"");try{const e=n?.trim()?JSON.parse(n):null;await r(t,e),x(t,"")}catch(e){p(t,"Invalid JSON.")}}catch(e){p(t,e?.message??String(e))}},[d,x,p,r,a]);return _jsxs("div",{className:`rounded-md border border-gray-200 bg-white text-sm ${n}`,style:{minWidth:680},children:[_jsx("div",{className:"flex items-center justify-between px-3 py-2",style:{borderBottom:"1px solid #eee"},children:_jsxs("div",{className:"flex items-center gap-2",children:[_jsx("strong",{children:t}),_jsx("span",{title:l?"Loading":"Live",style:{width:8,height:8,borderRadius:999,background:l?"#aaa":"#22c55e",display:"inline-block"}})]})}),_jsx("div",{style:{overflowX:"auto"},children:_jsxs("table",{style:{borderCollapse:"collapse",width:"100%"},children:[_jsx("thead",{children:_jsxs("tr",{children:[_jsx(Th,{children:"Tag"}),_jsx(Th,{children:"Kind"}),_jsx(Th,{children:"Domain"}),_jsx(Th,{children:"Symbol"}),_jsx(Th,{children:"Display"}),_jsx(Th,{children:"Raw"}),_jsx(Th,{children:"Scale"}),_jsx(Th,{children:"Units"}),_jsx(Th,{children:"Input"}),_jsx(Th,{children:"Actions"})]})}),_jsx("tbody",{children:m.map(({tag:e,display:t,raw:n,scaleName:a,factor:o,label:l})=>{const r=d[e.tagName]??"",i=u[e.tagName];return _jsxs("tr",{children:[_jsx(Td,{mono:!0,children:e.tagName}),_jsx(Td,{mono:!0,children:e.valueType}),_jsx(Td,{mono:!0,children:e.domain}),_jsx(Td,{mono:!0,children:e.symbolName}),_jsx(Td,{mono:!0,children:fmt(t)}),_jsx(Td,{mono:!0,children:fmt(n)}),_jsx(Td,{mono:!0,children:a?`${a} ×${o??1}`:"—"}),_jsx(Td,{mono:!0,children:a?l??"":"—"}),_jsxs(Td,{children:[_jsx(InputForTag,{tag:e,buf:r,setBuf:t=>x(e.tagName,t),onKeyDown:t=>((e,t)=>{"Enter"!==e.key||e.shiftKey||(e.preventDefault(),g(t))})(t,e)}),i&&_jsx("div",{style:{color:"#dc2626",marginTop:4},children:i})]}),_jsx(Td,{children:_jsxs("div",{style:{display:"flex",gap:6},children:[_jsx("button",{onClick:()=>g(e),children:"Write"}),"boolean"===e.valueType&&_jsx("button",{onClick:()=>s(e.tagName),children:"TAP"})]})})]},e.tagName)})})]})})]})};const Th=({children:e})=>_jsx("th",{style:{textAlign:"left",borderBottom:"1px solid #ddd",padding:"6px 8px",fontFamily:"ui-monospace, SFMono-Regular, Menlo, monospace"},children:e}),Td=({children:e,mono:t})=>_jsx("td",{style:{borderBottom:"1px solid #eee",padding:"6px 8px",whiteSpace:"nowrap",fontFamily:t?"ui-monospace, SFMono-Regular, Menlo, monospace":"inherit"},children:e}),InputForTag=({tag:e,buf:t,setBuf:n,onKeyDown:a})=>"boolean"===e.valueType?_jsxs("label",{style:{display:"inline-flex",alignItems:"center",gap:6},children:[_jsx("input",{type:"checkbox",checked:t?"true"===t:Boolean,onChange:e=>n(e.target.checked?"true":"false"),onKeyDown:a}),_jsx("span",{children:"set"})]}):"number"===e.valueType?_jsx("input",{type:"number",step:"any",value:t,onChange:e=>n(e.target.value),onKeyDown:a,style:{width:140},placeholder:"number…"}):"string"===e.valueType?_jsx("input",{type:"text",value:t,onChange:e=>n(e.target.value),onKeyDown:a,style:{width:180},placeholder:"text…"}):_jsx("textarea",{value:t,onChange:e=>n(e.target.value),onKeyDown:a,rows:2,style:{width:260,fontFamily:"ui-monospace, SFMono-Regular, Menlo, monospace"},placeholder:'{"foo": 42}'});function fmt(e){if(null==e)return"—";if("number"==typeof e)return Number.isFinite(e)?e.toString():String(e);if("string"==typeof e)return e;try{return JSON.stringify(e)}catch{return String(e)}}
1
+ import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React,{useContext,useMemo,useState,useCallback}from"react";import{AutoCoreTagContext}from"../core/AutoCoreTagContext";const getDomain=e=>e.split(".")[0];export const AutoCoreDevPanel=({tags:e,title:n="AutoCore Dev Panel",className:t=""})=>{const{values:o,rawValues:a,isLoading:s,write:l,tap:r,scales:i}=useContext(AutoCoreTagContext),[d,c]=useState({}),[u,h]=useState({}),x=useMemo(()=>e.map(e=>{const n=o[e.fqdn],t=a[e.fqdn],s=e.scale??"",l=s?i[s]:void 0;return{tag:e,display:n,raw:t,scaleName:s,factor:l?.scale,label:l?.label}}),[e,o,a,i]),m=useCallback((e,n)=>{c(t=>({...t,[e]:n})),h(n=>({...n,[e]:""}))},[]),p=useCallback((e,n)=>{h(t=>({...t,[e]:n}))},[]),y=useCallback(async e=>{const n=e.fqdn,t=d[n];try{if("boolean"===e.valueType){const e="true"===t||"false"!==t&&!o[n];return await l(n,e),void m(n,"")}if("number"===e.valueType){if(null==t||""===t.trim())return void p(n,"Enter a number.");const e=Number(t);return Number.isNaN(e)?void p(n,"Invalid number."):(await l(n,e),void m(n,""))}if("string"===e.valueType)return await l(n,t??""),void m(n,"");try{const e=t?.trim()?JSON.parse(t):null;await l(n,e),m(n,"")}catch(e){p(n,"Invalid JSON.")}}catch(e){p(n,e?.message??String(e))}},[d,m,p,l,o]);return _jsxs("div",{className:`rounded-md border border-gray-200 bg-white text-sm ${t}`,style:{minWidth:680},children:[_jsx("div",{className:"flex items-center justify-between px-3 py-2",style:{borderBottom:"1px solid #eee"},children:_jsxs("div",{className:"flex items-center gap-2",children:[_jsx("strong",{children:n}),_jsx("span",{title:s?"Loading":"Live",style:{width:8,height:8,borderRadius:999,background:s?"#aaa":"#22c55e",display:"inline-block"}})]})}),_jsx("div",{style:{overflowX:"auto"},children:_jsxs("table",{style:{borderCollapse:"collapse",width:"100%"},children:[_jsx("thead",{children:_jsxs("tr",{children:[_jsx(Th,{children:"Tag"}),_jsx(Th,{children:"Kind"}),_jsx(Th,{children:"Domain"}),_jsx(Th,{children:"Symbol"}),_jsx(Th,{children:"Display"}),_jsx(Th,{children:"Raw"}),_jsx(Th,{children:"Scale"}),_jsx(Th,{children:"Units"}),_jsx(Th,{children:"Input"}),_jsx(Th,{children:"Actions"})]})}),_jsx("tbody",{children:x.map(({tag:e,display:n,raw:t,scaleName:o,factor:a,label:s})=>{const l=d[e.fqdn]??"",i=u[e.fqdn];return _jsxs("tr",{children:[_jsx(Td,{mono:!0,children:e.tagName}),_jsx(Td,{mono:!0,children:e.valueType}),_jsx(Td,{mono:!0,children:getDomain(e.fqdn)}),_jsx(Td,{mono:!0,children:e.fqdn}),_jsx(Td,{mono:!0,children:fmt(n)}),_jsx(Td,{mono:!0,children:fmt(t)}),_jsx(Td,{mono:!0,children:o?`${o} ×${a??1}`:"—"}),_jsx(Td,{mono:!0,children:o?s??"":"—"}),_jsxs(Td,{children:[_jsx(InputForTag,{tag:e,buf:l,setBuf:n=>m(e.fqdn,n),onKeyDown:n=>((e,n)=>{"Enter"!==e.key||e.shiftKey||(e.preventDefault(),y(n))})(n,e)}),i&&_jsx("div",{style:{color:"#dc2626",marginTop:4},children:i})]}),_jsx(Td,{children:_jsxs("div",{style:{display:"flex",gap:6},children:[_jsx("button",{onClick:()=>y(e),children:"Write"}),"boolean"===e.valueType&&_jsx("button",{onClick:()=>r(e.fqdn),children:"TAP"})]})})]},e.fqdn)})})]})})]})};const Th=({children:e})=>_jsx("th",{style:{textAlign:"left",borderBottom:"1px solid #ddd",padding:"6px 8px",fontFamily:"ui-monospace, SFMono-Regular, Menlo, monospace"},children:e}),Td=({children:e,mono:n})=>_jsx("td",{style:{borderBottom:"1px solid #eee",padding:"6px 8px",whiteSpace:"nowrap",fontFamily:n?"ui-monospace, SFMono-Regular, Menlo, monospace":"inherit"},children:e}),InputForTag=({tag:e,buf:n,setBuf:t,onKeyDown:o})=>"boolean"===e.valueType?_jsxs("label",{style:{display:"inline-flex",alignItems:"center",gap:6},children:[_jsx("input",{type:"checkbox",checked:n?"true"===n:Boolean,onChange:e=>t(e.target.checked?"true":"false"),onKeyDown:o}),_jsx("span",{children:"set"})]}):"number"===e.valueType?_jsx("input",{type:"number",step:"any",value:n,onChange:e=>t(e.target.value),onKeyDown:o,style:{width:140},placeholder:"number…"}):"string"===e.valueType?_jsx("input",{type:"text",value:n,onChange:e=>t(e.target.value),onKeyDown:o,style:{width:180},placeholder:"text…"}):_jsx("textarea",{value:n,onChange:e=>t(e.target.value),onKeyDown:o,rows:2,style:{width:260,fontFamily:"ui-monospace, SFMono-Regular, Menlo, monospace"},placeholder:'{"foo": 42}'});function fmt(e){if(null==e)return"—";if("number"==typeof e)return Number.isFinite(e)?e.toString():String(e);if("string"==typeof e)return e;try{return JSON.stringify(e)}catch{return String(e)}}
@@ -1 +1 @@
1
- {"version":3,"file":"FileList.d.ts","sourceRoot":"","sources":["../../src/components/FileList.tsx"],"names":[],"mappings":"AASA;;;;;;GAMG;AAEH,OAAO,KAA0C,MAAM,OAAO,CAAC;AAW/D;;GAEG;AACH;;GAEG;AACH,KAAK,aAAa,GAAG;IAGjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAGhB,YAAY,CAAC,EAAE,OAAO,CAAC;IAIvB,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf;;;;;;;;;;;;;;;;;;;OAmBG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,SAAS,CAAC,EAAG,CAAC,OAAO,EAAC,MAAM,KAAK,IAAI,CAAC;IAEtC;;OAEG;IACH,OAAO,CAAC,EAAG,CAAC,OAAO,EAAC,MAAM,KAAK,IAAI,CAAC;CACvC,CAAA;AAWD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CA8Q5C,CAAC;AAEF,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"FileList.d.ts","sourceRoot":"","sources":["../../src/components/FileList.tsx"],"names":[],"mappings":"AASA;;;;;;GAMG;AAEH,OAAO,KAA0C,MAAM,OAAO,CAAC;AAY/D;;GAEG;AACH;;GAEG;AACH,KAAK,aAAa,GAAG;IAGjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAGhB,YAAY,CAAC,EAAE,OAAO,CAAC;IAIvB,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf;;;;;;;;;;;;;;;;;;;OAmBG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,SAAS,CAAC,EAAG,CAAC,OAAO,EAAC,MAAM,KAAK,IAAI,CAAC;IAEtC;;OAEG;IACH,OAAO,CAAC,EAAG,CAAC,OAAO,EAAC,MAAM,KAAK,IAAI,CAAC;CACvC,CAAA;AAWD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CA8Q5C,CAAC;AAEF,eAAe,QAAQ,CAAC"}
@@ -1 +1 @@
1
- import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import React,{useState,useContext,useEffect}from"react";import{DataTable}from"primereact/datatable";import{Column}from"primereact/column";import{Toolbar}from"primereact/toolbar";import{Button}from"primereact/button";import{confirmPopup}from"primereact/confirmpopup";import{FileUpload}from"primereact/fileupload";import{EventEmitterContext}from"../core/EventEmitterContext";export const FileList=({domain:e="DATASTORE",enableUpload:t=!1,subdir:o,filter:a=".json",onSuccess:n,onError:i})=>{const[r,l]=useState(0),{invoke:s}=useContext(EventEmitterContext),[c,d]=useState(),m=e=>null!==e?void 0!==o?`${o}/${e}`:e:"",p=async()=>{try{const t=void 0!==o?{subdir:o}:{};let a=await s(e,"list_files",t),n=[];for(let e=0;e<a.data.length;++e){const t=a.data[e];n.push({id:e+1,name:t})}d(n)}catch(e){i&&i(`Failed to upload file list: ${e}`)}};const u=()=>{l(e=>e+1)},f=`File Listing [/${void 0!==o?o:""}]`,x=_jsx(React.Fragment,{children:_jsx("span",{style:{fontWeight:600},children:f})}),b=_jsxs(React.Fragment,{children:[t&&_jsx(FileUpload,{customUpload:!0,auto:!0,uploadHandler:async t=>{const o=t.files[0];let a=m(o.name);const r=new FileReader;r.onload=async t=>{const r=t.target?.result,l=function c(e){let t="",o=new Uint8Array(e),a=o.byteLength;for(let e=0;e<a;e++)t+=String.fromCharCode(o[e]);return window.btoa(t)}(r);try{await s(e,"write_file",{file_name:a,value:l,options:{base64:!0}}),n&&n(`Uploaded file ${o.name}`),p()}catch(e){i&&i(`Failed to upload file: ${e}`)}u()},r.onerror=e=>{i&&i(`Error reading file: ${e}`)},r.readAsArrayBuffer(o)},accept:a,maxFileSize:25e3,mode:"basic",chooseLabel:"",chooseOptions:{icon:"pi pi-upload",className:"p-button-icon-only p-button-text p-button-rounded p-mr-2"}},r),_jsx(Button,{icon:"pi pi-refresh",onClick:()=>{p()},className:"p-button-rounded p-mr-2","aria-label":"Refresh",size:"small",rounded:!0,text:!0})]}),h=(t,o)=>{confirmPopup({target:o.currentTarget,message:`Are you want to delete file ${t.name}?\nWARNING: This cannot be undone.`,icon:"pi pi-info-circle",defaultFocus:"reject",acceptClassName:"p-button-danger",accept:()=>(async t=>{let o=m(t);try{await s(e,"delete_file",{file_name:o}),n&&n(`Deleted file: ${t}`),p()}catch(e){i&&i(`Failed to delete file: ${e}`)}p()})(t.name)})};return useEffect(()=>(p(),()=>{}),[e,t]),_jsxs("div",{children:[_jsx(Toolbar,{start:x,end:b,style:{padding:"1mm"}}),_jsxs(DataTable,{value:c,children:[_jsx(Column,{field:"name",header:"Name"}),_jsx(Column,{body:t=>_jsxs(_Fragment,{children:[_jsx(Button,{icon:"pi pi-download",onClick:()=>(async t=>{let o=m(t.name);try{await s(e,"download_file",{file_name:o}),n&&n(`Downloaded file: ${t.name}`)}catch(e){i&&i(`Failed downloading file: ${e}`)}})(t),className:"p-button-rounded p-button-success p-mr-2",style:{marginRight:"2mm"},size:"small"}),_jsx(Button,{icon:"pi pi-trash",onClick:e=>h(t,e),className:"p-button-rounded p-button-danger",size:"small"})]}),header:"Actions"})]})]})};export default FileList;
1
+ import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import React,{useState,useContext,useEffect}from"react";import{DataTable}from"primereact/datatable";import{Column}from"primereact/column";import{Toolbar}from"primereact/toolbar";import{Button}from"primereact/button";import{confirmPopup}from"primereact/confirmpopup";import{FileUpload}from"primereact/fileupload";import{EventEmitterContext}from"../core/EventEmitterContext";import{MessageType}from"../hub/CommandMessage";export const FileList=({domain:e="DATASTORE",enableUpload:t=!1,subdir:a,filter:o=".json",onSuccess:n,onError:i})=>{const[r,s]=useState(0),{invoke:l}=useContext(EventEmitterContext),[c,m]=useState(),d=e=>null!==e?void 0!==a?`${a}/${e}`:e:"",p=async()=>{try{const t=void 0!==a?{subdir:a}:{};let o=await l(`${e}.list_files`,MessageType.Request,t),n=[];for(let e=0;e<o.data.length;++e){const t=o.data[e];n.push({id:e+1,name:t})}m(n)}catch(e){i&&i(`Failed to upload file list: ${e}`)}};const u=()=>{s(e=>e+1)},f=`File Listing [/${void 0!==a?a:""}]`,b=_jsx(React.Fragment,{children:_jsx("span",{style:{fontWeight:600},children:f})}),x=_jsxs(React.Fragment,{children:[t&&_jsx(FileUpload,{customUpload:!0,auto:!0,uploadHandler:async t=>{const a=t.files[0];let o=d(a.name);const r=new FileReader;r.onload=async t=>{const r=t.target?.result,s=function c(e){let t="",a=new Uint8Array(e),o=a.byteLength;for(let e=0;e<o;e++)t+=String.fromCharCode(a[e]);return window.btoa(t)}(r);try{await l(`${e}.write_file`,MessageType.Request,{file_name:o,value:s,options:{base64:!0}}),n&&n(`Uploaded file ${a.name}`),p()}catch(e){i&&i(`Failed to upload file: ${e}`)}u()},r.onerror=e=>{i&&i(`Error reading file: ${e}`)},r.readAsArrayBuffer(a)},accept:o,maxFileSize:25e3,mode:"basic",chooseLabel:"",chooseOptions:{icon:"pi pi-upload",className:"p-button-icon-only p-button-text p-button-rounded p-mr-2"}},r),_jsx(Button,{icon:"pi pi-refresh",onClick:()=>{p()},className:"p-button-rounded p-mr-2","aria-label":"Refresh",size:"small",rounded:!0,text:!0})]}),g=(t,a)=>{confirmPopup({target:a.currentTarget,message:`Are you want to delete file ${t.name}?\nWARNING: This cannot be undone.`,icon:"pi pi-info-circle",defaultFocus:"reject",acceptClassName:"p-button-danger",accept:()=>(async t=>{let a=d(t);try{await l(`${e}.delete_file`,MessageType.Request,{file_name:a}),n&&n(`Deleted file: ${t}`),p()}catch(e){i&&i(`Failed to delete file: ${e}`)}p()})(t.name)})};return useEffect(()=>(p(),()=>{}),[e,t]),_jsxs("div",{children:[_jsx(Toolbar,{start:b,end:x,style:{padding:"1mm"}}),_jsxs(DataTable,{value:c,children:[_jsx(Column,{field:"name",header:"Name"}),_jsx(Column,{body:t=>_jsxs(_Fragment,{children:[_jsx(Button,{icon:"pi pi-download",onClick:()=>(async t=>{let a=d(t.name);try{await l(`${e}.download_file`,MessageType.Request,{file_name:a}),n&&n(`Downloaded file: ${t.name}`)}catch(e){i&&i(`Failed downloading file: ${e}`)}})(t),className:"p-button-rounded p-button-success p-mr-2",style:{marginRight:"2mm"},size:"small"}),_jsx(Button,{icon:"pi pi-trash",onClick:e=>g(t,e),className:"p-button-rounded p-button-danger",size:"small"})]}),header:"Actions"})]})]})};export default FileList;
@@ -1 +1 @@
1
- {"version":3,"file":"FileSelect.d.ts","sourceRoot":"","sources":["../../src/components/FileSelect.tsx"],"names":[],"mappings":"AAUA,OAAO,KAA0C,MAAM,OAAO,CAAC;AAO/D,KAAK,eAAe,GAAG;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;CACxB,CAAA;AAOD,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CA0FhD,CAAC;AAEF,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"FileSelect.d.ts","sourceRoot":"","sources":["../../src/components/FileSelect.tsx"],"names":[],"mappings":"AAUA,OAAO,KAA0C,MAAM,OAAO,CAAC;AAQ/D,KAAK,eAAe,GAAG;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;CACxB,CAAA;AAOD,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CA0FhD,CAAC;AAEF,eAAe,UAAU,CAAC"}
@@ -1 +1 @@
1
- import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React,{useState,useContext,useEffect}from"react";import{DataTable}from"primereact/datatable";import{Column}from"primereact/column";import{Button}from"primereact/button";import{EventEmitterContext}from"../core/EventEmitterContext";export const FileSelect=({domain:e="DATASTORE",subdir:t,filter:n,onFileSelected:l,onAccept:i,onCancel:o})=>{const{invoke:a}=useContext(EventEmitterContext),[s,c]=useState([]),[r,m]=useState(null),u=e=>{m(e),l&&l(e.name)};return useEffect(()=>{(async()=>{try{let l;l=null!=n?t?{subdir:t,options:{filter:n}}:{options:{filter:n}}:t?{subdir:t}:{};const i=(await a(e,"list_files",l)).data.map((e,t)=>({id:t+1,name:e}));c(i)}catch(e){}})()},[e,t]),_jsxs("div",{children:[_jsxs(DataTable,{value:s,selectionMode:"single",selection:r,onSelectionChange:e=>u(e.value),children:[_jsx(Column,{field:"name",header:"File Name"}),_jsx(Column,{body:e=>_jsx(Button,{label:r?.name===e.name?"Selected":"Select",icon:r?.name===e.name?"pi pi-check-circle":"pi pi-circle-off",onClick:()=>u(e),className:"p-button-rounded "+(r?.name===e.name?"p-button-success":"p-button-outlined"),"aria-label":"Select",size:"small"}),header:"Select"})]}),_jsxs("div",{style:{display:"flex",justifyContent:"flex-end",marginTop:"10px"},children:[_jsx(Button,{label:"Cancel",icon:"pi pi-times",className:"p-button-text",onClick:o}),_jsx(Button,{label:"Accept",icon:"pi pi-check",className:"p-button",onClick:()=>{void 0!==i&&null!==r&&i(null!==r?void 0!==t?`${t}/${r.name}`:r.name:"")},disabled:!r})]})]})};export default FileSelect;
1
+ import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React,{useState,useContext,useEffect}from"react";import{DataTable}from"primereact/datatable";import{Column}from"primereact/column";import{Button}from"primereact/button";import{EventEmitterContext}from"../core/EventEmitterContext";import{MessageType}from"../hub/CommandMessage";export const FileSelect=({domain:e="DATASTORE",subdir:t,filter:n,onFileSelected:l,onAccept:a,onCancel:i})=>{const{invoke:o}=useContext(EventEmitterContext),[s,c]=useState([]),[r,m]=useState(null),u=e=>{m(e),l&&l(e.name)};return useEffect(()=>{(async()=>{try{let l;l=null!=n?t?{subdir:t,options:{filter:n}}:{options:{filter:n}}:t?{subdir:t}:{};const a=(await o(`${e}.list_files`,MessageType.Request,l)).data.map((e,t)=>({id:t+1,name:e}));c(a)}catch(e){}})()},[e,t]),_jsxs("div",{children:[_jsxs(DataTable,{value:s,selectionMode:"single",selection:r,onSelectionChange:e=>u(e.value),children:[_jsx(Column,{field:"name",header:"File Name"}),_jsx(Column,{body:e=>_jsx(Button,{label:r?.name===e.name?"Selected":"Select",icon:r?.name===e.name?"pi pi-check-circle":"pi pi-circle-off",onClick:()=>u(e),className:"p-button-rounded "+(r?.name===e.name?"p-button-success":"p-button-outlined"),"aria-label":"Select",size:"small"}),header:"Select"})]}),_jsxs("div",{style:{display:"flex",justifyContent:"flex-end",marginTop:"10px"},children:[_jsx(Button,{label:"Cancel",icon:"pi pi-times",className:"p-button-text",onClick:i}),_jsx(Button,{label:"Accept",icon:"pi pi-check",className:"p-button",onClick:()=>{void 0!==a&&null!==r&&a(null!==r?void 0!==t?`${t}/${r.name}`:r.name:"")},disabled:!r})]})]})};export default FileSelect;
@@ -4,101 +4,77 @@
4
4
  * @document ../../additional-docs/AutCoreTagContext.md
5
5
  *
6
6
  * @summary
7
- * A React Context + Provider that:
8
- * - Buffers **raw** controller values for every tag (exactly as received)
9
- * - Derives **display** values from raw using current `scales` and optional tag `codec`
10
- * - Recomputes display values **from raw** whenever a scale changes (no lossy re-scaling)
11
- * - Inverse-scales on `write()` so the server always receives controller units
12
- * - Supports ADS one-shot refresh, GNV-style scale objects, and resilient eager reads
7
+ * A React Context + Provider that manages the state and synchronization of "Tags" (data points)
8
+ * between the React frontend and the AutoCore backend.
13
9
  *
14
- * @remarks
15
- * **Two representations per tag**
16
- * - `rawValues[tagName]`: last controller value as-is (pre-scale, pre-codec)
17
- * - `values[tagName]`: app-visible value derived from raw (scales/codec applied)
18
- *
19
- * ❖ **Scaling**
20
- * - Provide `scales` keyed by scale group (e.g., `"position"`, `"load"`).
21
- * - Each scale may point at a server tag (`serverTag`) that publishes an object
22
- * `{ name, scale, label }` (GNV-style). When received, the Provider recomputes
23
- * *only* affected display values **from raw**.
24
- * - Manual `updateScale(name, scale, label)` writes the object back to the server
25
- * (if `serverTag` is configured) and recomputes from raw locally.
10
+ * It acts as the central data store for real-time values, handling:
11
+ * - **Buffering**: Stores raw controller values exactly as received.
12
+ * - **Scaling**: Converts raw values to display values (e.g., mm -> inches) based on configuration.
13
+ * - **Synchronization**: Subscribes to live updates from the server.
14
+ * - **Writing**: Converts display values back to raw controller units before sending.
26
15
  *
27
- * ❖ **Lifecycle order (eagerRead = true)**
28
- * 1. Pull server scales first (so first ADS burst displays in correct units)
29
- * 2. Register ADS symbols and subscribe all domains
30
- * 3. Eager-pull non-ADS (refresh if available, else read_value)
31
- * 4. ADS `refresh` one-shot publish
16
+ * @remarks
17
+ * **Dual-State Representation**
18
+ * To prevent rounding errors and race conditions, we maintain two parallel states:
19
+ * 1. `rawValues[tagName]`: The exact value received from the controller (Source of Truth).
20
+ * 2. `values[tagName]`: The derived value shown in the UI (calculated from raw + scale).
32
21
  *
33
- * **Writes**
34
- * - `write(tagName, displayValue)` (codec?) inverse-scale → `write_value`
35
- * - `tap(tagName)` pulses booleans `true → (300ms) → false` with proper domain envelopes
22
+ * When a scale changes (e.g., user switches units), we recompute `values` from `rawValues`.
23
+ * We *never* rescale a previously scaled value.
36
24
  *
37
- * ❖ **Resilience**
38
- * - Eager reads tolerate “missing key” errors on fresh systems and keep going
39
- * - All re-scaling recomputes from **raw** to avoid cumulative precision/race issues
25
+ * ❖ **Key Features**
26
+ * - **Resilient Initialization**: Eagerly fetches initial values (via ADS refresh or read fallback).
27
+ * - **Server-Stored Scales**: Can load unit preferences from the server (GNV domain).
28
+ * - **Optimized Updates**: Uses stable references and memoization to minimize React re-renders.
29
+ * - **Type Safety**: Strongly typed context via generic `VMapRuntime`.
40
30
  *
41
31
  * @example Minimal wiring
42
32
  * ```tsx
43
- * import { AutoCoreTagProvider } from "@adcops/autocore-react/core/AutoCoreTagContext";
44
- * import type { TagConfig, ScaleConfig } from "@adcops/autocore-react/core/AutoCoreTagTypes";
45
- *
46
- * const acTagSpec = [
47
- * { tagName: "pressPosition", domain: "ADS", valueType: "number", symbolName: "AX.Press.Position", scale: "position" },
48
- * { tagName: "pressLoad", domain: "ADS", valueType: "number", symbolName: "AX.Press.Load", scale: "load" },
49
- * { tagName: "isMotorsOn", domain: "ADS", valueType: "boolean", symbolName: "GIO.isMotorsOn" },
50
- * ] as const satisfies readonly TagConfig[];
51
- *
52
- * const scales: Record<string, ScaleConfig> = {
53
- * position: {
54
- * name: "position",
55
- * scale: 1.0,
56
- * label: "mm",
57
- * serverTag: { domain: "GNV", symbolName: "position_units" }, // expects {name, scale, label}
58
- * },
59
- * load: {
60
- * name: "load",
61
- * scale: 1.0,
62
- * label: "N",
63
- * serverTag: { domain: "GNV", symbolName: "load_units" }, // expects {name, scale, label}
64
- * },
33
+ * // 1. Define your tags
34
+ * const tags = [
35
+ * { tagName: "position", fqdn: "ADS.Axis.Pos", valueType: "number", scale: "dist" },
36
+ * { tagName: "speed", fqdn: "ADS.Axis.Vel", valueType: "number", scale: "dist" }
37
+ * ];
38
+ *
39
+ * // 2. Define scales
40
+ * const scales = {
41
+ * dist: { name: "dist", scale: 1.0, label: "mm" }
65
42
  * };
66
43
  *
67
- * export function AppRoot() {
68
- * return (
69
- * <AutoCoreTagProvider tags={acTagSpec} scales={scales} eagerRead>
70
- * <App />
71
- * </AutoCoreTagProvider>
72
- * );
73
- * }
74
- * ```
75
- *
76
- * @example Consuming values with hooks
77
- * ```tsx
78
- * import { makeAutoCoreTagHooks } from "@adcops/autocore-react/hooks/useAutoCoreTag";
79
- * import { AutoCoreTagContext } from "@adcops/autocore-react/core/AutoCoreTagContext";
80
- *
81
- * export const AutoCoreHooks = makeAutoCoreTagHooks(AutoCoreTagContext, acTagSpec);
82
- *
83
- * function Dashboard() {
84
- * const { value: pos } = AutoCoreHooks.useAutoCoreTag("pressPosition"); // display units
85
- * const { value: load } = AutoCoreHooks.useAutoCoreTag("pressLoad");
86
- * const { scales, updateScale } = AutoCoreHooks.useScales();
87
- *
88
- * return (
89
- * <>
90
- * <div>Position: {pos} {scales.position.label}</div>
91
- * <div>Load: {load} {scales.load.label}</div>
92
- * <button onClick={() => updateScale("position", 1/25.4, "in")}>inches</button>
93
- * </>
94
- * );
95
- * }
44
+ * // 3. Wrap application
45
+ * <AutoCoreTagProvider tags={tags} scales={scales}>
46
+ * <App />
47
+ * </AutoCoreTagProvider>
96
48
  * ```
97
49
  */
98
50
  import React, { type ReactNode } from "react";
99
51
  import type { BaseContextValue, TagConfig, ScaleConfig } from "./AutoCoreTagTypes";
52
+ /**
53
+ * Runtime type for the values map - allows any tag name to map to any value type.
54
+ * This is the generic type used when the specific tag configuration is not known at compile time.
55
+ */
100
56
  type VMapRuntime = Record<string, unknown>;
57
+ /**
58
+ * The React Context that holds all AutoCore tag state and operations.
59
+ *
60
+ * This context provides:
61
+ * - `values`: Display values (with scaling/codecs applied)
62
+ * - `rawValues`: Raw controller values as received from server
63
+ * - `isLoading`: Whether initial data loading is complete
64
+ * - `write`: Function to write a value to a tag
65
+ * - `tap`: Function to pulse a boolean tag (true → delay → false)
66
+ * - `scales`: Current scale configurations
67
+ * - `updateScale`: Function to change a scale factor/label
68
+ *
69
+ * @see AutoCoreTagProvider for the provider implementation
70
+ * @see makeAutoCoreTagHooks for creating typed hooks from this context
71
+ */
101
72
  export declare const AutoCoreTagContext: React.Context<BaseContextValue<VMapRuntime>>;
73
+ /**
74
+ * Extracts the domain (first segment) from a Fully-Qualified Domain Name.
75
+ * @param fqdn - The full topic path (e.g., "ads.plc1.gio.bControlPowerOk")
76
+ * @returns The domain segment (e.g., "ads")
77
+ */
102
78
  /**
103
79
  * AutoCoreTagProvider
104
80
  *
@@ -108,111 +84,9 @@ export declare const AutoCoreTagContext: React.Context<BaseContextValue<VMapRunt
108
84
  * writes/taps with proper domain envelopes. Scaling is **always** applied to display
109
85
  * values only; raw values remain untouched and are the single source of truth.
110
86
  *
111
- * @props
112
- * - `tags: readonly TagConfig[]`
113
- * The full tag spec. Each tag declares `tagName`, `domain`, `symbolName`,
114
- * `valueType` ("boolean"|"number"|"string"|"json"), optional `scale` name, and
115
- * optional `codec` for JSON.
116
- *
117
- * - `scales?: Record<string, ScaleConfig>`
118
- * Map of scale groups (`position`, `load`, …). Each scale may include an optional
119
- * `serverTag` `{ domain, symbolName }`. When present, the provider reads that key
120
- * first and subscribes to updates. The server must publish a GNV-style object
121
- * `{ name, scale, label }` (stringified or object). When a new scale arrives,
122
- * the provider recomputes affected display values **from raw**.
123
- *
124
- * - `eagerRead?: boolean = true`
125
- * If true, the provider performs a non-ADS eager fetch pass (refresh if available,
126
- * otherwise read_value with backoff) and then performs a single ADS `refresh`.
127
- * Missing keys are common on clean systems—these are logged and skipped.
128
- *
129
- * - `children: ReactNode`
130
- * Your app subtree that consumes `AutoCoreTagContext`.
131
- *
132
- * @context value
133
- * - `values`: Partial<Record<tagName, unknown>> — app-visible (scaled/decoded)
134
- * - `rawValues`: Record<tagName, unknown> — last controller values as received
135
- * - `isLoading`: boolean — true until initial wiring completes
136
- * - `write(tagName, displayValue)`: Promise<void>
137
- * Serializes/encodes JSON if needed and inverse-scales numbers back to raw units.
138
- * Dispatches `write_value` with appropriate domain envelope:
139
- * - ADS: `{ symbol_name, value }`
140
- * - GNV: `{ group:"ux", key, value }`
141
- * - Other: `{ key, value }`
142
- * - `tap(tagName)`: Promise<void>
143
- * For boolean tags only. Pulses true → 300ms → false with the proper envelope.
144
- * - `scales`: Record<string, ScaleConfig> — current factors/labels
145
- * - `updateScale(name, scale, label)`: Promise<void>
146
- * Writes `{ name, scale, label }` to the configured `serverTag` (if present) and
147
- * recomputes display values **from raw** locally.
148
- *
149
- * @example With server-driven scales (GNV) and ADS data
150
- * ```tsx
151
- * const tags: readonly TagConfig[] = [
152
- * { tagName: "pressPosition", domain: "ADS", valueType: "number", symbolName: "AX.Press.Pos", scale: "position" },
153
- * { tagName: "pressLoad", domain: "ADS", valueType: "number", symbolName: "AX.Press.Load", scale: "load" },
154
- * { tagName: "isMotorsOn", domain: "ADS", valueType: "boolean", symbolName: "GIO.isMotorsOn" },
155
- * // JSON with codec example
156
- * { tagName: "jobMeta", domain: "GNV", valueType: "json", symbolName: "job_meta",
157
- * codec: {
158
- * fromServer: (raw) => (typeof raw === "string" ? JSON.parse(raw) : raw),
159
- * toServer: (val) => JSON.stringify(val),
160
- * }
161
- * },
162
- * ] as const;
163
- *
164
- * const scales: Record<string, ScaleConfig> = {
165
- * position: {
166
- * name: "position",
167
- * scale: 1, label: "mm",
168
- * serverTag: { domain: "GNV", symbolName: "position_units" } // expects {name, scale, label}
169
- * },
170
- * load: {
171
- * name: "load",
172
- * scale: 1, label: "N",
173
- * serverTag: { domain: "GNV", symbolName: "load_units" } // expects {name, scale, label}
174
- * }
175
- * };
176
- *
177
- * <AutoCoreTagProvider tags={tags} scales={scales} eagerRead>
178
- * <YourApp/>
179
- * </AutoCoreTagProvider>
180
- * ```
181
- *
182
- * @example Reading values, raw vs display, and writing
183
- * ```tsx
184
- * import { makeAutoCoreTagHooks } from "../hooks/useAutoCoreTag";
185
- * import { AutoCoreTagContext } from "../core/AutoCoreTagContext";
186
- *
187
- * const Hooks = makeAutoCoreTagHooks(AutoCoreTagContext, tags);
188
- *
189
- * function Status() {
190
- * const { value: pos, isLoading } = Hooks.useAutoCoreTag("pressPosition"); // scaled
191
- * const { value: rawPos } = (() => {
192
- * // access raw via context when needed for debugging
193
- * const ctx = React.useContext(AutoCoreTagContext);
194
- * return { value: ctx.rawValues["pressPosition"] };
195
- * })();
196
- *
197
- * const { scales, updateScale } = Hooks.useScales();
198
- *
199
- * return (
200
- * <>
201
- * <div>Pos: {pos} {scales.position.label} (raw: {String(rawPos)})</div>
202
- * <button onClick={() => updateScale("position", 1/25.4, "in")}>inches</button>
203
- * </>
204
- * );
205
- * }
206
- * ```
207
- *
208
- * @example Tapping booleans and writing numbers in display units
209
- * ```tsx
210
- * const { tap } = Hooks.useAutoCoreTag("isMotorsOn");
211
- * const { write } = Hooks.useAutoCoreTag("pressPosition");
212
- *
213
- * <button onClick={() => tap()}>Motors TAP</button>
214
- * <button onClick={() => write(10.0)}>Jog to 10 (display units)</button>
215
- * ```
87
+ * @param props.tags - List of tag configurations (tagName, fqdn, etc.)
88
+ * @param props.scales - Map of scale definitions (name, factor, label)
89
+ * @param props.eagerRead - If true, automatically fetches initial values on mount
216
90
  */
217
91
  export declare const AutoCoreTagProvider: React.FC<{
218
92
  children: ReactNode;
@@ -1 +1 @@
1
- {"version":3,"file":"AutoCoreTagContext.d.ts","sourceRoot":"","sources":["../../src/core/AutoCoreTagContext.tsx"],"names":[],"mappings":"AASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgGG;AAGH,OAAO,KAAK,EAAE,EAQV,KAAK,SAAS,EACjB,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EACR,gBAAgB,EAChB,SAAS,EACT,WAAW,EACd,MAAM,oBAAoB,CAAC;AAE5B,KAAK,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE3C,eAAO,MAAM,kBAAkB,8CAQ7B,CAAC;AAQH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkHG;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;CACvB,CAkbA,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,EACd,MAAM,oBAAoB,CAAC;AAI5B;;;GAGG;AACH,KAAK,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE3C;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,kBAAkB,8CAQ7B,CAAC;AAsBH;;;;GAIG;AAIH;;;;;;;;;;;;GAYG;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;CACvB,CA0cA,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";export const AutoCoreTagContext=createContext({values:{},rawValues:{},isLoading:!0,write:async()=>{},tap:async()=>{},scales:{},updateScale:async()=>{}});const sleep=e=>new Promise(t=>setTimeout(t,e));export const AutoCoreTagProvider=({children:e,tags:t,scales:a={},eagerRead:s=!0})=>{const o=useRef(!1),{invoke:n,isConnected:r,subscribe:c,unsubscribe:l}=useContext(EventEmitterContext),[u,i]=useState(()=>{const e={};for(const a of t)void 0!==a.initialValue&&(e[a.tagName]=a.initialValue);return e}),[m,f]=useState({}),[y,b]=useState(a),p=useRef(y),v=useRef(u);useEffect(()=>{p.current=y},[y]),useEffect(()=>{v.current=u},[u]);const[g,d]=useState(!0),N=useCallback((e,t)=>{const{valueType:a,scale:s,codec:o}=e;if("number"===a&&"number"==typeof t&&s){const e=p.current[s];return t*(e?.scale??1)}if("json"===a&&o?.fromServer)try{return o.fromServer(t)}catch{}return t},[]),C=useCallback((e,t)=>{const{valueType:a,scale:s,codec:o}=e;if("json"===a&&o?.toServer)try{t=o.toServer(t)}catch{}if("number"===a&&"number"==typeof t&&s){const e=p.current[s];return t/(e?.scale??1)}return t},[]),w=useCallback(e=>{const a=t.filter(t=>t.scale===e);a.length&&f(e=>{const t={...e};for(const e of a){const a=v.current[e.tagName];if("number"!=typeof a)continue;const s=N(e,a);t[e.tagName]!==s&&(t[e.tagName]=s)}return t})},[t,N]),h=useCallback((e,t)=>{i(a=>a[e.tagName]===t?a:{...a,[e.tagName]:t});const a=N(e,t);f(t=>t[e.tagName]===a?t:{...t,[e.tagName]:a})},[N]),x=useCallback(async(e,t,a)=>{const s=a?.concurrency??4,o=a?.minDelayMs??20,r=a?.jitterMs??40;let c=0;const l=Array.from({length:s},()=>(async()=>{for(;;){const a=c++;if(a>=t.length)return;const s=t[a];try{let t=!1;try{await n(e,"refresh",{topic:s.symbolName}),t=!0}catch{}if(!t){const t="GNV"===e.toUpperCase()?{group:"ux",key:s.symbolName}:{key:s.symbolName};s.options&&(t.options=s.options);try{const a=await n(e,"read_value",t);a?.success&&a?.valid&&h(s,a.data)}catch(e){}}}catch(e){}finally{const e=Math.floor(Math.random()*r);await sleep(o+e)}}})());await Promise.all(l)},[n,h]),k=useCallback(async()=>{for(const[e,t]of Object.entries(a)){if(!t.serverTag)continue;const{domain:a,symbolName:s}=t.serverTag;try{const t=await n(a,"read_value",{group:"ux",key:s});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;b(a=>({...a,[e]:{...a[e],scale:t,label:s??a[e]?.label??"---"}})),w(e)}}}catch{}}},[n,a,w]);useEffect(()=>{let e=!0;const a=[],u=async()=>{if(e&&!o.current){o.current=!0;try{await(async()=>{const o=new Map;for(const e of t){const t=o.get(e.domain);t?t.push(e):o.set(e.domain,[e])}try{await k();for(const[t,r]of o.entries()){if("ADS"===t.toUpperCase())for(const e of r)try{const t=e.options?{symbol_name:e.symbolName,options:e.options}:{symbol_name:e.symbolName};await n("ADS","register_symbol",t)}catch(e){}for(const s of r){const o=c(`${t}/${s.symbolName}`,t=>{e&&h(s,t?.value)});a.push(o)}s&&"ADS"!==t.toUpperCase()&&await x(t,r,{concurrency:4,minDelayMs:20,jitterMs:40})}s&&await n("ADS","refresh",{})}finally{e&&setTimeout(()=>e&&d(!1),100)}})()}finally{e&&setTimeout(()=>e&&d(!1),100)}}};if(r())u();else{const e=c("HUB/connected",()=>{l(e),u()});a.push(e)}return()=>{e=!1,a.forEach(l),o.current=!1}},[c,l,r,n,s,t,k,x,h]);const S=useMemo(()=>Object.entries(a).filter(([,e])=>e.serverTag).map(([e,t])=>({scaleName:e,domain:t.serverTag.domain,symbolName:t.serverTag.symbolName})),[a]);useEffect(()=>{let e=!0;const t=[];for(const{scaleName:a,domain:s,symbolName:o}of S){const n=c(`${s}/${o}`,t=>{if(!e)return;const s=t?.value;if(s&&"object"==typeof s&&"number"==typeof s.scale){const{scale:e,label:t}=s;b(s=>({...s,[a]:{...s[a],scale:e,label:t??s[a]?.label??"---"}})),w(a)}});t.push(n)}return()=>{e=!1,t.forEach(l)}},[c,l,S,w]);const T=useCallback(async(e,a)=>{const s=t.find(t=>t.tagName===e);if(!s)return;const o=C(s,a);let r;const c=s.domain.toUpperCase();r="ADS"===c?{symbol_name:s.symbolName,value:o}:"GNV"===c?{group:"ux",key:s.symbolName,value:o}:{key:s.symbolName,value:o},await n(s.domain,"write_value",r)},[t,n,C]),E=useCallback(async e=>{const a=t.find(t=>t.tagName===e);if(!a)return;if("boolean"!==a.valueType)return;const s=a.domain.toUpperCase(),o=e=>"ADS"===s?{symbol_name:a.symbolName,value:e}:"GNV"===s?{group:"ux",key:a.symbolName,value:e}:{key:a.symbolName,value:e};await n(a.domain,"write_value",o(!0)),await sleep(300),await n(a.domain,"write_value",o(!1))},[t,n]),_=useCallback(async(e,t,a)=>{const s=y[e];s&&(s.serverTag&&await n(s.serverTag.domain,"write_value",{group:"ux",key:s.serverTag.symbolName,value:{name:e,scale:t,label:a}}),b(s=>({...s,[e]:{...s[e],scale:t,label:a}})),w(e))},[y,n,w]);useEffect(()=>{f(e=>{const a={...e};for(const e of t){const t=v.current[e.tagName];if(void 0===t)continue;const s=N(e,t);a[e.tagName]!==s&&(a[e.tagName]=s)}return a})},[t,N,y]);const j=useMemo(()=>({values:m,rawValues:u,isLoading:g,write:T,tap:E,scales:y,updateScale:_}),[m,u,g,T,E,y,_]);return _jsx(AutoCoreTagContext.Provider,{value:j,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";export const AutoCoreTagContext=createContext({values:{},rawValues:{},isLoading:!0,write:async()=>{},tap:async()=>{},scales:{},updateScale:async()=>{}});const sleep=e=>new Promise(t=>setTimeout(t,e));export const AutoCoreTagProvider=({children:e,tags:t,scales:a,eagerRead:s=!0})=>{const n=useRef(!1),r=useMemo(()=>({}),[]),c=a??r,{invoke:o,read:l,write:u,serverSubscribe:i,isConnected:f,subscribe:m,unsubscribe:b}=useContext(EventEmitterContext),[y,g]=useState(()=>{const e={};for(const a of t)void 0!==a.initialValue&&(e[a.tagName]=a.initialValue);return e}),[d,p]=useState({}),[v,C]=useState(c),N=useRef(v),h=useRef(y);useEffect(()=>{N.current=v},[v]),useEffect(()=>{h.current=y},[y]);const[w,T]=useState(!0),x=useCallback((e,t)=>{const{valueType:a,scale:s,codec:n}=e;if("number"===a&&"number"==typeof t&&s){const e=N.current[s];return t*(e?.scale??1)}if("json"===a&&n?.fromServer)try{return n.fromServer(t)}catch{}return t},[]),E=useCallback((e,t)=>{const{valueType:a,scale:s,codec:n}=e;if("json"===a&&n?.toServer)try{t=n.toServer(t)}catch{}if("number"===a&&"number"==typeof t&&s){const e=N.current[s];return t/(e?.scale??1)}return t},[]),S=useCallback(e=>{const a=t.filter(t=>t.scale===e);a.length&&p(e=>{const t={...e};for(const e of a){const a=h.current[e.tagName];if("number"!=typeof a)continue;const s=x(e,a);t[e.tagName]!==s&&(t[e.tagName]=s)}return t})},[t,x]),k=useCallback((e,t)=>{g(a=>a[e.tagName]===t?a:{...a,[e.tagName]:t});const a=x(e,t);p(t=>t[e.tagName]===a?t:{...t,[e.tagName]:a})},[x]),M=useCallback(async(e,t,a)=>{const s=a?.concurrency??4,n=a?.minDelayMs??20,r=a?.jitterMs??40;let c=0;const u=Array.from({length:s},()=>(async()=>{for(;;){const a=c++;if(a>=t.length)return;const s=t[a];try{let t=!1;try{await o(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&&k(s,e.data)}catch(e){}}}catch(e){}finally{const e=Math.floor(Math.random()*r);await sleep(n+e)}}})());await Promise.all(u)},[o,l,k]),j=useCallback(async()=>{for(const[e,t]of Object.entries(c)){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;C(a=>({...a,[e]:{...a[e],scale:t,label:s??a[e]?.label??"---"}})),S(e)}}}catch{}}},[l,c,S]);useEffect(()=>{let e=!0;const a=[],s=async()=>{if(e&&!n.current){n.current=!0;try{await(async()=>{try{await j();for(const s of t){await i(s.tagName,s.fqdn,s.subscriptionOptions);const t=m(s.tagName,t=>{e&&k(s,t)});a.push(t)}}finally{e&&setTimeout(()=>e&&T(!1),100)}})()}finally{e&&setTimeout(()=>e&&T(!1),100)}}};if(f())s();else{const e=m("HUB/connected",()=>{b(e),s()});a.push(e)}return()=>{e=!1,a.forEach(b),n.current=!1}},[m,b,f,o,i,s,t,j,M,k]);const q=useMemo(()=>Object.entries(c).filter(([,e])=>e.serverTag).map(([e,t])=>({scaleName:e,domain:t.serverTag.domain,symbolName:t.serverTag.symbolName})),[c]);useEffect(()=>{let e=!0;const t=[];for(const{scaleName:a,domain:s,symbolName:n}of q){const r=m(`${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;C(s=>({...s,[a]:{...s[a],scale:e,label:t??s[a]?.label??"---"}})),S(a)}});t.push(r)}return()=>{e=!1,t.forEach(b)}},[m,b,q,S]);const R=useCallback(async(e,a)=>{const s=t.find(t=>t.tagName===e);if(!s)return;const n=E(s,a);await u(s.fqdn,n)},[t,u,E]),$=useCallback(async e=>{const a=t.find(t=>t.tagName===e);a&&"boolean"===a.valueType&&(await u(a.fqdn,!0),await sleep(300),await u(a.fqdn,!1))},[t,u]),V=useCallback(async(e,t,a)=>{const s=v[e];if(s){if(s.serverTag){const n=`${s.serverTag.domain}.${s.serverTag.symbolName}`;await u(n,{name:e,scale:t,label:a})}C(s=>({...s,[e]:{...s[e],scale:t,label:a}})),S(e)}},[v,u,S]);useEffect(()=>{p(e=>{const a={...e};for(const e of t){const t=h.current[e.tagName];if(void 0===t)continue;const s=x(e,t);a[e.tagName]!==s&&(a[e.tagName]=s)}return a})},[t,x,v]);const A=useMemo(()=>({values:d,rawValues:y,isLoading:w,write:R,tap:$,scales:v,updateScale:V}),[d,y,w,R,$,v,V]);return _jsx(AutoCoreTagContext.Provider,{value:A,children:e})};