@qoretechnologies/reqraft 0.10.10 → 0.10.12

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 (41) hide show
  1. package/dist/providers/StorageProvider.d.ts.map +1 -1
  2. package/dist/providers/StorageProvider.js +14 -4
  3. package/dist/providers/StorageProvider.js.map +1 -1
  4. package/package.json +1 -1
  5. package/src/components/dpqlEditor/DpqlEditor.stories.tsx +74 -2
  6. package/src/components/form/engine/FormEngine.stories.tsx +654 -32
  7. package/src/components/form/engine/FormEngineRemote.stories.tsx +48 -0
  8. package/src/components/form/engine/_structuredData/StructuredDataView.stories.tsx +8 -0
  9. package/src/components/form/engine/variants/FormEngineVariants.stories.tsx +40 -0
  10. package/src/components/form/expressions/ExpressionField.stories.tsx +74 -2
  11. package/src/components/form/expressions/builder/ExpressionBuilder.stories.tsx +187 -0
  12. package/src/components/form/fields/Field.stories.tsx +40 -0
  13. package/src/components/form/fields/array/ArrayAutoField.stories.tsx +64 -0
  14. package/src/components/form/fields/auto/AutoFormField.stories.tsx +136 -0
  15. package/src/components/form/fields/binary/Binary.stories.tsx +32 -0
  16. package/src/components/form/fields/boolean/Boolean.stories.tsx +24 -0
  17. package/src/components/form/fields/byte-size/ByteSize.stories.tsx +24 -0
  18. package/src/components/form/fields/color/Color.stories.tsx +30 -0
  19. package/src/components/form/fields/cron/Cron.stories.tsx +8 -0
  20. package/src/components/form/fields/date/Date.stories.tsx +22 -0
  21. package/src/components/form/fields/file/File.stories.tsx +48 -0
  22. package/src/components/form/fields/long-string/LongString.stories.tsx +24 -0
  23. package/src/components/form/fields/markdown/Markdown.stories.tsx +8 -0
  24. package/src/components/form/fields/number/Number.stories.tsx +31 -0
  25. package/src/components/form/fields/object/Object.stories.tsx +88 -0
  26. package/src/components/form/fields/radio-group/RadioGroup.stories.tsx +24 -0
  27. package/src/components/form/fields/rich-text/RichText.stories.tsx +23 -0
  28. package/src/components/form/fields/schema-definition/SchemaDefinitionField.stories.tsx +72 -0
  29. package/src/components/form/fields/select/Select.stories.tsx +104 -0
  30. package/src/components/form/fields/string/String.stories.tsx +16 -0
  31. package/src/components/form/fields/template/TemplateField.stories.tsx +160 -0
  32. package/src/components/form/fields/url/Url.stories.tsx +24 -0
  33. package/src/components/log/Log.stories.tsx +96 -0
  34. package/src/components/menu/Menu.stories.tsx +54 -0
  35. package/src/components/qonsoleSmartInput/QonsoleSmartInput.stories.tsx +14 -0
  36. package/src/components/smartEditor/SmartEditor.stories.tsx +32 -0
  37. package/src/hooks/useFetch/useFetch.stories.tsx +30 -0
  38. package/src/hooks/useStorage/useStorage.stories.tsx +82 -0
  39. package/src/hooks/useWebSocket/useWebsocket.stories.tsx +127 -1
  40. package/src/providers/StorageProvider.tsx +12 -4
  41. package/src/stores/currentUser/currentUser.stories.tsx +17 -0
