@startinblox/boilerplate 4.3.1 → 6.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 +3 -3
- package/AGENTS.md +518 -0
- package/README.md +16 -19
- package/biome.json +1 -1
- package/cypress/component/sample-object.cy.ts +816 -0
- package/cypress/component/solid-boilerplate.cy.ts +894 -5
- package/cypress/e2e/helpers/components/setupCacheInvalidation.cy.ts +512 -0
- package/cypress/e2e/helpers/components/setupCacheOnResourceReady.cy.ts +497 -0
- package/cypress/e2e/helpers/components/setupComponentSubscriptions.cy.ts +239 -0
- package/cypress/e2e/helpers/components/setupOnSaveReset.cy.ts +393 -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 +614 -646
- package/package.json +17 -15
- package/scripts/init.js +355 -0
- package/src/components/solid-boilerplate.ts +3 -6
- package/src/helpers/components/componentObjectHandler.ts +5 -7
- package/src/helpers/components/componentObjectsHandler.ts +8 -3
- package/src/helpers/components/orbitComponent.ts +106 -57
- 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 +6 -4
- 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/src/index.ts +2 -2
|
@@ -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(
|
|
@@ -29,10 +34,11 @@ export default class extends ComponentObjectsHandler {
|
|
|
29
34
|
if (attach) {
|
|
30
35
|
this.requestUpdate();
|
|
31
36
|
}
|
|
32
|
-
}
|
|
37
|
+
},
|
|
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,9 +74,9 @@ 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
|
-
ignoreRouter: boolean
|
|
79
|
+
ignoreRouter: boolean,
|
|
71
80
|
) {
|
|
72
81
|
if (!this.orbit) {
|
|
73
82
|
if (window.orbit) {
|
|
@@ -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
|
|
94
|
+
for (const c of this.orbit.components) {
|
|
85
95
|
if (c.uniq === this.component.uniq) {
|
|
86
96
|
c.instance = this;
|
|
87
97
|
}
|
|
88
|
-
|
|
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,24 +129,31 @@ 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
|
-
(c) => c?.routeAttributes?.["rdf-type"] === rdfType
|
|
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) +
|
|
121
144
|
(subrouter ? `-${subrouter}` : ""),
|
|
122
|
-
resource
|
|
145
|
+
resource,
|
|
123
146
|
);
|
|
124
147
|
}
|
|
148
|
+
|
|
125
149
|
e.preventDefault();
|
|
126
150
|
}
|
|
127
151
|
|
|
128
|
-
_normalizeLdpContains(value: Resource[] | Resource): Resource[] {
|
|
129
|
-
if (
|
|
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;
|
|
@@ -134,20 +161,27 @@ export default class extends ComponentObjectsHandler {
|
|
|
134
161
|
|
|
135
162
|
async _expandContainer(
|
|
136
163
|
value: Resource[],
|
|
137
|
-
recursive = true
|
|
164
|
+
recursive = true,
|
|
165
|
+
targetProperties: PropertiesPicker[] = this.cherryPickedProperties,
|
|
138
166
|
): Promise<UnknownResource[]> {
|
|
139
167
|
const expandedContainer: UnknownResource[] = [];
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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
|
+
);
|
|
144
178
|
return expandedContainer;
|
|
145
179
|
}
|
|
146
180
|
|
|
147
181
|
async _getProperties(
|
|
148
182
|
resource: Resource,
|
|
149
183
|
recursive = true,
|
|
150
|
-
targetProperties: PropertiesPicker[] = this.cherryPickedProperties
|
|
184
|
+
targetProperties: PropertiesPicker[] = this.cherryPickedProperties,
|
|
151
185
|
) {
|
|
152
186
|
const properties = await resource.properties;
|
|
153
187
|
const response: Resource = {
|
|
@@ -156,63 +190,78 @@ export default class extends ComponentObjectsHandler {
|
|
|
156
190
|
"@context": resource.serverContext,
|
|
157
191
|
_originalResource: resource,
|
|
158
192
|
};
|
|
159
|
-
|
|
160
|
-
if (properties?.includes(prop.key))
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
response[prop.value] = await prop.cast(response[prop.value]);
|
|
171
|
-
}
|
|
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);
|
|
172
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;
|
|
173
214
|
}
|
|
215
|
+
|
|
174
216
|
return await this._responseAdaptator(response);
|
|
175
217
|
}
|
|
176
218
|
|
|
219
|
+
async _hasCherryPickedProperties(resource: Resource) {
|
|
220
|
+
const properties = await resource.properties;
|
|
221
|
+
|
|
222
|
+
for (const prop of this.cherryPickedProperties) {
|
|
223
|
+
if (properties?.includes(prop.key)) {
|
|
224
|
+
return true;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
|
|
177
231
|
async _getProxyValue(
|
|
178
232
|
resource:
|
|
179
233
|
| string
|
|
180
234
|
| Resource
|
|
181
235
|
| ProxyValue<Resource | Container<ProxyValue<Resource> | Resource>>,
|
|
182
236
|
recursive = true,
|
|
183
|
-
targetProperties: PropertiesPicker[] = this.cherryPickedProperties
|
|
237
|
+
targetProperties: PropertiesPicker[] = this.cherryPickedProperties,
|
|
184
238
|
) {
|
|
185
239
|
try {
|
|
186
|
-
if (resource)
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
(target as Resource).properties = Object.keys(target);
|
|
203
|
-
(target as Resource).get = (property: any) =>
|
|
204
|
-
(target as Resource)[property];
|
|
205
|
-
}
|
|
206
|
-
if (!target) return { _originalResource: target };
|
|
207
|
-
if (typeof target === "object" && target !== null) {
|
|
208
|
-
if (target["ldp:contains"]) {
|
|
209
|
-
const value = this._normalizeLdpContains(target["ldp:contains"]);
|
|
210
|
-
return await this._expandContainer(value, recursive);
|
|
211
|
-
}
|
|
240
|
+
if (!resource) return;
|
|
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)) {
|
|
212
256
|
return await this._getProperties(target, recursive, targetProperties);
|
|
213
257
|
}
|
|
258
|
+
|
|
259
|
+
const value = this._normalizeLdpContains(await target["ldp:contains"]);
|
|
260
|
+
|
|
261
|
+
return await this._expandContainer(value, recursive, targetProperties);
|
|
214
262
|
}
|
|
215
|
-
|
|
263
|
+
|
|
264
|
+
return await this._getProperties(target, recursive, targetProperties);
|
|
216
265
|
} catch (e) {
|
|
217
266
|
if (import.meta.env.DEV) console.error(e);
|
|
218
267
|
}
|
|
@@ -7,35 +7,62 @@ const setupCacheInvalidation = (
|
|
|
7
7
|
{ keywords = [] as string[], attributes = ["dataSrc"] } = {}
|
|
8
8
|
) => {
|
|
9
9
|
const setup = () => {
|
|
10
|
-
if (keywords
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
|
|
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
|
-
|
|
35
|
-
|
|
54
|
+
component._subscriptions.add(["save", component.cacheListener]);
|
|
55
|
+
component._subscribe();
|
|
36
56
|
};
|
|
57
|
+
|
|
37
58
|
if (document.readyState !== "complete") {
|
|
38
|
-
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
25
|
-
|
|
26
|
-
component.resourceCacheListener,
|
|
27
|
-
]);
|
|
16
|
+
let updateScheduled = false;
|
|
17
|
+
const keywordSet = new Set(keywords);
|
|
28
18
|
|
|
29
|
-
|
|
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
|
-
|
|
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 =
|
|
35
|
-
|
|
36
|
-
|
|
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 =
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
|
|
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 ||
|