@startinblox/components-ds4go 2.2.4 → 3.0.0

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 (52) hide show
  1. package/.gitlab-ci.yml +8 -2
  2. package/AGENTS.md +516 -0
  3. package/cypress/component/no-component-test.cy.ts +9 -0
  4. package/cypress/e2e/helpers/components/setupCacheInvalidation.cy.ts +512 -0
  5. package/cypress/e2e/helpers/components/setupCacheOnResourceReady.cy.ts +483 -0
  6. package/cypress/e2e/helpers/components/setupComponentSubscriptions.cy.ts +239 -0
  7. package/cypress/e2e/helpers/components/setupOnSaveReset.cy.ts +380 -0
  8. package/cypress/e2e/helpers/datas/checkValueInIntervalRecursive.cy.ts +563 -0
  9. package/cypress/e2e/helpers/datas/dataBuilder.cy.ts +508 -0
  10. package/cypress/e2e/helpers/datas/filterGenerator.cy.ts +285 -0
  11. package/cypress/e2e/helpers/datas/filterObjectByDateAfter.cy.ts +389 -0
  12. package/cypress/e2e/helpers/datas/filterObjectByDateInterval.cy.ts +613 -0
  13. package/cypress/e2e/helpers/datas/filterObjectById.cy.ts +276 -0
  14. package/cypress/e2e/helpers/datas/filterObjectByInterval.cy.ts +237 -0
  15. package/cypress/e2e/helpers/datas/filterObjectByNamedValue.cy.ts +299 -0
  16. package/cypress/e2e/helpers/datas/filterObjectByType.cy.ts +307 -0
  17. package/cypress/e2e/helpers/datas/filterObjectByValue.cy.ts +375 -0
  18. package/cypress/e2e/helpers/datas/sort.cy.ts +293 -0
  19. package/cypress/e2e/helpers/ui/formatDate.cy.ts +233 -0
  20. package/cypress/e2e/helpers/utils/requestNavigation.cy.ts +257 -0
  21. package/cypress/e2e/helpers/utils/uniq.cy.ts +160 -0
  22. package/cypress/support/e2e.ts +1 -0
  23. package/cypress.config.ts +2 -0
  24. package/dist/index.js +932 -734
  25. package/locales/en.xlf +75 -0
  26. package/package.json +10 -10
  27. package/src/components/solid-boilerplate.ts +76 -0
  28. package/src/components/solid-fact-bundle-creation.ts +202 -59
  29. package/src/helpers/components/componentObjectHandler.ts +5 -7
  30. package/src/helpers/components/componentObjectsHandler.ts +8 -3
  31. package/src/helpers/components/orbitComponent.ts +87 -68
  32. package/src/helpers/components/setupCacheInvalidation.ts +50 -23
  33. package/src/helpers/components/setupCacheOnResourceReady.ts +42 -23
  34. package/src/helpers/components/setupComponentSubscriptions.ts +10 -9
  35. package/src/helpers/components/setupOnSaveReset.ts +27 -5
  36. package/src/helpers/datas/checkValueInIntervalRecursive.ts +66 -0
  37. package/src/helpers/datas/dataBuilder.ts +4 -4
  38. package/src/helpers/datas/filterGenerator.ts +13 -10
  39. package/src/helpers/datas/filterObjectByDateAfter.ts +3 -3
  40. package/src/helpers/datas/filterObjectByDateInterval.ts +44 -0
  41. package/src/helpers/datas/filterObjectById.ts +7 -6
  42. package/src/helpers/datas/filterObjectByInterval.ts +6 -110
  43. package/src/helpers/datas/filterObjectByNamedValue.ts +35 -33
  44. package/src/helpers/datas/filterObjectByType.ts +3 -3
  45. package/src/helpers/datas/filterObjectByValue.ts +17 -16
  46. package/src/helpers/datas/sort.ts +50 -23
  47. package/src/helpers/index.ts +2 -0
  48. package/src/helpers/ui/formatDate.ts +14 -1
  49. package/src/helpers/utils/requestNavigation.ts +5 -2
  50. package/src/helpers/utils/uniq.ts +1 -1
  51. package/src/styles/fact-bundle-creation.scss +102 -0
  52. package/cypress/component/solid-boilerplate.cy.ts +0 -9
