@startinblox/components-ds4go 2.3.0 → 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.
- package/.gitlab-ci.yml +8 -2
- package/AGENTS.md +516 -0
- package/cypress/component/no-component-test.cy.ts +9 -0
- package/cypress/e2e/helpers/components/setupCacheInvalidation.cy.ts +512 -0
- package/cypress/e2e/helpers/components/setupCacheOnResourceReady.cy.ts +483 -0
- package/cypress/e2e/helpers/components/setupComponentSubscriptions.cy.ts +239 -0
- package/cypress/e2e/helpers/components/setupOnSaveReset.cy.ts +380 -0
- package/cypress/e2e/helpers/datas/checkValueInIntervalRecursive.cy.ts +563 -0
- package/cypress/e2e/helpers/datas/dataBuilder.cy.ts +508 -0
- package/cypress/e2e/helpers/datas/filterGenerator.cy.ts +285 -0
- package/cypress/e2e/helpers/datas/filterObjectByDateAfter.cy.ts +389 -0
- package/cypress/e2e/helpers/datas/filterObjectByDateInterval.cy.ts +613 -0
- package/cypress/e2e/helpers/datas/filterObjectById.cy.ts +276 -0
- package/cypress/e2e/helpers/datas/filterObjectByInterval.cy.ts +237 -0
- package/cypress/e2e/helpers/datas/filterObjectByNamedValue.cy.ts +299 -0
- package/cypress/e2e/helpers/datas/filterObjectByType.cy.ts +307 -0
- package/cypress/e2e/helpers/datas/filterObjectByValue.cy.ts +375 -0
- package/cypress/e2e/helpers/datas/sort.cy.ts +293 -0
- package/cypress/e2e/helpers/ui/formatDate.cy.ts +233 -0
- package/cypress/e2e/helpers/utils/requestNavigation.cy.ts +257 -0
- package/cypress/e2e/helpers/utils/uniq.cy.ts +160 -0
- package/cypress/support/e2e.ts +1 -0
- package/cypress.config.ts +2 -0
- package/dist/index.js +1102 -1002
- package/package.json +10 -10
- package/src/components/solid-boilerplate.ts +76 -0
- package/src/helpers/components/componentObjectHandler.ts +5 -7
- package/src/helpers/components/componentObjectsHandler.ts +8 -3
- package/src/helpers/components/orbitComponent.ts +87 -68
- package/src/helpers/components/setupCacheInvalidation.ts +50 -23
- package/src/helpers/components/setupCacheOnResourceReady.ts +42 -23
- package/src/helpers/components/setupComponentSubscriptions.ts +10 -9
- package/src/helpers/components/setupOnSaveReset.ts +27 -5
- package/src/helpers/datas/checkValueInIntervalRecursive.ts +66 -0
- package/src/helpers/datas/dataBuilder.ts +4 -4
- package/src/helpers/datas/filterGenerator.ts +13 -10
- package/src/helpers/datas/filterObjectByDateAfter.ts +3 -3
- package/src/helpers/datas/filterObjectByDateInterval.ts +44 -0
- package/src/helpers/datas/filterObjectById.ts +7 -6
- package/src/helpers/datas/filterObjectByInterval.ts +6 -110
- package/src/helpers/datas/filterObjectByNamedValue.ts +35 -33
- package/src/helpers/datas/filterObjectByType.ts +3 -3
- package/src/helpers/datas/filterObjectByValue.ts +17 -16
- package/src/helpers/datas/sort.ts +50 -23
- package/src/helpers/index.ts +2 -0
- package/src/helpers/ui/formatDate.ts +14 -1
- package/src/helpers/utils/requestNavigation.ts +5 -2
- package/src/helpers/utils/uniq.ts +1 -1
- package/cypress/component/solid-boilerplate.cy.ts +0 -9
|
@@ -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
|
-
|
|
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 (
|
|
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 {
|
|
1
|
+
import type { UnknownResource } from "@src/component";
|
|
2
2
|
|
|
3
|
-
export const recusiveRemovePath = (obj:
|
|
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:
|
|
17
|
+
resource: UnknownResource,
|
|
18
18
|
pathToRemove: string[] = [],
|
|
19
19
|
replacements: object = {},
|
|
20
20
|
removeThenReplace = false,
|
|
21
|
-
):
|
|
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
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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 {
|
|
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:
|
|
56
|
+
array: UnknownResource[],
|
|
57
57
|
propName: string,
|
|
58
58
|
thresholdDateString: string
|
|
59
|
-
):
|
|
59
|
+
): UnknownResource[] => {
|
|
60
60
|
if (
|
|
61
61
|
!propName ||
|
|
62
62
|
!thresholdDateString ||
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { UnknownResource } from "@src/component";
|
|
2
|
+
import checkValueInIntervalRecursive from "@src/helpers/datas/checkValueInIntervalRecursive";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Filters an array of Resource objects based on whether a specific date/number property
|
|
6
|
+
* falls within a given interval string (e.g., "2023-01-01/2023-01-31" or "3/6").
|
|
7
|
+
* Checks the property recursively within nested objects and arrays.
|
|
8
|
+
*/
|
|
9
|
+
const filterObjectByDateInterval = (
|
|
10
|
+
array: UnknownResource[],
|
|
11
|
+
propName: string,
|
|
12
|
+
interval: string,
|
|
13
|
+
): UnknownResource[] => {
|
|
14
|
+
if (!propName || !interval || typeof interval !== "string") {
|
|
15
|
+
return array;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const [startStr, endStr] = interval.split("/");
|
|
19
|
+
if (!startStr) {
|
|
20
|
+
return array;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const startDate = new Date(startStr);
|
|
24
|
+
|
|
25
|
+
const endDate = new Date(endStr ?? startStr);
|
|
26
|
+
|
|
27
|
+
if (Number.isNaN(startDate.getTime()) || Number.isNaN(endDate.getTime())) {
|
|
28
|
+
console.warn(`Invalid date interval provided: ${interval}`);
|
|
29
|
+
return array;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
endDate.setHours(23, 59, 59, 999);
|
|
33
|
+
|
|
34
|
+
if (startDate > endDate) {
|
|
35
|
+
console.warn(`Start date is after end date in interval: ${interval}`);
|
|
36
|
+
return array;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return array.filter((obj) =>
|
|
40
|
+
checkValueInIntervalRecursive(obj, propName, startDate, endDate),
|
|
41
|
+
);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export default filterObjectByDateInterval;
|
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { UnknownResource } from "@src/component";
|
|
2
2
|
|
|
3
3
|
const filterObjectById = (
|
|
4
|
-
array:
|
|
4
|
+
array: UnknownResource[],
|
|
5
5
|
propName: string,
|
|
6
|
-
targetId: string
|
|
7
|
-
):
|
|
6
|
+
targetId: string,
|
|
7
|
+
): UnknownResource[] => {
|
|
8
8
|
if (!propName || !targetId) {
|
|
9
9
|
return array;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
const propPath = propName.split(".");
|
|
13
|
+
|
|
12
14
|
return array.filter((obj) => {
|
|
13
15
|
let current = obj;
|
|
14
|
-
const propPath = propName.split(".");
|
|
15
16
|
|
|
16
17
|
for (const segment of propPath) {
|
|
17
18
|
if (current && typeof current === "object" && segment in current) {
|
|
@@ -43,7 +44,7 @@ const filterObjectById = (
|
|
|
43
44
|
typeof item === "object" &&
|
|
44
45
|
item !== null &&
|
|
45
46
|
"@id" in item &&
|
|
46
|
-
item["@id"] === targetId
|
|
47
|
+
item["@id"] === targetId,
|
|
47
48
|
);
|
|
48
49
|
}
|
|
49
50
|
|
|
@@ -1,115 +1,11 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
function isValidDateValue(value: unknown): value is string | number | Date {
|
|
5
|
-
if (
|
|
6
|
-
typeof value !== "string" &&
|
|
7
|
-
typeof value !== "number" &&
|
|
8
|
-
!(value instanceof Date)
|
|
9
|
-
) {
|
|
10
|
-
return false;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
return !Number.isNaN(new Date(value).getTime());
|
|
14
|
-
}
|
|
15
|
-
const checkValueInIntervalRecursive = (
|
|
16
|
-
data: any,
|
|
17
|
-
propName: string,
|
|
18
|
-
startValue: number | Date,
|
|
19
|
-
endValue: number | Date
|
|
20
|
-
): boolean => {
|
|
21
|
-
if (data === null || data === undefined) {
|
|
22
|
-
return false;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const propPath = propName.split(".");
|
|
26
|
-
let current = data;
|
|
27
|
-
|
|
28
|
-
for (const segment of propPath) {
|
|
29
|
-
if (current && typeof current === "object" && segment in current) {
|
|
30
|
-
current = current[segment];
|
|
31
|
-
} else {
|
|
32
|
-
return false;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (typeof current === "number") {
|
|
37
|
-
if (typeof startValue === "number" && typeof endValue === "number") {
|
|
38
|
-
if (startValue <= current && current <= endValue) {
|
|
39
|
-
return true;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
} else if (isValidDateValue(current)) {
|
|
43
|
-
const date = new Date(current);
|
|
44
|
-
if (startValue instanceof Date && endValue instanceof Date) {
|
|
45
|
-
if (startValue <= date && date <= endValue) {
|
|
46
|
-
return true;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
} else {
|
|
50
|
-
return false;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (Array.isArray(data)) {
|
|
54
|
-
return data.some((item) =>
|
|
55
|
-
checkValueInIntervalRecursive(item, propName, startValue, endValue)
|
|
56
|
-
);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (typeof data === "object") {
|
|
60
|
-
return Object.entries(data).some(([key, value]) =>
|
|
61
|
-
checkValueInIntervalRecursive(value, propName, startValue, endValue)
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return false;
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Filters an array of Resource objects based on whether a specific date/number property
|
|
70
|
-
* falls within a given interval string (e.g., "2023-01-01/2023-01-31" or "3/6").
|
|
71
|
-
* Checks the property recursively within nested objects and arrays.
|
|
72
|
-
*/
|
|
73
|
-
const filterObjectByDateInterval = (
|
|
74
|
-
array: Resource[],
|
|
75
|
-
propName: string,
|
|
76
|
-
interval: string
|
|
77
|
-
): Resource[] => {
|
|
78
|
-
if (!propName || !interval || typeof interval !== "string") {
|
|
79
|
-
return array;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const [startStr, endStr] = interval.split("/");
|
|
83
|
-
if (!startStr) {
|
|
84
|
-
return array;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const startDate = new Date(startStr);
|
|
88
|
-
|
|
89
|
-
const endDate = new Date(endStr ?? startStr);
|
|
90
|
-
|
|
91
|
-
if (Number.isNaN(startDate.getTime()) || Number.isNaN(endDate.getTime())) {
|
|
92
|
-
console.warn(`Invalid date interval provided: ${interval}`);
|
|
93
|
-
return array;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
endDate.setHours(23, 59, 59, 999);
|
|
97
|
-
|
|
98
|
-
if (startDate > endDate) {
|
|
99
|
-
console.warn(`Start date is after end date in interval: ${interval}`);
|
|
100
|
-
return array;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return array.filter((obj) =>
|
|
104
|
-
checkValueInIntervalRecursive(obj, propName, startDate, endDate)
|
|
105
|
-
);
|
|
106
|
-
};
|
|
1
|
+
import type { UnknownResource } from "@src/component";
|
|
2
|
+
import checkValueInIntervalRecursive from "@src/helpers/datas/checkValueInIntervalRecursive";
|
|
107
3
|
|
|
108
4
|
const filterObjectByInterval = (
|
|
109
|
-
array:
|
|
5
|
+
array: UnknownResource[],
|
|
110
6
|
propName: string,
|
|
111
|
-
interval: string
|
|
112
|
-
):
|
|
7
|
+
interval: string,
|
|
8
|
+
): UnknownResource[] => {
|
|
113
9
|
if (!propName || !interval || typeof interval !== "string") {
|
|
114
10
|
return array;
|
|
115
11
|
}
|
|
@@ -126,7 +22,7 @@ const filterObjectByInterval = (
|
|
|
126
22
|
}
|
|
127
23
|
|
|
128
24
|
return array.filter((obj) =>
|
|
129
|
-
checkValueInIntervalRecursive(obj, propName, startStr, endStr)
|
|
25
|
+
checkValueInIntervalRecursive(obj, propName, startStr, endStr),
|
|
130
26
|
);
|
|
131
27
|
};
|
|
132
28
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { UnknownResource } from "@src/component";
|
|
2
2
|
|
|
3
3
|
const calculatePertinenceScoreRecursive = (
|
|
4
4
|
data: any,
|
|
5
5
|
lowerCaseString: string,
|
|
6
|
-
isTargetProperty: boolean
|
|
6
|
+
isTargetProperty: boolean,
|
|
7
7
|
): number => {
|
|
8
8
|
if (data === null || data === undefined) {
|
|
9
9
|
return 0;
|
|
@@ -18,7 +18,7 @@ const calculatePertinenceScoreRecursive = (
|
|
|
18
18
|
|
|
19
19
|
const escapedString = lowerCaseString.replace(
|
|
20
20
|
/[.*+?^${}()|[\]\\]/g,
|
|
21
|
-
"\\$&"
|
|
21
|
+
"\\$&",
|
|
22
22
|
);
|
|
23
23
|
|
|
24
24
|
const wholeWordRegex = new RegExp(`\\b${escapedString}\\b`);
|
|
@@ -40,8 +40,8 @@ const calculatePertinenceScoreRecursive = (
|
|
|
40
40
|
calculatePertinenceScoreRecursive(
|
|
41
41
|
item,
|
|
42
42
|
lowerCaseString,
|
|
43
|
-
isTargetProperty
|
|
44
|
-
)
|
|
43
|
+
isTargetProperty,
|
|
44
|
+
),
|
|
45
45
|
);
|
|
46
46
|
if (maxScore === 2) break;
|
|
47
47
|
}
|
|
@@ -55,8 +55,8 @@ const calculatePertinenceScoreRecursive = (
|
|
|
55
55
|
calculatePertinenceScoreRecursive(
|
|
56
56
|
value,
|
|
57
57
|
lowerCaseString,
|
|
58
|
-
isTargetProperty
|
|
59
|
-
)
|
|
58
|
+
isTargetProperty,
|
|
59
|
+
),
|
|
60
60
|
);
|
|
61
61
|
if (maxScore === 2) break;
|
|
62
62
|
}
|
|
@@ -64,40 +64,42 @@ const calculatePertinenceScoreRecursive = (
|
|
|
64
64
|
};
|
|
65
65
|
|
|
66
66
|
const filterObjectByNamedValue = (
|
|
67
|
-
array:
|
|
67
|
+
array: UnknownResource[],
|
|
68
68
|
propName: string,
|
|
69
|
-
searchString: string
|
|
70
|
-
):
|
|
69
|
+
searchString: string,
|
|
70
|
+
): UnknownResource[] => {
|
|
71
71
|
if (!propName || !searchString || searchString.trim() === "") {
|
|
72
72
|
return array;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
const lowerCaseString = searchString.toLowerCase();
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
current
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
76
|
+
const propPath = propName.split(".");
|
|
77
|
+
|
|
78
|
+
return array
|
|
79
|
+
.map((obj) => {
|
|
80
|
+
let current: any = obj;
|
|
81
|
+
for (const segment of propPath) {
|
|
82
|
+
if (current && typeof current === "object" && segment in current) {
|
|
83
|
+
current = current[segment];
|
|
84
|
+
} else {
|
|
85
|
+
current = null;
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
86
88
|
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
let score = 0;
|
|
90
|
-
if (current) {
|
|
91
|
-
score = calculatePertinenceScoreRecursive(current, lowerCaseString, true);
|
|
92
|
-
}
|
|
93
|
-
return { obj, score };
|
|
94
|
-
});
|
|
95
89
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
90
|
+
let score = 0;
|
|
91
|
+
if (current) {
|
|
92
|
+
score = calculatePertinenceScoreRecursive(
|
|
93
|
+
current,
|
|
94
|
+
lowerCaseString,
|
|
95
|
+
true,
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
return { obj, score };
|
|
99
|
+
})
|
|
100
|
+
.filter((item) => item.score > 0)
|
|
101
|
+
.sort((a, b) => b.score - a.score)
|
|
102
|
+
.map((item) => item.obj);
|
|
101
103
|
};
|
|
102
104
|
|
|
103
105
|
export default filterObjectByNamedValue;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { UnknownResource } from "@src/component";
|
|
2
2
|
|
|
3
3
|
const filterObjectByType = (
|
|
4
|
-
array:
|
|
4
|
+
array: UnknownResource[],
|
|
5
5
|
targetType: string
|
|
6
|
-
):
|
|
6
|
+
): UnknownResource[] => {
|
|
7
7
|
if (!targetType) {
|
|
8
8
|
return array;
|
|
9
9
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { UnknownResource } from "@src/component";
|
|
2
2
|
|
|
3
3
|
const calculatePertinenceScore = (
|
|
4
4
|
data: any,
|
|
5
5
|
lowerCaseString: string,
|
|
6
|
-
key?: string
|
|
6
|
+
key?: string,
|
|
7
7
|
): number => {
|
|
8
8
|
if (data === null || data === undefined) {
|
|
9
9
|
return 0;
|
|
@@ -14,7 +14,7 @@ const calculatePertinenceScore = (
|
|
|
14
14
|
|
|
15
15
|
const escapedString = lowerCaseString.replace(
|
|
16
16
|
/[.*+?^${}()|[\]\\]/g,
|
|
17
|
-
"\\$&"
|
|
17
|
+
"\\$&",
|
|
18
18
|
);
|
|
19
19
|
|
|
20
20
|
const wholeWordRegex = new RegExp(`\\b${escapedString}\\b`);
|
|
@@ -41,7 +41,7 @@ const calculatePertinenceScore = (
|
|
|
41
41
|
for (const item of data) {
|
|
42
42
|
maxScore = Math.max(
|
|
43
43
|
maxScore,
|
|
44
|
-
calculatePertinenceScore(item, lowerCaseString)
|
|
44
|
+
calculatePertinenceScore(item, lowerCaseString),
|
|
45
45
|
);
|
|
46
46
|
if (maxScore === 4) break;
|
|
47
47
|
}
|
|
@@ -52,30 +52,31 @@ const calculatePertinenceScore = (
|
|
|
52
52
|
for (const [currentKey, value] of Object.entries(data)) {
|
|
53
53
|
maxScore = Math.max(
|
|
54
54
|
maxScore,
|
|
55
|
-
calculatePertinenceScore(value, lowerCaseString, currentKey)
|
|
55
|
+
calculatePertinenceScore(value, lowerCaseString, currentKey),
|
|
56
56
|
);
|
|
57
57
|
if (maxScore === 4) break;
|
|
58
58
|
}
|
|
59
59
|
return maxScore;
|
|
60
60
|
};
|
|
61
61
|
|
|
62
|
-
const filterObjectByValue = (
|
|
62
|
+
const filterObjectByValue = (
|
|
63
|
+
array: UnknownResource[],
|
|
64
|
+
searchString: string,
|
|
65
|
+
): UnknownResource[] => {
|
|
63
66
|
if (!searchString || searchString.trim() === "") {
|
|
64
67
|
return array;
|
|
65
68
|
}
|
|
66
69
|
|
|
67
70
|
const lowerCaseString = searchString.toLowerCase();
|
|
68
71
|
|
|
69
|
-
|
|
70
|
-
obj
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
return filteredObjects.map((item) => item.obj);
|
|
72
|
+
return array
|
|
73
|
+
.map((obj) => ({
|
|
74
|
+
obj,
|
|
75
|
+
score: calculatePertinenceScore(obj, lowerCaseString),
|
|
76
|
+
}))
|
|
77
|
+
.filter((item) => item.score > 0)
|
|
78
|
+
.sort((a, b) => b.score - a.score)
|
|
79
|
+
.map((item) => item.obj);
|
|
79
80
|
};
|
|
80
81
|
|
|
81
82
|
export default filterObjectByValue;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
const getValueFromAnyKey = (obj: any, keys: string[]): any => {
|
|
2
2
|
let value = obj;
|
|
3
|
-
for (
|
|
4
|
-
if (value &&
|
|
5
|
-
value = value[
|
|
3
|
+
for (const key of keys) {
|
|
4
|
+
if (value && key in value) {
|
|
5
|
+
value = value[key];
|
|
6
6
|
} else {
|
|
7
|
-
|
|
7
|
+
return undefined;
|
|
8
8
|
}
|
|
9
9
|
}
|
|
10
10
|
return value;
|
|
@@ -13,28 +13,55 @@ const getValueFromAnyKey = (obj: any, keys: string[]): any => {
|
|
|
13
13
|
type Sort = (arr: any[], k: string | string[], order?: "asc" | "desc") => any[];
|
|
14
14
|
|
|
15
15
|
const sort: Sort = (arr, k, order = "asc") => {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
16
|
+
const keys = Array.isArray(k) ? k : [k];
|
|
17
|
+
const shouldReverse = order !== "asc";
|
|
18
|
+
|
|
19
|
+
const result = [...arr];
|
|
20
|
+
|
|
21
|
+
const getComparator = () => {
|
|
22
|
+
const sampleValue = getValueFromAnyKey(result[0], keys);
|
|
23
|
+
|
|
24
|
+
if (typeof sampleValue === "number") {
|
|
25
|
+
return (a: any, b: any) => {
|
|
26
|
+
const aN = getValueFromAnyKey(a, keys);
|
|
27
|
+
const bN = getValueFromAnyKey(b, keys);
|
|
28
|
+
if (aN == null) return bN == null ? 0 : 1;
|
|
29
|
+
if (bN == null) return -1;
|
|
30
|
+
return (aN as number) - (bN as number);
|
|
31
|
+
};
|
|
25
32
|
}
|
|
26
|
-
|
|
27
|
-
if (typeof
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
|
|
34
|
+
if (typeof sampleValue === "string") {
|
|
35
|
+
return (a: any, b: any) => {
|
|
36
|
+
const aN = getValueFromAnyKey(a, keys);
|
|
37
|
+
const bN = getValueFromAnyKey(b, keys);
|
|
38
|
+
if (aN == null) return bN == null ? 0 : 1;
|
|
39
|
+
if (bN == null) return -1;
|
|
40
|
+
return (aN as string).localeCompare(bN as string);
|
|
41
|
+
};
|
|
35
42
|
}
|
|
36
|
-
|
|
43
|
+
|
|
44
|
+
if (sampleValue instanceof Date) {
|
|
45
|
+
return (a: any, b: any) => {
|
|
46
|
+
const aN = getValueFromAnyKey(a, keys);
|
|
47
|
+
const bN = getValueFromAnyKey(b, keys);
|
|
48
|
+
if (aN == null) return bN == null ? 0 : 1;
|
|
49
|
+
if (bN == null) return -1;
|
|
50
|
+
return (aN as Date).getTime() - (bN as Date).getTime();
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
throw new TypeError(`Unsupported data type for key "${k}"`);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const comparator = getComparator();
|
|
58
|
+
|
|
59
|
+
result.sort((a, b) => {
|
|
60
|
+
const comparison = comparator(a, b);
|
|
61
|
+
return shouldReverse ? -comparison : comparison;
|
|
37
62
|
});
|
|
63
|
+
|
|
64
|
+
return result;
|
|
38
65
|
};
|
|
39
66
|
|
|
40
67
|
export default sort;
|