@arquimedes.co/eureka-forms 3.0.47-test → 3.0.48-test

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 (61) hide show
  1. package/dist/@Types/Condition.d.ts +6 -4
  2. package/dist/@Types/ErkValue.d.ts +16 -0
  3. package/dist/@Types/ErkValue.js +1 -0
  4. package/dist/@Types/Form.d.ts +1 -0
  5. package/dist/@Types/FormStep.d.ts +8 -1
  6. package/dist/@Types/User.d.ts +13 -0
  7. package/dist/@Types/User.js +1 -0
  8. package/dist/App/App.js +1 -1
  9. package/dist/App/AppFunctions.js +8 -3
  10. package/dist/App/AppHooks.js +20 -1
  11. package/dist/Form/Form.js +6 -2
  12. package/dist/Form/Form.module.css +48 -39
  13. package/dist/FormSteps/ApiSelectorStep/MaterialApiSelectorStep/MaterialApiSelectorStep.js +8 -4
  14. package/dist/FormSteps/CBRStepMapper.js +1 -1
  15. package/dist/FormSteps/ClassifierSelectorStep/MaterialClassifierSelectorStep/MaterialClassifierSelectorStep.js +2 -2
  16. package/dist/FormSteps/EntityValueStep/MaterialEntityValuePickerStep/MaterialEntityValuePickerStep.js +52 -4
  17. package/dist/FormSteps/StepFunctions.js +6 -9
  18. package/dist/FormSteps/StepFunctions.test.js +3 -3
  19. package/dist/FormSteps/TitleStep/MaterialTitleStep/MaterialTitleStep.js +2 -1
  20. package/dist/Icons/EmailIcon.d.ts +3 -0
  21. package/dist/Icons/EmailIcon.js +7 -0
  22. package/dist/Icons/Entities/SchoolIcon.d.ts +3 -0
  23. package/dist/Icons/Entities/SchoolIcon.js +7 -0
  24. package/dist/Icons/GroupIcon.d.ts +3 -0
  25. package/dist/Icons/GroupIcon.js +7 -0
  26. package/dist/Icons/LockedIcon.d.ts +3 -0
  27. package/dist/Icons/LockedIcon.js +7 -0
  28. package/dist/Login/Login.module.css +135 -0
  29. package/dist/Login/LoginLayout.module.css +68 -0
  30. package/dist/Login/LoginPage.d.ts +10 -0
  31. package/dist/Login/LoginPage.js +101 -0
  32. package/dist/Login/LoginTextField.d.ts +14 -0
  33. package/dist/Login/LoginTextField.js +29 -0
  34. package/dist/Services/ApiSelectorService.d.ts +366 -0
  35. package/dist/Services/ApiSelectorService.js +173 -0
  36. package/dist/Services/ApiSelectorService.test.d.ts +1 -0
  37. package/dist/Services/ApiSelectorService.test.js +87 -0
  38. package/dist/Services/DraftService.js +4 -1
  39. package/dist/Services/IntegrationService.d.ts +21 -0
  40. package/dist/Services/IntegrationService.js +22 -0
  41. package/dist/Services/UserService.d.ts +10 -0
  42. package/dist/Services/UserService.js +21 -0
  43. package/dist/Shared/ErkSelect/ErkSelect.d.ts +2 -2
  44. package/dist/Shared/InputIcon/InputIcon.js +6 -0
  45. package/dist/Shared/Navbar/Navbar.d.ts +2 -1
  46. package/dist/Shared/Navbar/Navbar.js +22 -3
  47. package/dist/Shared/Navbar/Navbar.module.css +22 -8
  48. package/dist/Shared/SmartDraftRenderer/LinkDecorator.d.ts +14 -0
  49. package/dist/Shared/SmartDraftRenderer/LinkDecorator.js +48 -0
  50. package/dist/Shared/SmartDraftRenderer/SmartDraftRenderer.js +8 -2
  51. package/dist/States/GlobalSlice.d.ts +4 -1
  52. package/dist/States/GlobalSlice.js +8 -1
  53. package/dist/constants/ErkIconTypes.d.ts +3 -1
  54. package/dist/constants/ErkIconTypes.js +2 -0
  55. package/dist/constants/ErkValueTypes.d.ts +6 -0
  56. package/dist/constants/ErkValueTypes.js +7 -0
  57. package/dist/constants/FormStepTypes.d.ts +2 -1
  58. package/dist/constants/FormStepTypes.js +1 -0
  59. package/dist/hooks.d.ts +3 -0
  60. package/dist/hooks.js +17 -1
  61. package/package.json +9 -2