@@ -20,8 +20,13 @@ export default class extends ComponentObjectsHandler {
20
20
  defaultRoute = false,
21
21
  setupSubscriptions = true,
22
22
  ignoreRouter = false,
23
+ }: {
24
+ defaultRoute?: boolean | string;
25
+ setupSubscriptions?: boolean;
26
+ ignoreRouter?: boolean;
23
27
  } = {}) {
24
28
  super();
29
+
25
30
  const attach = () => {
26
31
  if (document.readyState === "complete") {
27
32
  this._attach(defaultRoute, setupSubscriptions, ignoreRouter).then(
@@ -33,6 +38,7 @@ export default class extends ComponentObjectsHandler {
33
38
  );
34
39
  }
35
40
  };
41
+
36
42
  if (document.readyState === "complete") {
37
43
  attach();
38
44
  } else {
@@ -40,6 +46,9 @@ export default class extends ComponentObjectsHandler {
40
46
  }
41
47
  }
42
48
 
49
+ @state()
50
+ ready = false;
51
+
43
52
  @property({ attribute: "default-data-src", reflect: true })
44
53
  defaultDataSrc?: string;
45
54
 
@@ -65,7 +74,7 @@ export default class extends ComponentObjectsHandler {
65
74
  currentRoute = "";
66
75
 
67
76
  protected async _attach(
68
- defaultRoute: boolean,
77
+ defaultRoute: boolean | string,
69
78
  setupSubscriptions: boolean,
70
79
  ignoreRouter: boolean,
71
80
  ) {
@@ -78,18 +87,29 @@ export default class extends ComponentObjectsHandler {
78
87
  defaultRoute: defaultRoute,
79
88
  ignoreRouter: ignoreRouter,
80
89
  });
90
+
81
91
  if (this.route) {
82
92
  this.component = this.orbit.getComponentFromRoute(this.route);
83
93
  if (this.component) {
84
- this.orbit.components.map((c) => {
94
+ for (const c of this.orbit.components) {
85
95
  if (c.uniq === this.component.uniq) {
86
96
  c.instance = this;
87
97
  }
88
- return c;
89
- });
98
+ }
90
99
  }
91
100
  }
101
+
92
102
  await this._afterAttach();
103
+
104
+ this.ready = true;
105
+ this.dispatchEvent(
106
+ new CustomEvent("component-ready", {
107
+ detail: {
108
+ component: this.component,
109
+ },
110
+ }),
111
+ );
112
+
93
113
  return Promise.resolve(true);
94
114
  }
95
115
  }
@@ -109,12 +129,15 @@ export default class extends ComponentObjectsHandler {
109
129
  const subrouter = navigator.getAttribute("navigation-subrouter");
110
130
  const resource = navigator.getAttribute("navigation-resource");
111
131
  const rdfType = navigator.getAttribute("navigation-rdf-type");
132
+
112
133
  if (rdfType) {
113
134
  const compatibleComponents = window.orbit?.components?.filter(
114
135
  (c) => c?.routeAttributes?.["rdf-type"] === rdfType,
115
136
  );
137
+
116
138
  if (compatibleComponents) target = compatibleComponents[0]?.uniq;
117
139
  }
140
+
118
141
  if (target) {
119
142
  requestNavigation(
120
143
  (window.orbit ? window.orbit.getRoute(target, true) : target) +
@@ -122,11 +145,15 @@ export default class extends ComponentObjectsHandler {
122
145
  resource,
123
146
  );
124
147
  }
148
+
125
149
  e.preventDefault();
126
150
  }
127
151
 
128
- _normalizeLdpContains(value: Resource[] | Resource): Resource[] {
129
- if (!Array.isArray(value) && value !== null) {
152
+ _normalizeLdpContains(value: Resource[] | Resource | null): Resource[] {
153
+ if (value === null) {
154
+ return [];
155
+ }
156
+ if (!Array.isArray(value)) {
130
157
  return [value];
131
158
  }
132
159
  return value;
@@ -138,14 +165,16 @@ export default class extends ComponentObjectsHandler {
138
165
  targetProperties: PropertiesPicker[] = this.cherryPickedProperties,
139
166
  ): Promise<UnknownResource[]> {
140
167
  const expandedContainer: UnknownResource[] = [];
141
- for (const entry of value) {
142
- const line = await this._getProxyValue(
143
- await entry,
144
- recursive,
145
- targetProperties,
146
- );
147
- if (line) expandedContainer.push(line);
148
- }
168
+ await Promise.all(
169
+ value.map(async (entry) => {
170
+ const line = await this._getProxyValue(
171
+ await entry,
172
+ recursive,
173
+ targetProperties,
174
+ );
175
+ if (line) expandedContainer.push(line);
176
+ }),
177
+ );
149
178
  return expandedContainer;
150
179
  }
151
180
 
@@ -161,31 +190,41 @@ export default class extends ComponentObjectsHandler {
161
190
  "@context": resource.serverContext,
162
191
  _originalResource: resource,
163
192
  };
164
- for (const prop of targetProperties) {
165
- if (properties?.includes(prop.key)) {
166
- response[prop.value] = await resource.get(prop.key);
167
- if (prop.expand) {
168
- response[prop.value] = await this._getProxyValue(
169
- response[prop.value],
170
- recursive,
171
- targetProperties,
172
- );
173
- }
174
- if (prop.cast) {
175
- response[prop.value] = await prop.cast(response[prop.value]);
176
- }
193
+ const propPromises = targetProperties.map(async (prop) => {
194
+ if (!properties?.includes(prop.key)) return;
195
+
196
+ let value = await resource.get(prop.key);
197
+
198
+ if (prop.expand) {
199
+ value = await this._getProxyValue(value, recursive, targetProperties);
200
+ }
201
+
202
+ if (prop.cast) {
203
+ value = await prop.cast(value);
177
204
  }
205
+ return { prop, value };
206
+ });
207
+
208
+ const results = (await Promise.all(propPromises)).filter(
209
+ (r): r is { prop: PropertiesPicker; value: unknown } => r !== undefined,
210
+ );
211
+
212
+ for (const { prop, value } of results) {
213
+ if (value !== undefined) response[prop.value] = value;
178
214
  }
215
+
179
216
  return await this._responseAdaptator(response);
180
217
  }
181
218
 
182
219
  async _hasCherryPickedProperties(resource: Resource) {
183
220
  const properties = await resource.properties;
221
+
184
222
  for (const prop of this.cherryPickedProperties) {
185
223
  if (properties?.includes(prop.key)) {
186
224
  return true;
187
225
  }
188
226
  }
227
+
189
228
  return false;
190
229
  }
191
230
 
@@ -198,51 +237,31 @@ export default class extends ComponentObjectsHandler {
198
237
  targetProperties: PropertiesPicker[] = this.cherryPickedProperties,
199
238
  ) {
200
239
  try {
201
- if (resource) {
202
- let target = resource;
203
- if (typeof resource === "string") {
204
- target = await window.sibStore.getData(resource, CLIENT_CONTEXT);
205
- }
206
- if (typeof resource !== "string" && resource.isFullResource) {
207
- if (!resource.isFullResource?.()) {
208
- target = await window.sibStore.getData(
209
- resource["@id"],
210
- CLIENT_CONTEXT,
211
- );
212
- }
213
- }
240
+ if (!resource) return;
214
241
 
215
- if (typeof resource !== "string" && !resource.isFullResource) {
216
- // Edge case when calling getProxyValue with an already
217
- // fetched resource with server search, not a proxy
218
- (target as Resource).properties = Object.keys(target);
219
- (target as Resource).get = (property: any) =>
220
- (target as Resource)[property];
221
- }
222
- if (!target) return { _originalResource: target };
223
- if (typeof target === "object" && target !== null) {
224
- if (target.isContainer?.() && target["ldp:contains"]) {
225
- // Allow ldp:containers to be treated manually by a component
226
- if (await this._hasCherryPickedProperties(target)) {
227
- return await this._getProperties(
228
- target,
229
- recursive,
230
- targetProperties,
231
- );
232
- }
233
- const value = this._normalizeLdpContains(
234
- await target["ldp:contains"],
235
- );
236
- return await this._expandContainer(
237
- value,
238
- recursive,
239
- targetProperties,
240
- );
241
- }
242
+ let target = resource;
243
+
244
+ if (typeof resource === "string") {
245
+ target = await window.sibStore.getData(resource, CLIENT_CONTEXT);
246
+ } else if (resource.isFullResource && !resource.isFullResource?.()) {
247
+ target = await window.sibStore.getData(resource["@id"], CLIENT_CONTEXT);
248
+ }
249
+
250
+ if (!target) return { _originalResource: target };
251
+
252
+ if (typeof target !== "object" || target === null) return;
253
+
254
+ if (target.isContainer?.() && target["ldp:contains"]) {
255
+ if (await this._hasCherryPickedProperties(target)) {
242
256
  return await this._getProperties(target, recursive, targetProperties);
243
257
  }
258
+
259
+ const value = this._normalizeLdpContains(await target["ldp:contains"]);
260
+
261
+ return await this._expandContainer(value, recursive, targetProperties);
244
262
  }
245
- return;
263
+
264
+ return await this._getProperties(target, recursive, targetProperties);
246
265
  } catch (e) {
247
266
  if (import.meta.env.DEV) console.error(e);
248
267
  }
@@ -7,35 +7,62 @@ const setupCacheInvalidation = (
7
7
  { keywords = [] as string[], attributes = ["dataSrc"] } = {}
8
8
  ) => {
9
9
  const setup = () => {
10
- if (keywords && attributes) {
11
- if (component.caching === undefined) {
12
- component.caching = 0;
13
- }
14
- if (component.hasCachedDatas === undefined) {
15
- component.hasCachedDatas = false;
16
- }
10
+ if (!keywords.length || !attributes.length) return;
11
+
12
+ if (component.caching === undefined) {
13
+ component.caching = 0;
14
+ }
15
+ if (component.hasCachedDatas === undefined) {
16
+ component.hasCachedDatas = false;
17
+ }
18
+
19
+ let updateScheduled = false;
20
+ const keywordSet = new Set(keywords);
21
+
22
+ component.cacheListener = (e: Event) => {
23
+ const resource = e.detail.id || e.detail.resource?.["@id"];
24
+ if (!resource) return;
25
+
26
+ const isMatch = Array.from(keywordSet).some((keyword) => {
27
+ const idx = resource.indexOf(keyword);
28
+ return idx !== -1 && (idx === 0 || resource[idx - 1] === "/");
29
+ });
17
30
 
18
- component.cacheListener = (e: Event) => {
19
- const resource = e.detail.id || e.detail.resource["@id"];
20
- if (keywords.some((keyword) => resource?.includes(keyword))) {
21
- for (const attribute of attributes) {
22
- if (component[attribute] && resource !== component[attribute]) {
23
- window.sibStore.clearCache(component[attribute]);
24
- }
25
- }
26
- component.caching++;
27
- component.hasCachedDatas = false;
28
- component.requestUpdate();
31
+ if (!isMatch) return;
32
+
33
+ let cacheCleared = false;
34
+ for (const attribute of attributes) {
35
+ if (component[attribute] && resource !== component[attribute]) {
36
+ window.sibStore.clearCache(component[attribute]);
37
+ cacheCleared = true;
29
38
  }
30
- };
39
+ }
31
40
 
32
- component._subscriptions.add(["save", component.cacheListener]);
41
+ if (cacheCleared) {
42
+ component.caching++;
43
+ component.hasCachedDatas = false;
44
+ if (!updateScheduled) {
45
+ updateScheduled = true;
46
+ requestAnimationFrame(() => {
47
+ component.requestUpdate();
48
+ updateScheduled = false;
49
+ });
50
+ }
51
+ }
52
+ };
33
53
 
34
- component._subscribe();
35
- }
54
+ component._subscriptions.add(["save", component.cacheListener]);
55
+ component._subscribe();
36
56
  };
57
+
37
58
  if (document.readyState !== "complete") {
38
- document.addEventListener("DOMContentLoaded", setup);
59
+ const listener = () => {
60
+ if (document.readyState === "complete") {
61
+ document.removeEventListener("readystatechange", listener);
62
+ setup();
63
+ }
64
+ };
65
+ document.addEventListener("readystatechange", listener);
39
66
  } else {
40
67
  setup();
41
68
  }
@@ -2,35 +2,54 @@
2
2
  Common code for components
3
3
  Handle cache invalidation based on keywords
4
4
  */
5
- const setupCacheOnResourceReady = (component: any, { keywords = [] } = {}) => {
5
+ const setupCacheOnResourceReady = (component: any, { keywords = [] as string[] } = {}) => {
6
6
  const setup = () => {
7
- if (keywords) {
8
- if (component.caching === undefined) {
9
- component.caching = 0;
10
- }
11
- if (component.hasCachedDatas === undefined) {
12
- component.hasCachedDatas = false;
13
- }
7
+ if (!keywords.length) return;
14
8
 
15
- component.resourceCacheListener = (e: Event) => {
16
- const resource = e.detail.id || e.detail.resource["@id"];
17
- if (keywords.some((keyword) => resource?.includes(keyword))) {
18
- component.caching++;
19
- component.hasCachedDatas = false;
20
- component.requestUpdate();
21
- }
22
- };
9
+ if (component.caching === undefined) {
10
+ component.caching = 0;
11
+ }
12
+ if (component.hasCachedDatas === undefined) {
13
+ component.hasCachedDatas = false;
14
+ }
23
15
 
24
- component._subscriptions.add([
25
- "resourceReady",
26
- component.resourceCacheListener,
27
- ]);
16
+ let updateScheduled = false;
17
+ const keywordSet = new Set(keywords);
28
18
 
29
- component._subscribe();
30
- }
19
+ component.resourceCacheListener = (e: Event) => {
20
+ const resource = e.detail.id || e.detail.resource?.["@id"];
21
+ if (!resource) return;
22
+
23
+ const isMatch = Array.from(keywordSet).some((keyword) => {
24
+ const idx = resource.indexOf(keyword);
25
+ return idx !== -1 && (idx === 0 || resource[idx - 1] === "/");
26
+ });
27
+
28
+ if (isMatch) {
29
+ component.caching++;
30
+ component.hasCachedDatas = false;
31
+ if (!updateScheduled) {
32
+ updateScheduled = true;
33
+ requestAnimationFrame(() => {
34
+ component.requestUpdate();
35
+ updateScheduled = false;
36
+ });
37
+ }
38
+ }
39
+ };
40
+
41
+ component._subscriptions.add(["resourceReady", component.resourceCacheListener]);
42
+ component._subscribe();
31
43
  };
44
+
32
45
  if (document.readyState !== "complete") {
33
- document.addEventListener("DOMContentLoaded", setup);
46
+ const listener = () => {
47
+ if (document.readyState === "complete") {
48
+ document.removeEventListener("readystatechange", listener);
49
+ setup();
50
+ }
51
+ };
52
+ document.addEventListener("readystatechange", listener);
34
53
  } else {
35
54
  setup();
36
55
  }
@@ -1,4 +1,5 @@
1
1
  import uniq from "@helpers/utils/uniq";
2
+
2
3
  /*
3
4
  Common code for components
4
5
  Handles uniq, route, optional orbit interface, subscriptions manager for each component
@@ -9,7 +10,7 @@ const setupComponentSubscriptions = ({
9
10
  ignoreRouter = false,
10
11
  }: {
11
12
  component: any;
12
- defaultRoute: boolean;
13
+ defaultRoute: boolean | string;
13
14
  ignoreRouter: boolean;
14
15
  }) => {
15
16
  if (!component.uniq) {
@@ -28,26 +29,26 @@ const setupComponentSubscriptions = ({
28
29
  }
29
30
  component.noRouter = true;
30
31
  let router = document.querySelector("solid-router");
32
+ const currentResource = window.sibRouter.currentResource;
31
33
  while (router) {
32
34
  component.noRouter = false;
33
35
  component.currentRoute = router.currentRouteName;
34
- component.currentResource = window.sibRouter.currentResource;
35
- router = document.querySelector(
36
- `[data-view="${router.currentRouteName}"] solid-router`,
37
- );
36
+ component.currentResource = currentResource;
37
+ const nextRouterSelector = `[data-view="${router.currentRouteName}"] solid-router`;
38
+ router = document.querySelector(nextRouterSelector);
38
39
  }
39
40
 
40
41
  component.navigationListener = () => {
41
42
  // component.currentRoute = e.detail?.route;
42
43
  // component.currentResource = window.sibRouter.currentResource;
43
44
  let router = document.querySelector("solid-router");
45
+ const currentResource = window.sibRouter.currentResource;
44
46
  while (router) {
45
47
  component.noRouter = false;
46
48
  component.currentRoute = router.currentRouteName;
47
- component.currentResource = window.sibRouter.currentResource;
48
- router = document.querySelector(
49
- `[data-view="${router.currentRouteName}"] solid-router`,
50
- );
49
+ component.currentResource = currentResource;
50
+ const nextRouterSelector = `[data-view="${router.currentRouteName}"] solid-router`;
51
+ router = document.querySelector(nextRouterSelector);
51
52
  }
52
53
  component.requestUpdate();
53
54
  };
@@ -2,18 +2,40 @@
2
2
  Common code for components
3
3
  Handle cache invalidation based on keywords
4
4
  */
5
- const setupOnSaveReset = (component: any, { keywords = [] } = {}) => {
6
- if (keywords) {
5
+ const setupOnSaveReset = (component: any, { keywords = [] as string[] } = {}) => {
6
+ const setup = () => {
7
+ if (!keywords.length) return;
8
+
9
+ const keywordSet = new Set(keywords);
10
+
7
11
  component.saveListener = (e: Event) => {
8
- const resource = e.detail.id || e.detail.resource["@id"];
9
- if (keywords.some((keyword) => resource?.includes(keyword))) {
12
+ const resource = e.detail.id || e.detail.resource?.["@id"];
13
+ if (!resource) return;
14
+
15
+ const isMatch = Array.from(keywordSet).some((keyword) => {
16
+ const idx = resource.indexOf(keyword);
17
+ return idx !== -1 && (idx === 0 || resource[idx - 1] === "/");
18
+ });
19
+
20
+ if (isMatch) {
10
21
  component._setValue({ target: { value: "" } });
11
22
  }
12
23
  };
13
24
 
14
25
  component._subscriptions.add(["save", component.saveListener]);
15
-
16
26
  component._subscribe();
27
+ };
28
+
29
+ if (document.readyState !== "complete") {
30
+ const listener = () => {
31
+ if (document.readyState === "complete") {
32
+ document.removeEventListener("readystatechange", listener);
33
+ setup();
34
+ }
35
+ };
36
+ document.addEventListener("readystatechange", listener);
37
+ } else {
38
+ setup();
17
39
  }
18
40
  };
19
41
 
@@ -0,0 +1,66 @@
1
+ function isValidDateValue(value: unknown): value is string | number | Date {
2
+ if (
3
+ typeof value !== "string" &&
4
+ typeof value !== "number" &&
5
+ !(value instanceof Date)
6
+ ) {
7
+ return false;
8
+ }
9
+
10
+ return !Number.isNaN(new Date(value).getTime());
11
+ }
12
+
13
+ const checkValueInIntervalRecursive = (
14
+ data: any,
15
+ propName: string,
16
+ startValue: number | Date,
17
+ endValue: number | Date,
18
+ ): boolean => {
19
+ if (data === null || data === undefined) {
20
+ return false;
21
+ }
22
+
23
+ const propPath = propName.split(".");
24
+ let current = data;
25
+
26
+ for (const segment of propPath) {
27
+ if (current && typeof current === "object" && segment in current) {
28
+ current = current[segment];
29
+ } else {
30
+ return false;
31
+ }
32
+ }
33
+
34
+ if (typeof current === "number") {
35
+ if (typeof startValue === "number" && typeof endValue === "number") {
36
+ if (startValue <= current && current <= endValue) {
37
+ return true;
38
+ }
39
+ }
40
+ } else if (isValidDateValue(current)) {
41
+ const date = new Date(current);
42
+ if (startValue instanceof Date && endValue instanceof Date) {
43
+ if (startValue <= date && date <= endValue) {
44
+ return true;
45
+ }
46
+ }
47
+ } else {
48
+ return false;
49
+ }
50
+
51
+ if (Array.isArray(data)) {
52
+ return data.some((item) =>
53
+ checkValueInIntervalRecursive(item, propName, startValue, endValue),
54
+ );
55
+ }
56
+
57
+ if (typeof data === "object") {
58
+ return Object.entries(data).some(([_key, value]) =>
59
+ checkValueInIntervalRecursive(value, propName, startValue, endValue),
60
+ );
61
+ }
62
+
63
+ return false;
64
+ };
65
+
66
+ export default checkValueInIntervalRecursive;
@@ -1,6 +1,6 @@
1
- import type { Resource } from "@src/component";
1
+ import type { UnknownResource } from "@src/component";
2
2
 
3
- export const recusiveRemovePath = (obj: Resource, pathArray: string[]) => {
3
+ export const recusiveRemovePath = (obj: UnknownResource, pathArray: string[]) => {
4
4
  if (!obj || pathArray.length === 0) return;
5
5
  const key = pathArray.shift();
6
6
 
@@ -14,11 +14,11 @@ export const recusiveRemovePath = (obj: Resource, pathArray: string[]) => {
14
14
  };
15
15
 
16
16
  export const dataBuilder = (
17
- resource: Resource,
17
+ resource: UnknownResource,
18
18
  pathToRemove: string[] = [],
19
19
  replacements: object = {},
20
20
  removeThenReplace = false,
21
- ): Resource => {
21
+ ): UnknownResource => {
22
22
  const clone = structuredClone(resource);
23
23
 
24
24
  if (!removeThenReplace) {
@@ -1,4 +1,6 @@
1
1
  const filterGenerator = (objects: { [key: string]: any }[], field: string) => {
2
+ const seen = new Map<string, boolean>();
3
+
2
4
  return objects
3
5
  .flatMap((obj) => {
4
6
  if (obj[field]) {
@@ -13,17 +15,18 @@ const filterGenerator = (objects: { [key: string]: any }[], field: string) => {
13
15
  value: obj[field]?.["@id"] || obj[field],
14
16
  };
15
17
  }
16
- return;
18
+ return {
19
+ label: false,
20
+ value: false,
21
+ };
17
22
  })
18
- .filter(
19
- (value, index, self) =>
20
- value?.label &&
21
- value?.value &&
22
- index ===
23
- self.findIndex(
24
- (t) => t?.label === value?.label && t?.value === value?.value,
25
- ),
26
- );
23
+ .filter((value) => {
24
+ if (!value?.label || !value?.value) return false;
25
+ const key = `${value.label}|${value.value}`;
26
+ if (seen.has(key)) return false;
27
+ seen.set(key, true);
28
+ return true;
29
+ });
27
30
  };
28
31
 
29
32
  export default filterGenerator;
@@ -1,4 +1,4 @@
1
- import type { Resource } from "@src/component";
1
+ import type { UnknownResource } from "@src/component";
2
2
 
3
3
  function isValidDateValue(value: unknown): value is string | number | Date {
4
4
  return !Number.isNaN(new Date((value as Date)).getTime());
@@ -53,10 +53,10 @@ const checkDateIsAfterRecursive = (
53
53
  };
54
54
 
55
55
  const filterObjectByDateAfter = (
56
- array: Resource[],
56
+ array: UnknownResource[],
57
57
  propName: string,
58
58
  thresholdDateString: string
59
- ): Resource[] => {
59
+ ): UnknownResource[] => {
60
60
  if (
61
61
  !propName ||
62
62
  !thresholdDateString ||