@@ -106,8 +106,25 @@ const meta = {
106
106
  export default meta;
107
107
  export type Story = StoryObj<typeof meta>;
108
108
 
109
- export const Default: Story = {};
109
+ export const Default: Story = {
110
+ parameters: {
111
+ docs: {
112
+ description: {
113
+ story:
114
+ 'Renders the useReqraftWebSocket demo with no lifecycle options — the socket stays CLOSED until the operator clicks Connect.',
115
+ },
116
+ },
117
+ },
118
+ };
110
119
  export const OpenManually: Story = {
120
+ parameters: {
121
+ docs: {
122
+ description: {
123
+ story:
124
+ 'Renders the useReqraftWebSocket demo and clicks the Connect action — the socket opens and the onOpen callback fires.',
125
+ },
126
+ },
127
+ },
111
128
  play: async ({ args }) => {
112
129
  await testsClickButton({ label: 'Connect' });
113
130
  await testsWaitForText('Websocket Status: OPEN');
@@ -118,6 +135,14 @@ export const OpenOnMount: Story = {
118
135
  args: {
119
136
  openOnMount: true,
120
137
  },
138
+ parameters: {
139
+ docs: {
140
+ description: {
141
+ story:
142
+ 'Renders the useReqraftWebSocket demo with openOnMount enabled — the socket opens immediately after mount without any user action.',
143
+ },
144
+ },
145
+ },
121
146
  play: async ({ args }) => {
122
147
  await testsWaitForText('Websocket Status: OPEN');
123
148
  await expect(args.onOpen).toHaveBeenCalled();
@@ -126,6 +151,15 @@ export const OpenOnMount: Story = {
126
151
 
127
152
  export const CloseManually: Story = {
128
153
  ...OpenOnMount,
154
+ parameters: {
155
+ ...OpenOnMount.parameters,
156
+ docs: {
157
+ description: {
158
+ story:
159
+ 'Renders the useReqraftWebSocket demo opened on mount. When Disconnect is clicked, the socket transitions to CLOSED and the onClose callback fires.',
160
+ },
161
+ },
162
+ },
129
163
  play: async ({ args, ...rest }) => {
130
164
  await OpenOnMount.play({ args, ...rest });
131
165
  await testsClickButton({ label: 'Disconnect' });
@@ -141,6 +175,14 @@ export const Reconnects: Story = {
141
175
  maxReconnectTries: 5,
142
176
  openOnMount: true,
143
177
  },
178
+ parameters: {
179
+ docs: {
180
+ description: {
181
+ story:
182
+ 'Renders the useReqraftWebSocket demo with reconnect enabled. When the server is killed, the socket transitions to CONNECTING and then back to OPEN once the server returns.',
183
+ },
184
+ },
185
+ },
144
186
  play: async ({ args, ...rest }) => {
145
187
  await OpenOnMount.play({ args, ...rest });
146
188
  await testsClickButton({ label: 'Kill' });
@@ -159,6 +201,12 @@ export const ReconnectFails: Story = {
159
201
  reconnectInterval: 500,
160
202
  },
161
203
  parameters: {
204
+ docs: {
205
+ description: {
206
+ story:
207
+ 'Renders the useReqraftWebSocket demo with a low maxReconnectTries. When the server never returns, the socket exhausts its reconnect attempts and fires onReconnectFailed.',
208
+ },
209
+ },
162
210
  jest: {
163
211
  timeout: 60000,
164
212
  },
@@ -178,6 +226,14 @@ export const SendMessage: Story = {
178
226
  includeSentMessagesInState: true,
179
227
  useState: true,
180
228
  },
229
+ parameters: {
230
+ docs: {
231
+ description: {
232
+ story:
233
+ 'Renders the useReqraftWebSocket demo with useState enabled. When Send is clicked, the message is dispatched and the echoed reply appears in the accumulated message list.',
234
+ },
235
+ },
236
+ },
181
237
  play: async ({ args, ...rest }) => {
182
238
  await OpenOnMount.play({ args, ...rest });
183
239
  await testsClickButton({ label: 'Send' });
@@ -197,6 +253,14 @@ export const WithLogs: Story = {
197
253
  useState: true,
198
254
  reconnectInterval: 1500,
199
255
  },
256
+ parameters: {
257
+ docs: {
258
+ description: {
259
+ story:
260
+ 'Renders the useReqraftWebSocket demo with includeLogMessagesInState. Connect / disconnect / reconnect lifecycle events are captured as log entries alongside regular messages.',
261
+ },
262
+ },
263
+ },
200
264
  play: async ({ args, ...rest }) => {
201
265
  await Reconnects.play({ args, ...rest });
202
266
 
@@ -206,6 +270,15 @@ export const WithLogs: Story = {
206
270
 
207
271
  export const ClearsMessages: Story = {
208
272
  ...SendMessage,
273
+ parameters: {
274
+ ...SendMessage.parameters,
275
+ docs: {
276
+ description: {
277
+ story:
278
+ 'Renders the useReqraftWebSocket demo after sending a message. When Clear is clicked, the accumulated message list is emptied.',
279
+ },
280
+ },
281
+ },
209
282
  play: async ({ args, ...rest }) => {
210
283
  await SendMessage.play({ args, ...rest });
211
284
  await testsClickButton({ label: 'Clear' });
@@ -353,6 +426,14 @@ export const MultipleConnections: Story = {
353
426
  includeLogMessagesInState: true,
354
427
  useState: true,
355
428
  },
429
+ parameters: {
430
+ docs: {
431
+ description: {
432
+ story:
433
+ 'Renders three panels that each call useReqraftWebSocket against the same URL — proves the connections share one pooled underlying WebSocket while keeping independent message state.',
434
+ },
435
+ },
436
+ },
356
437
  // @ts-expect-error customprops
357
438
  render: (args: IUseReqraftWebSocketOptions) => {
358
439
  const [conectionStatus, setConnectionStatus] = useState<string>('CLOSED');
@@ -405,6 +486,15 @@ export const MultipleConnectionsOpenOnMount: Story = {
405
486
  ...MultipleConnections.args,
406
487
  openOnMount: true,
407
488
  },
489
+ parameters: {
490
+ ...MultipleConnections.parameters,
491
+ docs: {
492
+ description: {
493
+ story:
494
+ 'Renders three pooled useReqraftWebSocket panels with openOnMount — all three transition to OPEN over the shared underlying socket without any user action.',
495
+ },
496
+ },
497
+ },
408
498
  play: async ({ args }) => {
409
499
  await testsWaitForText('First Connection Status: OPEN');
410
500
  await testsWaitForText('Second Connection Status: OPEN');
@@ -420,6 +510,15 @@ export const MultipleConnectionsClosedAtOnce: Story = {
420
510
  ...MultipleConnections.args,
421
511
  openOnMount: true,
422
512
  },
513
+ parameters: {
514
+ ...MultipleConnections.parameters,
515
+ docs: {
516
+ description: {
517
+ story:
518
+ 'Renders three pooled useReqraftWebSocket panels. When Close All closes the shared socket, every consumer transitions to CLOSED at once and each panel logs its close handler.',
519
+ },
520
+ },
521
+ },
423
522
  play: async (args) => {
424
523
  await MultipleConnectionsOpenOnMount.play(args);
425
524
 
@@ -436,6 +535,15 @@ export const ConnectionIsClosedWhenAllUsersAreClosed: Story = {
436
535
  ...MultipleConnections.args,
437
536
  openOnMount: true,
438
537
  },
538
+ parameters: {
539
+ ...MultipleConnections.parameters,
540
+ docs: {
541
+ description: {
542
+ story:
543
+ 'Renders three pooled useReqraftWebSocket panels. Closing them one by one keeps the shared socket OPEN until the last consumer unmounts, then it closes.',
544
+ },
545
+ },
546
+ },
439
547
  play: async (args) => {
440
548
  await MultipleConnectionsOpenOnMount.play(args);
441
549
 
@@ -454,6 +562,15 @@ export const MultipleConnectionsHaveCustomHandlers: Story = {
454
562
  ...MultipleConnections.args,
455
563
  openOnMount: true,
456
564
  },
565
+ parameters: {
566
+ ...MultipleConnections.parameters,
567
+ docs: {
568
+ description: {
569
+ story:
570
+ 'Renders three pooled useReqraftWebSocket panels. Each panel attaches its own message handler, and sending a message triggers the handlers of only the connections still open.',
571
+ },
572
+ },
573
+ },
457
574
  play: async (args) => {
458
575
  const canvas = within(args.canvasElement);
459
576
 
@@ -480,6 +597,15 @@ export const MultipleConnectionsHaveCustomHandlers: Story = {
480
597
 
481
598
  export const MultipleConnectionsCanBeDisconnectedAndReconnected: Story = {
482
599
  ...MultipleConnectionsHaveCustomHandlers,
600
+ parameters: {
601
+ ...MultipleConnectionsHaveCustomHandlers.parameters,
602
+ docs: {
603
+ description: {
604
+ story:
605
+ 'Renders three pooled useReqraftWebSocket panels after custom handlers have fired. Disconnecting one and reconnecting another proves individual consumers can toggle without disturbing peers.',
606
+ },
607
+ },
608
+ },
483
609
  play: async (args) => {
484
610
  await MultipleConnectionsHaveCustomHandlers.play(args);
485
611
 
@@ -53,26 +53,34 @@ export const ReqraftUserProvider = ({ children, waitForStorage }: IReqraftStorag
53
53
  includeAppPrefix: boolean = true
54
54
  ) {
55
55
  const _path = includeAppPrefix ? `${appName}.${path}` : path;
56
- const updatedStorage = set(cloneDeep(currentUser?.storage), _path, value);
56
+ // Base the write on the LATEST storage read straight from the store, not
57
+ // the blob captured in this callback's closure. A caller holding a stale
58
+ // updater — e.g. an imperative store subscription created on mount, before
59
+ // other keys had loaded — would otherwise persist an out-of-date blob and
60
+ // wipe every key written to storage since its closure was captured.
61
+ const latestStorage = currentUserStore.getState().currentUser?.storage;
62
+ const updatedStorage = set(cloneDeep(latestStorage), _path, value);
57
63
 
58
64
  updateCurrentUserStorage(updatedStorage);
59
65
 
60
66
  load({ body: { storage: updatedStorage } });
61
67
  },
62
- [appName, currentUser?.storage, load, updateCurrentUserStorage]
68
+ [appName, load, updateCurrentUserStorage]
63
69
  );
64
70
 
65
71
  const removeStorageValue = useCallback(
66
72
  function (path: string, includeAppPrefix: boolean = true) {
67
73
  const _path = includeAppPrefix ? `${appName}.${path}` : path;
68
74
 
69
- const updatedStorage = set(cloneDeep(currentUser?.storage), _path, null);
75
+ // Same as `updateStorage`: mutate the latest blob, never a stale closure copy.
76
+ const latestStorage = currentUserStore.getState().currentUser?.storage;
77
+ const updatedStorage = set(cloneDeep(latestStorage), _path, null);
70
78
 
71
79
  updateCurrentUserStorage(updatedStorage);
72
80
 
73
81
  load({ body: { storage_path: _path } });
74
82
  },
75
- [appName, currentUser?.storage, load, updateCurrentUserStorage]
83
+ [appName, load, updateCurrentUserStorage]
76
84
  );
77
85
 
78
86
  const contextValue = useMemo(
@@ -26,6 +26,14 @@ export default meta;
26
26
  export type Story = StoryObj<typeof meta>;
27
27
 
28
28
  export const CurrentUserCanBeLoaded: Story = {
29
+ parameters: {
30
+ docs: {
31
+ description: {
32
+ story:
33
+ 'Renders a demo that reads currentUserStore — the store loads /users?action=current and the returned user object is displayed as a tree.',
34
+ },
35
+ },
36
+ },
29
37
  play: async () => {
30
38
  await testsWaitForText('"David Nichols"');
31
39
  },
@@ -33,6 +41,15 @@ export const CurrentUserCanBeLoaded: Story = {
33
41
 
34
42
  export const CurrentUserHasPermissions: Story = {
35
43
  ...CurrentUserCanBeLoaded,
44
+ parameters: {
45
+ ...CurrentUserCanBeLoaded.parameters,
46
+ docs: {
47
+ description: {
48
+ story:
49
+ 'Renders a demo that calls currentUserStore().hasAnyPermission — the affirmative message renders because the loaded user carries at least one of the requested permissions.',
50
+ },
51
+ },
52
+ },
36
53
  render: () => {
37
54
  const { hasAnyPermission } = currentUserStore();
38
55