@@ -0,0 +1,366 @@
1
+ /**
2
+ * RTK Query API service for ApiSelector endpoints with request throttling
3
+ */
4
+ export declare const ApiSelectorApi: import("@reduxjs/toolkit/query").Api<import("@reduxjs/toolkit/query").BaseQueryFn<{
5
+ url: string;
6
+ timeout?: import("axios").AxiosRequestConfig["timeout"];
7
+ method?: import("axios").AxiosRequestConfig["method"];
8
+ body?: import("axios").AxiosRequestConfig["data"];
9
+ params?: import("axios").AxiosRequestConfig["params"];
10
+ headers?: Record<string, any>;
11
+ }, unknown, unknown>, {
12
+ fetchApiSelectorOptions: import("@reduxjs/toolkit/query").QueryDefinition<{
13
+ url: string;
14
+ idOrganization?: string;
15
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<{
16
+ url: string;
17
+ timeout?: import("axios").AxiosRequestConfig["timeout"];
18
+ method?: import("axios").AxiosRequestConfig["method"];
19
+ body?: import("axios").AxiosRequestConfig["data"];
20
+ params?: import("axios").AxiosRequestConfig["params"];
21
+ headers?: Record<string, any>;
22
+ }, unknown, unknown>, never, any[], "api", unknown>;
23
+ }, "api", never, typeof import("@reduxjs/toolkit/query").coreModuleName | typeof import("@reduxjs/toolkit/query/react").reactHooksModuleName>;
24
+ export declare const useFetchApiSelectorOptionsQuery: <R extends Record<string, any> = import("@reduxjs/toolkit/query").TSHelpersId<(Omit<{
25
+ status: import("@reduxjs/toolkit/query").QueryStatus.uninitialized;
26
+ originalArgs?: undefined | undefined;
27
+ data?: undefined | undefined;
28
+ error?: undefined | undefined;
29
+ requestId?: undefined | undefined;
30
+ endpointName?: string | undefined;
31
+ startedTimeStamp?: undefined | undefined;
32
+ fulfilledTimeStamp?: undefined | undefined;
33
+ } & {
34
+ currentData?: any[] | undefined;
35
+ isUninitialized: false;
36
+ isLoading: false;
37
+ isFetching: false;
38
+ isSuccess: false;
39
+ isError: false;
40
+ }, "isUninitialized"> & {
41
+ isUninitialized: true;
42
+ }) | (Omit<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<{
43
+ url: string;
44
+ idOrganization?: string;
45
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<{
46
+ url: string;
47
+ timeout?: import("axios").AxiosRequestConfig["timeout"];
48
+ method?: import("axios").AxiosRequestConfig["method"];
49
+ body?: import("axios").AxiosRequestConfig["data"];
50
+ params?: import("axios").AxiosRequestConfig["params"];
51
+ headers?: Record<string, any>;
52
+ }, unknown, unknown>, never, any[], "api", unknown>> & {
53
+ currentData?: any[] | undefined;
54
+ isUninitialized: false;
55
+ isLoading: false;
56
+ isFetching: false;
57
+ isSuccess: false;
58
+ isError: false;
59
+ }, "data" | "isLoading" | "isFetching"> & {
60
+ isLoading: true;
61
+ isFetching: boolean;
62
+ data: undefined;
63
+ }) | (Omit<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<{
64
+ url: string;
65
+ idOrganization?: string;
66
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<{
67
+ url: string;
68
+ timeout?: import("axios").AxiosRequestConfig["timeout"];
69
+ method?: import("axios").AxiosRequestConfig["method"];
70
+ body?: import("axios").AxiosRequestConfig["data"];
71
+ params?: import("axios").AxiosRequestConfig["params"];
72
+ headers?: Record<string, any>;
73
+ }, unknown, unknown>, never, any[], "api", unknown>> & {
74
+ currentData?: any[] | undefined;
75
+ isUninitialized: false;
76
+ isLoading: false;
77
+ isFetching: false;
78
+ isSuccess: false;
79
+ isError: false;
80
+ }, "data" | "error" | "fulfilledTimeStamp" | "isFetching" | "isSuccess"> & {
81
+ isSuccess: true;
82
+ isFetching: true;
83
+ error: undefined;
84
+ } & {
85
+ data: any[];
86
+ } & Required<Pick<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<{
87
+ url: string;
88
+ idOrganization?: string;
89
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<{
90
+ url: string;
91
+ timeout?: import("axios").AxiosRequestConfig["timeout"];
92
+ method?: import("axios").AxiosRequestConfig["method"];
93
+ body?: import("axios").AxiosRequestConfig["data"];
94
+ params?: import("axios").AxiosRequestConfig["params"];
95
+ headers?: Record<string, any>;
96
+ }, unknown, unknown>, never, any[], "api", unknown>> & {
97
+ currentData?: any[] | undefined;
98
+ isUninitialized: false;
99
+ isLoading: false;
100
+ isFetching: false;
101
+ isSuccess: false;
102
+ isError: false;
103
+ }, "fulfilledTimeStamp">>) | (Omit<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<{
104
+ url: string;
105
+ idOrganization?: string;
106
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<{
107
+ url: string;
108
+ timeout?: import("axios").AxiosRequestConfig["timeout"];
109
+ method?: import("axios").AxiosRequestConfig["method"];
110
+ body?: import("axios").AxiosRequestConfig["data"];
111
+ params?: import("axios").AxiosRequestConfig["params"];
112
+ headers?: Record<string, any>;
113
+ }, unknown, unknown>, never, any[], "api", unknown>> & {
114
+ currentData?: any[] | undefined;
115
+ isUninitialized: false;
116
+ isLoading: false;
117
+ isFetching: false;
118
+ isSuccess: false;
119
+ isError: false;
120
+ }, "data" | "error" | "fulfilledTimeStamp" | "currentData" | "isFetching" | "isSuccess"> & {
121
+ isSuccess: true;
122
+ isFetching: false;
123
+ error: undefined;
124
+ } & {
125
+ data: any[];
126
+ currentData: any[];
127
+ } & Required<Pick<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<{
128
+ url: string;
129
+ idOrganization?: string;
130
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<{
131
+ url: string;
132
+ timeout?: import("axios").AxiosRequestConfig["timeout"];
133
+ method?: import("axios").AxiosRequestConfig["method"];
134
+ body?: import("axios").AxiosRequestConfig["data"];
135
+ params?: import("axios").AxiosRequestConfig["params"];
136
+ headers?: Record<string, any>;
137
+ }, unknown, unknown>, never, any[], "api", unknown>> & {
138
+ currentData?: any[] | undefined;
139
+ isUninitialized: false;
140
+ isLoading: false;
141
+ isFetching: false;
142
+ isSuccess: false;
143
+ isError: false;
144
+ }, "fulfilledTimeStamp">>) | (Omit<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<{
145
+ url: string;
146
+ idOrganization?: string;
147
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<{
148
+ url: string;
149
+ timeout?: import("axios").AxiosRequestConfig["timeout"];
150
+ method?: import("axios").AxiosRequestConfig["method"];
151
+ body?: import("axios").AxiosRequestConfig["data"];
152
+ params?: import("axios").AxiosRequestConfig["params"];
153
+ headers?: Record<string, any>;
154
+ }, unknown, unknown>, never, any[], "api", unknown>> & {
155
+ currentData?: any[] | undefined;
156
+ isUninitialized: false;
157
+ isLoading: false;
158
+ isFetching: false;
159
+ isSuccess: false;
160
+ isError: false;
161
+ }, "error" | "isError"> & {
162
+ isError: true;
163
+ } & Required<Pick<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<{
164
+ url: string;
165
+ idOrganization?: string;
166
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<{
167
+ url: string;
168
+ timeout?: import("axios").AxiosRequestConfig["timeout"];
169
+ method?: import("axios").AxiosRequestConfig["method"];
170
+ body?: import("axios").AxiosRequestConfig["data"];
171
+ params?: import("axios").AxiosRequestConfig["params"];
172
+ headers?: Record<string, any>;
173
+ }, unknown, unknown>, never, any[], "api", unknown>> & {
174
+ currentData?: any[] | undefined;
175
+ isUninitialized: false;
176
+ isLoading: false;
177
+ isFetching: false;
178
+ isSuccess: false;
179
+ isError: false;
180
+ }, "error">>)> & {
181
+ status: import("@reduxjs/toolkit/query").QueryStatus;
182
+ }>(arg: typeof import("@reduxjs/toolkit/query").skipToken | {
183
+ url: string;
184
+ idOrganization?: string;
185
+ }, options?: (import("@reduxjs/toolkit/query").SubscriptionOptions & {
186
+ skip?: boolean;
187
+ refetchOnMountOrArgChange?: boolean | number;
188
+ } & {
189
+ skip?: boolean;
190
+ selectFromResult?: ((state: import("@reduxjs/toolkit/query").TSHelpersId<(Omit<{
191
+ status: import("@reduxjs/toolkit/query").QueryStatus.uninitialized;
192
+ originalArgs?: undefined | undefined;
193
+ data?: undefined | undefined;
194
+ error?: undefined | undefined;
195
+ requestId?: undefined | undefined;
196
+ endpointName?: string | undefined;
197
+ startedTimeStamp?: undefined | undefined;
198
+ fulfilledTimeStamp?: undefined | undefined;
199
+ } & {
200
+ currentData?: any[] | undefined;
201
+ isUninitialized: false;
202
+ isLoading: false;
203
+ isFetching: false;
204
+ isSuccess: false;
205
+ isError: false;
206
+ }, "isUninitialized"> & {
207
+ isUninitialized: true;
208
+ }) | (Omit<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<{
209
+ url: string;
210
+ idOrganization?: string;
211
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<{
212
+ url: string;
213
+ timeout?: import("axios").AxiosRequestConfig["timeout"];
214
+ method?: import("axios").AxiosRequestConfig["method"];
215
+ body?: import("axios").AxiosRequestConfig["data"];
216
+ params?: import("axios").AxiosRequestConfig["params"];
217
+ headers?: Record<string, any>;
218
+ }, unknown, unknown>, never, any[], "api", unknown>> & {
219
+ currentData?: any[] | undefined;
220
+ isUninitialized: false;
221
+ isLoading: false;
222
+ isFetching: false;
223
+ isSuccess: false;
224
+ isError: false;
225
+ }, "data" | "isLoading" | "isFetching"> & {
226
+ isLoading: true;
227
+ isFetching: boolean;
228
+ data: undefined;
229
+ }) | (Omit<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<{
230
+ url: string;
231
+ idOrganization?: string;
232
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<{
233
+ url: string;
234
+ timeout?: import("axios").AxiosRequestConfig["timeout"];
235
+ method?: import("axios").AxiosRequestConfig["method"];
236
+ body?: import("axios").AxiosRequestConfig["data"];
237
+ params?: import("axios").AxiosRequestConfig["params"];
238
+ headers?: Record<string, any>;
239
+ }, unknown, unknown>, never, any[], "api", unknown>> & {
240
+ currentData?: any[] | undefined;
241
+ isUninitialized: false;
242
+ isLoading: false;
243
+ isFetching: false;
244
+ isSuccess: false;
245
+ isError: false;
246
+ }, "data" | "error" | "fulfilledTimeStamp" | "isFetching" | "isSuccess"> & {
247
+ isSuccess: true;
248
+ isFetching: true;
249
+ error: undefined;
250
+ } & {
251
+ data: any[];
252
+ } & Required<Pick<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<{
253
+ url: string;
254
+ idOrganization?: string;
255
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<{
256
+ url: string;
257
+ timeout?: import("axios").AxiosRequestConfig["timeout"];
258
+ method?: import("axios").AxiosRequestConfig["method"];
259
+ body?: import("axios").AxiosRequestConfig["data"];
260
+ params?: import("axios").AxiosRequestConfig["params"];
261
+ headers?: Record<string, any>;
262
+ }, unknown, unknown>, never, any[], "api", unknown>> & {
263
+ currentData?: any[] | undefined;
264
+ isUninitialized: false;
265
+ isLoading: false;
266
+ isFetching: false;
267
+ isSuccess: false;
268
+ isError: false;
269
+ }, "fulfilledTimeStamp">>) | (Omit<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<{
270
+ url: string;
271
+ idOrganization?: string;
272
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<{
273
+ url: string;
274
+ timeout?: import("axios").AxiosRequestConfig["timeout"];
275
+ method?: import("axios").AxiosRequestConfig["method"];
276
+ body?: import("axios").AxiosRequestConfig["data"];
277
+ params?: import("axios").AxiosRequestConfig["params"];
278
+ headers?: Record<string, any>;
279
+ }, unknown, unknown>, never, any[], "api", unknown>> & {
280
+ currentData?: any[] | undefined;
281
+ isUninitialized: false;
282
+ isLoading: false;
283
+ isFetching: false;
284
+ isSuccess: false;
285
+ isError: false;
286
+ }, "data" | "error" | "fulfilledTimeStamp" | "currentData" | "isFetching" | "isSuccess"> & {
287
+ isSuccess: true;
288
+ isFetching: false;
289
+ error: undefined;
290
+ } & {
291
+ data: any[];
292
+ currentData: any[];
293
+ } & Required<Pick<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<{
294
+ url: string;
295
+ idOrganization?: string;
296
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<{
297
+ url: string;
298
+ timeout?: import("axios").AxiosRequestConfig["timeout"];
299
+ method?: import("axios").AxiosRequestConfig["method"];
300
+ body?: import("axios").AxiosRequestConfig["data"];
301
+ params?: import("axios").AxiosRequestConfig["params"];
302
+ headers?: Record<string, any>;
303
+ }, unknown, unknown>, never, any[], "api", unknown>> & {
304
+ currentData?: any[] | undefined;
305
+ isUninitialized: false;
306
+ isLoading: false;
307
+ isFetching: false;
308
+ isSuccess: false;
309
+ isError: false;
310
+ }, "fulfilledTimeStamp">>) | (Omit<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<{
311
+ url: string;
312
+ idOrganization?: string;
313
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<{
314
+ url: string;
315
+ timeout?: import("axios").AxiosRequestConfig["timeout"];
316
+ method?: import("axios").AxiosRequestConfig["method"];
317
+ body?: import("axios").AxiosRequestConfig["data"];
318
+ params?: import("axios").AxiosRequestConfig["params"];
319
+ headers?: Record<string, any>;
320
+ }, unknown, unknown>, never, any[], "api", unknown>> & {
321
+ currentData?: any[] | undefined;
322
+ isUninitialized: false;
323
+ isLoading: false;
324
+ isFetching: false;
325
+ isSuccess: false;
326
+ isError: false;
327
+ }, "error" | "isError"> & {
328
+ isError: true;
329
+ } & Required<Pick<import("@reduxjs/toolkit/query").QuerySubState<import("@reduxjs/toolkit/query").QueryDefinition<{
330
+ url: string;
331
+ idOrganization?: string;
332
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<{
333
+ url: string;
334
+ timeout?: import("axios").AxiosRequestConfig["timeout"];
335
+ method?: import("axios").AxiosRequestConfig["method"];
336
+ body?: import("axios").AxiosRequestConfig["data"];
337
+ params?: import("axios").AxiosRequestConfig["params"];
338
+ headers?: Record<string, any>;
339
+ }, unknown, unknown>, never, any[], "api", unknown>> & {
340
+ currentData?: any[] | undefined;
341
+ isUninitialized: false;
342
+ isLoading: false;
343
+ isFetching: false;
344
+ isSuccess: false;
345
+ isError: false;
346
+ }, "error">>)> & {
347
+ status: import("@reduxjs/toolkit/query").QueryStatus;
348
+ }) => R) | undefined;
349
+ }) | undefined) => [R][R extends any ? 0 : never] & {
350
+ refetch: () => import("@reduxjs/toolkit/query").QueryActionCreatorResult<import("@reduxjs/toolkit/query").QueryDefinition<{
351
+ url: string;
352
+ idOrganization?: string;
353
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<{
354
+ url: string;
355
+ timeout?: import("axios").AxiosRequestConfig["timeout"];
356
+ method?: import("axios").AxiosRequestConfig["method"];
357
+ body?: import("axios").AxiosRequestConfig["data"];
358
+ params?: import("axios").AxiosRequestConfig["params"];
359
+ headers?: Record<string, any>;
360
+ }, unknown, unknown>, never, any[], "api", unknown>>;
361
+ };
362
+ /**
363
+ * Standalone throttled fetch function for imperative API calls
364
+ * This allows using the throttle manager without React hooks
365
+ */
366
+ export declare function fetchApiSelectorOptionsThrottled(url: string, idOrganization?: string): Promise<any[]>;
@@ -0,0 +1,173 @@
1
+ import { RootApi } from '../Utils/_api';
2
+ import widgetInstance from '../Utils/AxiosWidget';
3
+ import axiosInstance from '../Utils/AxiosAPI';
4
+ /**
5
+ * Queue manager to throttle requests per URL ensuring minimum time between requests
6
+ * Ensures at least 0.5 second between request starts
7
+ */
8
+ class RequestThrottleManager {
9
+ constructor() {
10
+ Object.defineProperty(this, "queues", {
11
+ enumerable: true,
12
+ configurable: true,
13
+ writable: true,
14
+ value: new Map()
15
+ });
16
+ Object.defineProperty(this, "processing", {
17
+ enumerable: true,
18
+ configurable: true,
19
+ writable: true,
20
+ value: new Map()
21
+ });
22
+ Object.defineProperty(this, "lastRequestTime", {
23
+ enumerable: true,
24
+ configurable: true,
25
+ writable: true,
26
+ value: new Map()
27
+ });
28
+ Object.defineProperty(this, "MIN_TIME_BETWEEN_REQUESTS_MS", {
29
+ enumerable: true,
30
+ configurable: true,
31
+ writable: true,
32
+ value: 500
33
+ }); // Minimum 0.5 seconds between requests
34
+ }
35
+ /**
36
+ * Gets the normalized URL key (base + path without query params)
37
+ * For URLs containing the forms domain, groups by path segments:
38
+ * - 3+ segments: use all but last (e.g., /sinco/bitakora/ENDPOINT -> /sinco/bitakora/)
39
+ * - 2 segments: use first only (e.g., /sinco/bitakora -> /sinco/)
40
+ * - 1 segment: use first only (e.g., /sinco -> /sinco/)
41
+ */
42
+ getUrlKey(url) {
43
+ try {
44
+ const urlObj = new URL(url, window.location.origin);
45
+ const domain = import.meta.env.VITE_REACT_APP_DOMAIN ?? 'capta.co';
46
+ // Check if URL contains the domain
47
+ if (url.includes(domain)) {
48
+ // Split path into segments, filter out empty strings
49
+ const pathSegments = urlObj.pathname.split('/').filter((s) => s.length > 0);
50
+ let normalizedPath;
51
+ if (pathSegments.length >= 3) {
52
+ // 3+ parts: use all but last
53
+ normalizedPath = '/' + pathSegments.slice(0, -1).join('/') + '/';
54
+ }
55
+ else if (pathSegments.length >= 1) {
56
+ // 1-2 parts: use first part only
57
+ normalizedPath = '/' + pathSegments[0] + '/';
58
+ }
59
+ else {
60
+ // No path segments
61
+ normalizedPath = '/';
62
+ }
63
+ return `${urlObj.origin}${normalizedPath}`;
64
+ }
65
+ // For non-domain URLs, use full pathname
66
+ return `${urlObj.origin}${urlObj.pathname}`;
67
+ }
68
+ catch {
69
+ // If URL parsing fails, use the URL up to the query string
70
+ return url.split('?')[0];
71
+ }
72
+ }
73
+ /**
74
+ * Executes a request with throttling using a simple queue
75
+ */
76
+ async executeRequest(url, requestFn) {
77
+ const urlKey = this.getUrlKey(url);
78
+ // Wait for our turn in the queue
79
+ await this.waitInQueue(urlKey);
80
+ // Record when we're starting the request
81
+ this.lastRequestTime.set(urlKey, Date.now());
82
+ try {
83
+ // Execute the request
84
+ return await requestFn();
85
+ }
86
+ finally {
87
+ // Process next request in queue, waiting if necessary
88
+ this.scheduleNextRequest(urlKey);
89
+ }
90
+ }
91
+ /**
92
+ * Adds request to queue and waits for its turn
93
+ */
94
+ waitInQueue(urlKey) {
95
+ return new Promise((resolve) => {
96
+ const queue = this.queues.get(urlKey) ?? [];
97
+ queue.push({ resolve, timestamp: Date.now() });
98
+ this.queues.set(urlKey, queue);
99
+ // If not already processing this queue, start processing
100
+ if (!this.processing.get(urlKey)) {
101
+ this.processQueue(urlKey);
102
+ }
103
+ });
104
+ }
105
+ /**
106
+ * Processes the next request in the queue
107
+ */
108
+ processQueue(urlKey) {
109
+ const queue = this.queues.get(urlKey) ?? [];
110
+ if (queue.length === 0) {
111
+ this.processing.set(urlKey, false);
112
+ return;
113
+ }
114
+ this.processing.set(urlKey, true);
115
+ const { resolve } = queue.shift();
116
+ this.queues.set(urlKey, queue);
117
+ // Resolve immediately to allow request to proceed
118
+ resolve();
119
+ }
120
+ /**
121
+ * Schedules the next request in queue, waiting if necessary to maintain minimum time between requests
122
+ */
123
+ scheduleNextRequest(urlKey) {
124
+ const lastTime = this.lastRequestTime.get(urlKey) ?? 0;
125
+ const timeSinceLastRequest = Date.now() - lastTime;
126
+ const waitTime = Math.max(0, this.MIN_TIME_BETWEEN_REQUESTS_MS - timeSinceLastRequest);
127
+ setTimeout(() => {
128
+ this.processQueue(urlKey);
129
+ }, waitTime);
130
+ }
131
+ }
132
+ // Global instance of the throttle manager
133
+ const throttleManager = new RequestThrottleManager();
134
+ /**
135
+ * RTK Query API service for ApiSelector endpoints with request throttling
136
+ */
137
+ export const ApiSelectorApi = RootApi.injectEndpoints({
138
+ endpoints: (builder) => ({
139
+ fetchApiSelectorOptions: builder.query({
140
+ queryFn: async ({ url, idOrganization }) => {
141
+ try {
142
+ // Use throttle manager to limit concurrent requests per URL
143
+ const data = await throttleManager.executeRequest(url, async () => {
144
+ const response = await (idOrganization ? widgetInstance.get(url) : axiosInstance.get(url));
145
+ return response.data;
146
+ });
147
+ return { data };
148
+ }
149
+ catch (error) {
150
+ return {
151
+ error: {
152
+ status: error.response?.status ?? 500,
153
+ data: error.response?.data ?? error.message,
154
+ },
155
+ };
156
+ }
157
+ },
158
+ // Keep data cached for 60 seconds
159
+ keepUnusedDataFor: 60,
160
+ }),
161
+ }),
162
+ });
163
+ export const { useFetchApiSelectorOptionsQuery } = ApiSelectorApi;
164
+ /**
165
+ * Standalone throttled fetch function for imperative API calls
166
+ * This allows using the throttle manager without React hooks
167
+ */
168
+ export async function fetchApiSelectorOptionsThrottled(url, idOrganization) {
169
+ return throttleManager.executeRequest(url, async () => {
170
+ const response = await (idOrganization ? widgetInstance.get(url) : axiosInstance.get(url));
171
+ return response.data;
172
+ });
173
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,87 @@
1
+ /* eslint-disable @typescript-eslint/unbound-method, @typescript-eslint/require-await, @typescript-eslint/explicit-function-return-type -- test file: vi.mocked()/expect() reference mocked axios methods as values, and the mock factory uses terse async/return types */
2
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
3
+ import { fetchApiSelectorOptionsThrottled } from './ApiSelectorService';
4
+ import widgetInstance from '../Utils/AxiosWidget';
5
+ import axiosInstance from '../Utils/AxiosAPI';
6
+ // Mock the axios instances. AxiosAPI also exports axiosBaseQuery, consumed by
7
+ // _api.ts at import time to build RootApi — keep it callable or the import chain throws.
8
+ vi.mock('../Utils/AxiosWidget', () => ({
9
+ default: { get: vi.fn() },
10
+ }));
11
+ vi.mock('../Utils/AxiosAPI', () => ({
12
+ default: { get: vi.fn() },
13
+ axiosBaseQuery: () => async () => ({ data: undefined }),
14
+ }));
15
+ describe('ApiSelectorService - Request Throttling', () => {
16
+ beforeEach(() => {
17
+ vi.clearAllMocks();
18
+ vi.useFakeTimers();
19
+ });
20
+ afterEach(async () => {
21
+ // Flush the throttle's pending scheduleNextRequest timers so the shared
22
+ // module singleton's per-URL "processing" flag resets between tests.
23
+ await vi.runOnlyPendingTimersAsync();
24
+ vi.useRealTimers();
25
+ });
26
+ it('should throttle requests to at least 500ms apart per URL', async () => {
27
+ const mockUrl = 'https://api.example.com/data';
28
+ const mockData = [{ id: 1, name: 'Test' }];
29
+ const requestTimes = [];
30
+ // Mock axios to record request times
31
+ vi.mocked(axiosInstance.get).mockImplementation(() => {
32
+ requestTimes.push(Date.now());
33
+ return Promise.resolve({ data: mockData });
34
+ });
35
+ // Fire 3 requests
36
+ const promise1 = fetchApiSelectorOptionsThrottled(mockUrl);
37
+ const promise2 = fetchApiSelectorOptionsThrottled(mockUrl);
38
+ const promise3 = fetchApiSelectorOptionsThrottled(mockUrl);
39
+ // Advance time to allow all requests to complete
40
+ await vi.advanceTimersByTimeAsync(1500);
41
+ await Promise.all([promise1, promise2, promise3]);
42
+ // Verify 3 requests were made
43
+ expect(axiosInstance.get).toHaveBeenCalledTimes(3);
44
+ // Verify requests were spaced at least 500ms apart
45
+ for (let i = 1; i < requestTimes.length; i++) {
46
+ const timeDiff = requestTimes[i] - requestTimes[i - 1];
47
+ expect(timeDiff).toBeGreaterThanOrEqual(500);
48
+ }
49
+ });
50
+ it('should allow different URLs to execute without interfering', async () => {
51
+ const mockUrl1 = 'https://api.example.com/data1';
52
+ const mockUrl2 = 'https://api.example.com/data2';
53
+ const mockData = [{ id: 1, name: 'Test' }];
54
+ vi.mocked(axiosInstance.get).mockResolvedValue({ data: mockData });
55
+ // Fire 2 requests for each URL
56
+ const promise1 = fetchApiSelectorOptionsThrottled(mockUrl1);
57
+ const promise2 = fetchApiSelectorOptionsThrottled(mockUrl2);
58
+ // Both should start immediately (different URLs)
59
+ await vi.advanceTimersByTimeAsync(0);
60
+ await Promise.all([promise1, promise2]);
61
+ // Both URLs should have made their requests
62
+ expect(axiosInstance.get).toHaveBeenCalledTimes(2);
63
+ });
64
+ it('should use widgetInstance when idOrganization is provided', async () => {
65
+ const mockUrl = 'https://api.example.com/data';
66
+ const mockData = [{ id: 1, name: 'Test' }];
67
+ const idOrganization = 'org123';
68
+ vi.mocked(widgetInstance.get).mockResolvedValue({ data: mockData });
69
+ await fetchApiSelectorOptionsThrottled(mockUrl, idOrganization);
70
+ expect(widgetInstance.get).toHaveBeenCalledWith(mockUrl);
71
+ expect(axiosInstance.get).not.toHaveBeenCalled();
72
+ });
73
+ it('should use axiosInstance when idOrganization is not provided', async () => {
74
+ const mockUrl = 'https://api.example.com/data';
75
+ const mockData = [{ id: 1, name: 'Test' }];
76
+ vi.mocked(axiosInstance.get).mockResolvedValue({ data: mockData });
77
+ await fetchApiSelectorOptionsThrottled(mockUrl);
78
+ expect(axiosInstance.get).toHaveBeenCalledWith(mockUrl);
79
+ expect(widgetInstance.get).not.toHaveBeenCalled();
80
+ });
81
+ it('should handle errors properly', async () => {
82
+ const mockUrl = 'https://api.example.com/data';
83
+ const mockError = new Error('Network error');
84
+ vi.mocked(axiosInstance.get).mockRejectedValue(mockError);
85
+ await expect(fetchApiSelectorOptionsThrottled(mockUrl)).rejects.toThrow('Network error');
86
+ });
87
+ });
@@ -21,7 +21,10 @@ export const DraftApi = RootApi.injectEndpoints({
21
21
  });
22
22
  }
23
23
  else {
24
- response = await axiosInstance.post(`/form/draft/${apiKey}`, dependencies);
24
+ response = await axiosInstance.post(`/form/draft/${apiKey}`, {
25
+ property,
26
+ dependencies,
27
+ });
25
28
  }
26
29
  return { data: response.data };
27
30
  },
@@ -0,0 +1,21 @@
1
+ export declare const IntegrationsApi: import("@reduxjs/toolkit/query").Api<import("@reduxjs/toolkit/query").BaseQueryFn<{
2
+ url: string;
3
+ timeout?: import("axios").AxiosRequestConfig["timeout"];
4
+ method?: import("axios").AxiosRequestConfig["method"];
5
+ body?: import("axios").AxiosRequestConfig["data"];
6
+ params?: import("axios").AxiosRequestConfig["params"];
7
+ headers?: Record<string, any>;
8
+ }, unknown, unknown>, {
9
+ fetchFilterIntegration: import("@reduxjs/toolkit/query").QueryDefinition<{
10
+ idForm: string;
11
+ idIntegration: string;
12
+ payload: Record<string, any>;
13
+ }, import("@reduxjs/toolkit/query").BaseQueryFn<{
14
+ url: string;
15
+ timeout?: import("axios").AxiosRequestConfig["timeout"];
16
+ method?: import("axios").AxiosRequestConfig["method"];
17
+ body?: import("axios").AxiosRequestConfig["data"];
18
+ params?: import("axios").AxiosRequestConfig["params"];
19
+ headers?: Record<string, any>;
20
+ }, unknown, unknown>, never, string[] | undefined, "api", unknown>;
21
+ }, "api", never, typeof import("@reduxjs/toolkit/query").coreModuleName | typeof import("@reduxjs/toolkit/query/react").reactHooksModuleName>;