@umbraco-cms/backoffice 15.3.0-rc2 → 15.3.1
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/dist-cms/assets/lang/da-dk.js +0 -3
- package/dist-cms/assets/lang/da-dk.ts +0 -3
- package/dist-cms/assets/lang/en-us.js +0 -3
- package/dist-cms/assets/lang/en-us.ts +0 -3
- package/dist-cms/assets/lang/en.js +0 -5
- package/dist-cms/assets/lang/en.ts +0 -6
- package/dist-cms/custom-elements.json +0 -29
- package/dist-cms/external/backend-api/src/types.gen.d.ts +0 -1
- package/dist-cms/libs/context-api/provide/context-provider.controller.js +2 -1
- package/dist-cms/libs/context-api/provide/context-provider.js +1 -2
- package/dist-cms/packages/block/block/workspace/block-element-manager.js +1 -1
- package/dist-cms/packages/block/block-list/property-editors/block-list-editor/property-editor-ui-block-list.element.js +5 -2
- package/dist-cms/packages/core/content/workspace/content-detail-workspace-base.js +1 -1
- package/dist-cms/packages/core/localization/registry/localization.registry.js +1 -1
- package/dist-cms/packages/core/validation/context/validation-messages.manager.d.ts +3 -0
- package/dist-cms/packages/core/validation/context/validation-messages.manager.js +39 -0
- package/dist-cms/packages/core/validation/controllers/form-control-validator.controller.js +7 -5
- package/dist-cms/packages/core/validation/controllers/validation.controller.d.ts +2 -0
- package/dist-cms/packages/core/validation/controllers/validation.controller.js +27 -3
- package/dist-cms/packages/core/validation/utils/json-path.function.d.ts +1 -1
- package/dist-cms/packages/core/validation/utils/json-path.function.js +53 -37
- package/dist-cms/packages/core/workspace/submittable/submittable-workspace-context-base.js +10 -3
- package/dist-cms/packages/documents/document-blueprints/repository/detail/document-blueprint-detail.server.data-source.js +1 -1
- package/dist-cms/packages/documents/documents/components/input-document/input-document.context.js +1 -1
- package/dist-cms/packages/documents/documents/publishing/publish-with-descendants/modal/document-publish-with-descendants-modal.element.js +1 -23
- package/dist-cms/packages/documents/documents/publishing/publish-with-descendants/modal/document-publish-with-descendants-modal.token.d.ts +0 -1
- package/dist-cms/packages/documents/documents/publishing/repository/document-publishing.repository.d.ts +1 -2
- package/dist-cms/packages/documents/documents/publishing/repository/document-publishing.repository.js +2 -3
- package/dist-cms/packages/documents/documents/publishing/repository/document-publishing.server.data-source.d.ts +1 -2
- package/dist-cms/packages/documents/documents/publishing/repository/document-publishing.server.data-source.js +2 -4
- package/dist-cms/packages/documents/documents/publishing/workspace-context/document-publishing.workspace-context.js +1 -1
- package/dist-cms/packages/documents/documents/repository/detail/document-detail.server.data-source.js +1 -1
- package/dist-cms/packages/media/media/components/input-media/input-media.context.js +1 -1
- package/dist-cms/packages/members/member/components/input-member/input-member.context.js +1 -1
- package/dist-cms/packages/multi-url-picker/property-editor/property-editor-ui-multi-url-picker.element.d.ts +2 -2
- package/dist-cms/packages/multi-url-picker/property-editor/property-editor-ui-multi-url-picker.element.js +3 -5
- package/dist-cms/packages/property-editors/accepted-types/property-editor-ui-accepted-upload-types.element.js +5 -35
- package/dist-cms/packages/property-editors/multiple-text-string/property-editor-ui-multiple-text-string.element.d.ts +2 -6
- package/dist-cms/packages/property-editors/multiple-text-string/property-editor-ui-multiple-text-string.element.js +14 -37
- package/dist-cms/packages/tiny-mce/components/input-tiny-mce/input-tiny-mce.element.js +1 -3
- package/dist-cms/packages/tiny-mce/property-editors/tiny-mce/property-editor-ui-tiny-mce.element.js +15 -18
- package/dist-cms/packages/tiptap/property-editors/tiptap/property-editor-ui-tiptap.element.js +1 -1
- package/dist-cms/tsconfig.build.tsbuildinfo +1 -1
- package/dist-cms/umbraco-package.json +1 -1
- package/dist-cms/vscode-html-custom-data.json +3 -17
- package/package.json +1 -1
|
@@ -276,9 +276,6 @@ export default {
|
|
|
276
276
|
removeTextBox: 'Fjern denne tekstboks',
|
|
277
277
|
contentRoot: 'Indholdsrod',
|
|
278
278
|
includeUnpublished: 'Inkluder ikke-udgivet indhold.',
|
|
279
|
-
forceRepublish: 'Udgiv uændrede elementer.',
|
|
280
|
-
forceRepublishWarning: 'ADVARSEL: Udgivelse af alle sider under denne i indholdstræet, uanset om de er ændret eller ej, kan være en ressourcekrævende og langvarig proces.',
|
|
281
|
-
forceRepublishAdvisory: 'Dette bør ikke være nødvendigt under normale omstændigheder, så fortsæt kun med denne handling, hvis du er sikker på, at det er nødvendigt.',
|
|
282
279
|
isSensitiveValue: 'Denne værdi er skjult.Hvis du har brug for adgang til at se denne værdi, bedes du\n kontakte din web-administrator.\n ',
|
|
283
280
|
isSensitiveValue_short: 'Denne værdi er skjult.',
|
|
284
281
|
languagesToPublish: 'Hvilke sprog vil du gerne udgive?',
|
|
@@ -298,9 +298,6 @@ export default {
|
|
|
298
298
|
removeTextBox: 'Fjern denne tekstboks',
|
|
299
299
|
contentRoot: 'Indholdsrod',
|
|
300
300
|
includeUnpublished: 'Inkluder ikke-udgivet indhold.',
|
|
301
|
-
forceRepublish: 'Udgiv uændrede elementer.',
|
|
302
|
-
forceRepublishWarning: 'ADVARSEL: Udgivelse af alle sider under denne i indholdstræet, uanset om de er ændret eller ej, kan være en ressourcekrævende og langvarig proces.',
|
|
303
|
-
forceRepublishAdvisory: 'Dette bør ikke være nødvendigt under normale omstændigheder, så fortsæt kun med denne handling, hvis du er sikker på, at det er nødvendigt.',
|
|
304
301
|
isSensitiveValue:
|
|
305
302
|
'Denne værdi er skjult.Hvis du har brug for adgang til at se denne værdi, bedes du\n kontakte din web-administrator.\n ',
|
|
306
303
|
isSensitiveValue_short: 'Denne værdi er skjult.',
|
|
@@ -296,9 +296,6 @@ export default {
|
|
|
296
296
|
removeTextBox: 'Remove this text box',
|
|
297
297
|
contentRoot: 'Content root',
|
|
298
298
|
includeUnpublished: 'Include unpublished content items.',
|
|
299
|
-
forceRepublish: 'Publish unchanged items.',
|
|
300
|
-
forceRepublishWarning: 'WARNING: Publishing all pages below this one in the content tree, whether or not they have changed, can be an expensive and long-running operation.',
|
|
301
|
-
forceRepublishAdvisory: 'This should not be necessary in normal circumstances so please only proceed with this option selected if you are certain it is required.',
|
|
302
299
|
isSensitiveValue: 'This value is hidden. If you need access to view this value please contact your\n website administrator.\n ',
|
|
303
300
|
isSensitiveValue_short: 'This value is hidden.',
|
|
304
301
|
languagesToPublish: 'What languages would you like to publish?',
|
|
@@ -320,9 +320,6 @@ export default {
|
|
|
320
320
|
removeTextBox: 'Remove this text box',
|
|
321
321
|
contentRoot: 'Content root',
|
|
322
322
|
includeUnpublished: 'Include unpublished content items.',
|
|
323
|
-
forceRepublish: 'Publish unchanged items.',
|
|
324
|
-
forceRepublishWarning: 'WARNING: Publishing all pages below this one in the content tree, whether or not they have changed, can be an expensive and long-running operation.',
|
|
325
|
-
forceRepublishAdvisory: 'This should not be necessary in normal circumstances so please only proceed with this option selected if you are certain it is required.',
|
|
326
323
|
isSensitiveValue:
|
|
327
324
|
'This value is hidden. If you need access to view this value please contact your\n website administrator.\n ',
|
|
328
325
|
isSensitiveValue_short: 'This value is hidden.',
|
|
@@ -293,9 +293,6 @@ export default {
|
|
|
293
293
|
removeTextBox: 'Remove this text box',
|
|
294
294
|
contentRoot: 'Content root',
|
|
295
295
|
includeUnpublished: 'Include unpublished content items.',
|
|
296
|
-
forceRepublish: 'Publish unchanged items.',
|
|
297
|
-
forceRepublishWarning: 'WARNING: Publishing all pages below this one in the content tree, whether or not they have changed, can be an expensive and long-running operation.',
|
|
298
|
-
forceRepublishAdvisory: 'This should not be necessary in normal circumstances so please only proceed with this option selected if you are certain it is required.',
|
|
299
296
|
isSensitiveValue: 'This value is hidden. If you need access to view this value please contact your\n website administrator.\n ',
|
|
300
297
|
isSensitiveValue_short: 'This value is hidden.',
|
|
301
298
|
languagesToPublish: 'What languages would you like to publish?',
|
|
@@ -350,7 +347,6 @@ export default {
|
|
|
350
347
|
fileSecurityValidationFailure: 'One or more file security validations have failed',
|
|
351
348
|
moveToSameFolderFailed: 'Parent and destination folders cannot be the same',
|
|
352
349
|
uploadNotAllowed: 'Upload is not allowed in this location.',
|
|
353
|
-
noticeExtensionsServerOverride: 'Regardless of the allowed file types, the following limitations apply system-wide due to the server configuration:',
|
|
354
350
|
},
|
|
355
351
|
member: {
|
|
356
352
|
'2fa': 'Two-Factor Authentication',
|
|
@@ -837,7 +833,6 @@ export default {
|
|
|
837
833
|
retrieve: 'Retrieve',
|
|
838
834
|
retry: 'Retry',
|
|
839
835
|
rights: 'Permissions',
|
|
840
|
-
serverConfiguration: 'Server Configuration',
|
|
841
836
|
scheduledPublishing: 'Scheduled Publishing',
|
|
842
837
|
umbracoInfo: 'Umbraco info',
|
|
843
838
|
search: 'Search',
|
|
@@ -317,9 +317,6 @@ export default {
|
|
|
317
317
|
removeTextBox: 'Remove this text box',
|
|
318
318
|
contentRoot: 'Content root',
|
|
319
319
|
includeUnpublished: 'Include unpublished content items.',
|
|
320
|
-
forceRepublish: 'Publish unchanged items.',
|
|
321
|
-
forceRepublishWarning: 'WARNING: Publishing all pages below this one in the content tree, whether or not they have changed, can be an expensive and long-running operation.',
|
|
322
|
-
forceRepublishAdvisory: 'This should not be necessary in normal circumstances so please only proceed with this option selected if you are certain it is required.',
|
|
323
320
|
isSensitiveValue:
|
|
324
321
|
'This value is hidden. If you need access to view this value please contact your\n website administrator.\n ',
|
|
325
322
|
isSensitiveValue_short: 'This value is hidden.',
|
|
@@ -377,8 +374,6 @@ export default {
|
|
|
377
374
|
fileSecurityValidationFailure: 'One or more file security validations have failed',
|
|
378
375
|
moveToSameFolderFailed: 'Parent and destination folders cannot be the same',
|
|
379
376
|
uploadNotAllowed: 'Upload is not allowed in this location.',
|
|
380
|
-
noticeExtensionsServerOverride:
|
|
381
|
-
'Regardless of the allowed file types, the following limitations apply system-wide due to the server configuration:',
|
|
382
377
|
},
|
|
383
378
|
member: {
|
|
384
379
|
'2fa': 'Two-Factor Authentication',
|
|
@@ -902,7 +897,6 @@ export default {
|
|
|
902
897
|
retrieve: 'Retrieve',
|
|
903
898
|
retry: 'Retry',
|
|
904
899
|
rights: 'Permissions',
|
|
905
|
-
serverConfiguration: 'Server Configuration',
|
|
906
900
|
scheduledPublishing: 'Scheduled Publishing',
|
|
907
901
|
umbracoInfo: 'Umbraco info',
|
|
908
902
|
search: 'Search',
|
|
@@ -10566,11 +10566,6 @@
|
|
|
10566
10566
|
"name": "umb-property-editor-ui-multi-url-picker",
|
|
10567
10567
|
"path": "./../src/packages/multi-url-picker/property-editor/property-editor-ui-multi-url-picker.element.ts",
|
|
10568
10568
|
"attributes": [
|
|
10569
|
-
{
|
|
10570
|
-
"name": "value",
|
|
10571
|
-
"type": "UmbLinkPickerLink[]",
|
|
10572
|
-
"default": "[]"
|
|
10573
|
-
},
|
|
10574
10569
|
{
|
|
10575
10570
|
"name": "readonly",
|
|
10576
10571
|
"description": "Sets the input to readonly mode, meaning value cannot be changed but still able to read and select its content.",
|
|
@@ -10579,12 +10574,6 @@
|
|
|
10579
10574
|
}
|
|
10580
10575
|
],
|
|
10581
10576
|
"properties": [
|
|
10582
|
-
{
|
|
10583
|
-
"name": "value",
|
|
10584
|
-
"attribute": "value",
|
|
10585
|
-
"type": "UmbLinkPickerLink[]",
|
|
10586
|
-
"default": "[]"
|
|
10587
|
-
},
|
|
10588
10577
|
{
|
|
10589
10578
|
"name": "config"
|
|
10590
10579
|
},
|
|
@@ -10737,10 +10726,6 @@
|
|
|
10737
10726
|
"name": "umb-property-editor-ui-accepted-upload-types",
|
|
10738
10727
|
"path": "./../src/packages/property-editors/accepted-types/property-editor-ui-accepted-upload-types.element.ts",
|
|
10739
10728
|
"attributes": [
|
|
10740
|
-
{
|
|
10741
|
-
"name": "value",
|
|
10742
|
-
"type": "string[] | undefined"
|
|
10743
|
-
},
|
|
10744
10729
|
{
|
|
10745
10730
|
"name": "disabled",
|
|
10746
10731
|
"description": "Disables the Multiple Text String Property Editor UI",
|
|
@@ -10766,11 +10751,6 @@
|
|
|
10766
10751
|
"type": "array",
|
|
10767
10752
|
"default": "[null]"
|
|
10768
10753
|
},
|
|
10769
|
-
{
|
|
10770
|
-
"name": "value",
|
|
10771
|
-
"attribute": "value",
|
|
10772
|
-
"type": "string[] | undefined"
|
|
10773
|
-
},
|
|
10774
10754
|
{
|
|
10775
10755
|
"name": "config"
|
|
10776
10756
|
},
|
|
@@ -11522,10 +11502,6 @@
|
|
|
11522
11502
|
"name": "umb-property-editor-ui-multiple-text-string",
|
|
11523
11503
|
"path": "./../src/packages/property-editors/multiple-text-string/property-editor-ui-multiple-text-string.element.ts",
|
|
11524
11504
|
"attributes": [
|
|
11525
|
-
{
|
|
11526
|
-
"name": "value",
|
|
11527
|
-
"type": "string[] | undefined"
|
|
11528
|
-
},
|
|
11529
11505
|
{
|
|
11530
11506
|
"name": "disabled",
|
|
11531
11507
|
"description": "Disables the Multiple Text String Property Editor UI",
|
|
@@ -11546,11 +11522,6 @@
|
|
|
11546
11522
|
}
|
|
11547
11523
|
],
|
|
11548
11524
|
"properties": [
|
|
11549
|
-
{
|
|
11550
|
-
"name": "value",
|
|
11551
|
-
"attribute": "value",
|
|
11552
|
-
"type": "string[] | undefined"
|
|
11553
|
-
},
|
|
11554
11525
|
{
|
|
11555
11526
|
"name": "config"
|
|
11556
11527
|
},
|
|
@@ -1753,7 +1753,6 @@ export type PublishDocumentRequestModel = {
|
|
|
1753
1753
|
};
|
|
1754
1754
|
export type PublishDocumentWithDescendantsRequestModel = {
|
|
1755
1755
|
includeUnpublishedDescendants: boolean;
|
|
1756
|
-
forceRepublish: boolean;
|
|
1757
1756
|
cultures: Array<(string)>;
|
|
1758
1757
|
};
|
|
1759
1758
|
export type PublishedDocumentResponseModel = {
|
|
@@ -25,8 +25,9 @@ export class UmbContextProviderController extends UmbContextProvider {
|
|
|
25
25
|
}
|
|
26
26
|
destroy() {
|
|
27
27
|
if (this.#host) {
|
|
28
|
-
this.#host
|
|
28
|
+
const host = this.#host;
|
|
29
29
|
this.#host = undefined;
|
|
30
|
+
host.removeUmbController(this);
|
|
30
31
|
}
|
|
31
32
|
super.destroy();
|
|
32
33
|
}
|
|
@@ -84,8 +84,7 @@ export class UmbContextProvider {
|
|
|
84
84
|
// Note we are not removing the event listener in the hostDisconnected, therefor we do it here [NL].
|
|
85
85
|
this.#eventTarget?.removeEventListener(UMB_CONTEXT_REQUEST_EVENT_TYPE, this.#handleContextRequest);
|
|
86
86
|
this.#eventTarget?.removeEventListener(UMB_DEBUG_CONTEXT_EVENT_TYPE, this.#handleDebugContextRequest);
|
|
87
|
-
// We want to call a destroy method on the instance,
|
|
88
|
-
this.#instance?.destroy?.();
|
|
87
|
+
// We do not want to call a destroy method on the instance, because maybe it should be re-provided later on. [NL]
|
|
89
88
|
this.#instance = undefined;
|
|
90
89
|
this.#eventTarget = undefined;
|
|
91
90
|
}
|
|
@@ -135,7 +135,7 @@ export class UmbBlockElementManager extends UmbControllerBase {
|
|
|
135
135
|
if (!editorAlias) {
|
|
136
136
|
throw new Error(`Editor Alias of "${property.dataType.unique}" not found.`);
|
|
137
137
|
}
|
|
138
|
-
const entry = { ...variantId.toObject(), alias,
|
|
138
|
+
const entry = { editorAlias, ...variantId.toObject(), alias, value };
|
|
139
139
|
const currentData = this.getData();
|
|
140
140
|
if (currentData) {
|
|
141
141
|
const values = appendToFrozenArray(currentData.values ?? [], entry, (x) => x.alias === alias && variantId.compare(x));
|
|
@@ -119,12 +119,13 @@ let UmbPropertyEditorUIBlockListElement = class UmbPropertyEditorUIBlockListElem
|
|
|
119
119
|
});
|
|
120
120
|
// Observe Blocks and clean up validation messages for content/settings that are not in the block list anymore:
|
|
121
121
|
this.observe(this.#managerContext.layouts, (layouts) => {
|
|
122
|
+
const validationMessagesToRemove = [];
|
|
122
123
|
const contentKeys = layouts.map((x) => x.contentKey);
|
|
123
124
|
this.#validationContext.messages.getMessagesOfPathAndDescendant('$.contentData').forEach((message) => {
|
|
124
125
|
// get the KEY from this string: $.contentData[?(@.key == 'KEY')]
|
|
125
126
|
const key = extractJsonQueryProps(message.path).key;
|
|
126
127
|
if (key && contentKeys.indexOf(key) === -1) {
|
|
127
|
-
|
|
128
|
+
validationMessagesToRemove.push(message.key);
|
|
128
129
|
}
|
|
129
130
|
});
|
|
130
131
|
const settingsKeys = layouts.map((x) => x.settingsKey).filter((x) => x !== undefined);
|
|
@@ -132,9 +133,11 @@ let UmbPropertyEditorUIBlockListElement = class UmbPropertyEditorUIBlockListElem
|
|
|
132
133
|
// get the key from this string: $.settingsData[?(@.key == 'KEY')]
|
|
133
134
|
const key = extractJsonQueryProps(message.path).key;
|
|
134
135
|
if (key && settingsKeys.indexOf(key) === -1) {
|
|
135
|
-
|
|
136
|
+
validationMessagesToRemove.push(message.key);
|
|
136
137
|
}
|
|
137
138
|
});
|
|
139
|
+
// Remove the messages after the loop to prevent changing the array while iterating over it.
|
|
140
|
+
this.#validationContext.messages.removeMessageByKeys(validationMessagesToRemove);
|
|
138
141
|
}, null);
|
|
139
142
|
this.consumeContext(UMB_PROPERTY_DATASET_CONTEXT, (context) => {
|
|
140
143
|
this.#managerContext.setVariantId(context.getVariantId());
|
|
@@ -332,7 +332,7 @@ export class UmbContentDetailWorkspaceContextBase extends UmbEntityDetailWorkspa
|
|
|
332
332
|
throw new Error(`Editor Alias of "${property.dataType.unique}" not found.`);
|
|
333
333
|
}
|
|
334
334
|
// Notice the order of the properties is important for our JSON String Compare function. [NL]
|
|
335
|
-
const entry = { editorAlias,
|
|
335
|
+
const entry = { editorAlias, ...variantId.toObject(), alias, value };
|
|
336
336
|
const currentData = this.getData();
|
|
337
337
|
if (currentData) {
|
|
338
338
|
const values = appendToFrozenArray(currentData.values ?? [], entry, (x) => x.alias === alias && variantId.compare(x));
|
|
@@ -69,7 +69,7 @@ export class UmbLocalizationRegistry {
|
|
|
69
69
|
if (!translations.length)
|
|
70
70
|
return;
|
|
71
71
|
if (diff.length) {
|
|
72
|
-
const filteredTranslations = translations.filter((t) => diff.some((ext) => ext.meta.culture === t.$code));
|
|
72
|
+
const filteredTranslations = translations.filter((t) => diff.some((ext) => ext.meta.culture.toLowerCase() === t.$code));
|
|
73
73
|
umbLocalizationManager.registerManyLocalizations(filteredTranslations);
|
|
74
74
|
}
|
|
75
75
|
// Set the document language
|
|
@@ -11,6 +11,9 @@ export declare class UmbValidationMessagesManager {
|
|
|
11
11
|
#private;
|
|
12
12
|
messages: Observable<UmbValidationMessage[]>;
|
|
13
13
|
debug(logName: string): void;
|
|
14
|
+
getMessages(): Array<UmbValidationMessage>;
|
|
15
|
+
initiateChange(): void;
|
|
16
|
+
finishChange(): void;
|
|
14
17
|
getHasAnyMessages(): boolean;
|
|
15
18
|
getMessagesOfPathAndDescendant(path: string): Array<UmbValidationMessage>;
|
|
16
19
|
messagesOfPathAndDescendant(path: string): Observable<Array<UmbValidationMessage>>;
|
|
@@ -15,12 +15,31 @@ export class UmbValidationMessagesManager {
|
|
|
15
15
|
constructor() {
|
|
16
16
|
this.#messages = new UmbArrayState([], (x) => x.key);
|
|
17
17
|
this.messages = this.#messages.asObservable();
|
|
18
|
+
this.#updateLock = 0;
|
|
18
19
|
this.#translators = [];
|
|
19
20
|
}
|
|
20
21
|
#messages;
|
|
21
22
|
debug(logName) {
|
|
22
23
|
this.messages.subscribe((x) => console.log(logName, x));
|
|
23
24
|
}
|
|
25
|
+
getMessages() {
|
|
26
|
+
return this.#messages.getValue();
|
|
27
|
+
}
|
|
28
|
+
#updateLock;
|
|
29
|
+
initiateChange() {
|
|
30
|
+
this.#updateLock++;
|
|
31
|
+
this.#messages.mute();
|
|
32
|
+
// TODO: When ready enable this code will enable handling a finish automatically by this implementation 'using myState.initiatePropertyValueChange()' (Relies on TS support of Using) [NL]
|
|
33
|
+
/*return {
|
|
34
|
+
[Symbol.dispose]: this.finishPropertyValueChange,
|
|
35
|
+
};*/
|
|
36
|
+
}
|
|
37
|
+
finishChange() {
|
|
38
|
+
this.#updateLock--;
|
|
39
|
+
if (this.#updateLock === 0) {
|
|
40
|
+
this.#messages.unmute();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
24
43
|
getHasAnyMessages() {
|
|
25
44
|
return this.#messages.getValue().length !== 0;
|
|
26
45
|
}
|
|
@@ -55,7 +74,9 @@ export class UmbValidationMessagesManager {
|
|
|
55
74
|
if (this.#messages.getValue().find((x) => x.type === type && x.path === path && x.body === body)) {
|
|
56
75
|
return;
|
|
57
76
|
}
|
|
77
|
+
this.initiateChange();
|
|
58
78
|
this.#messages.appendOne({ type, key, path, body: body });
|
|
79
|
+
this.finishChange();
|
|
59
80
|
}
|
|
60
81
|
addMessages(type, path, bodies) {
|
|
61
82
|
//path = this.#translatePath(path.toLowerCase()) ?? path.toLowerCase();
|
|
@@ -63,26 +84,42 @@ export class UmbValidationMessagesManager {
|
|
|
63
84
|
// filter out existing messages with the same path and type, and append the new messages: [NL]
|
|
64
85
|
const existingMessages = this.#messages.getValue();
|
|
65
86
|
const newBodies = bodies.filter((message) => existingMessages.find((x) => x.type === type && x.path === path && x.body === message) === undefined);
|
|
87
|
+
this.initiateChange();
|
|
66
88
|
this.#messages.append(newBodies.map((body) => ({ type, key: UmbId.new(), path, body })));
|
|
89
|
+
this.finishChange();
|
|
67
90
|
}
|
|
68
91
|
removeMessageByKey(key) {
|
|
92
|
+
this.initiateChange();
|
|
69
93
|
this.#messages.removeOne(key);
|
|
94
|
+
this.finishChange();
|
|
70
95
|
}
|
|
71
96
|
removeMessageByKeys(keys) {
|
|
97
|
+
if (keys.length === 0)
|
|
98
|
+
return;
|
|
99
|
+
this.initiateChange();
|
|
72
100
|
this.#messages.filter((x) => keys.indexOf(x.key) === -1);
|
|
101
|
+
this.finishChange();
|
|
73
102
|
}
|
|
74
103
|
removeMessagesByType(type) {
|
|
104
|
+
this.initiateChange();
|
|
75
105
|
this.#messages.filter((x) => x.type !== type);
|
|
106
|
+
this.finishChange();
|
|
76
107
|
}
|
|
77
108
|
removeMessagesByPath(path) {
|
|
109
|
+
this.initiateChange();
|
|
78
110
|
this.#messages.filter((x) => x.path !== path);
|
|
111
|
+
this.finishChange();
|
|
79
112
|
}
|
|
80
113
|
removeMessagesAndDescendantsByPath(path) {
|
|
114
|
+
this.initiateChange();
|
|
81
115
|
this.#messages.filter((x) => MatchPathOrDescendantPath(x.path, path));
|
|
116
|
+
this.finishChange();
|
|
82
117
|
}
|
|
83
118
|
removeMessagesByTypeAndPath(type, path) {
|
|
84
119
|
//path = path.toLowerCase();
|
|
120
|
+
this.initiateChange();
|
|
85
121
|
this.#messages.filter((x) => !(x.type === type && x.path === path));
|
|
122
|
+
this.finishChange();
|
|
86
123
|
}
|
|
87
124
|
#translatePath(path) {
|
|
88
125
|
//path = path.toLowerCase();
|
|
@@ -98,6 +135,7 @@ export class UmbValidationMessagesManager {
|
|
|
98
135
|
}
|
|
99
136
|
#translators;
|
|
100
137
|
addTranslator(translator) {
|
|
138
|
+
this.initiateChange();
|
|
101
139
|
if (this.#translators.indexOf(translator) === -1) {
|
|
102
140
|
this.#translators.push(translator);
|
|
103
141
|
}
|
|
@@ -111,6 +149,7 @@ export class UmbValidationMessagesManager {
|
|
|
111
149
|
this.#messages.updateOne(msg.key, { path: newPath });
|
|
112
150
|
}
|
|
113
151
|
}
|
|
152
|
+
this.finishChange();
|
|
114
153
|
}
|
|
115
154
|
removeTranslator(translator) {
|
|
116
155
|
const index = this.#translators.indexOf(translator);
|
|
@@ -27,8 +27,6 @@ export class UmbFormControlValidator extends UmbControllerBase {
|
|
|
27
27
|
}
|
|
28
28
|
});
|
|
29
29
|
this.#control = formControl;
|
|
30
|
-
this.#control.addEventListener(UmbValidationInvalidEvent.TYPE, this.#setInvalid);
|
|
31
|
-
this.#control.addEventListener(UmbValidationValidEvent.TYPE, this.#setValid);
|
|
32
30
|
}
|
|
33
31
|
get isValid() {
|
|
34
32
|
return this.#isValid;
|
|
@@ -68,12 +66,18 @@ export class UmbFormControlValidator extends UmbControllerBase {
|
|
|
68
66
|
}
|
|
69
67
|
hostConnected() {
|
|
70
68
|
super.hostConnected();
|
|
69
|
+
this.#control.addEventListener(UmbValidationInvalidEvent.TYPE, this.#setInvalid);
|
|
70
|
+
this.#control.addEventListener(UmbValidationValidEvent.TYPE, this.#setValid);
|
|
71
71
|
if (this.#context) {
|
|
72
72
|
this.#context.addValidator(this);
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
hostDisconnected() {
|
|
76
76
|
super.hostDisconnected();
|
|
77
|
+
if (this.#control) {
|
|
78
|
+
this.#control.removeEventListener(UmbValidationInvalidEvent.TYPE, this.#setInvalid);
|
|
79
|
+
this.#control.removeEventListener(UmbValidationValidEvent.TYPE, this.#setValid);
|
|
80
|
+
}
|
|
77
81
|
if (this.#context) {
|
|
78
82
|
this.#context.removeValidator(this);
|
|
79
83
|
// Remove any messages that this validator has added:
|
|
@@ -84,11 +88,9 @@ export class UmbFormControlValidator extends UmbControllerBase {
|
|
|
84
88
|
}
|
|
85
89
|
}
|
|
86
90
|
destroy() {
|
|
91
|
+
super.destroy();
|
|
87
92
|
if (this.#control) {
|
|
88
|
-
this.#control.removeEventListener(UmbValidationInvalidEvent.TYPE, this.#setInvalid);
|
|
89
|
-
this.#control.removeEventListener(UmbValidationValidEvent.TYPE, this.#setValid);
|
|
90
93
|
this.#control = undefined;
|
|
91
94
|
}
|
|
92
|
-
super.destroy();
|
|
93
95
|
}
|
|
94
96
|
}
|
|
@@ -48,6 +48,8 @@ export declare class UmbValidationController extends UmbControllerBase implement
|
|
|
48
48
|
* A message with the path: '$.values[?(@.alias == 'my-property')].value.innerProperty', will for above example become '$.innerProperty' for the local Validation Context.
|
|
49
49
|
*/
|
|
50
50
|
setDataPath(dataPath: string): void;
|
|
51
|
+
hostConnected(): void;
|
|
52
|
+
hostDisconnected(): void;
|
|
51
53
|
/**
|
|
52
54
|
* Get if this context is valid.
|
|
53
55
|
* Notice this does not verify the validity.
|
|
@@ -106,11 +106,12 @@ export class UmbValidationController extends UmbControllerBase {
|
|
|
106
106
|
this.setTranslationData(data);
|
|
107
107
|
});
|
|
108
108
|
this.observe(parent.messages.messagesOfPathAndDescendant(dataPath), (msgs) => {
|
|
109
|
+
this.messages.initiateChange();
|
|
109
110
|
//this.messages.appendMessages(msgs);
|
|
110
111
|
if (this.#parentMessages) {
|
|
111
112
|
// Remove the local messages that does not exist in the parent anymore:
|
|
112
113
|
const toRemove = this.#parentMessages.filter((msg) => !msgs.find((m) => m.key === msg.key));
|
|
113
|
-
this
|
|
114
|
+
this.messages.removeMessageByKeys(toRemove.map((msg) => msg.key));
|
|
114
115
|
}
|
|
115
116
|
this.#parentMessages = msgs;
|
|
116
117
|
msgs.forEach((msg) => {
|
|
@@ -121,10 +122,12 @@ export class UmbValidationController extends UmbControllerBase {
|
|
|
121
122
|
// Notice, the local message uses the same key. [NL]
|
|
122
123
|
this.messages.addMessage(msg.type, path, msg.body, msg.key);
|
|
123
124
|
});
|
|
125
|
+
this.messages.finishChange();
|
|
124
126
|
}, 'observeParentMessages');
|
|
125
127
|
this.observe(this.messages.messages, (msgs) => {
|
|
126
128
|
if (!this.#parent)
|
|
127
129
|
return;
|
|
130
|
+
this.#parent.messages.initiateChange();
|
|
128
131
|
//this.messages.appendMessages(msgs);
|
|
129
132
|
if (this.#localMessages) {
|
|
130
133
|
// Remove the parent messages that does not exist locally anymore:
|
|
@@ -141,10 +144,23 @@ export class UmbValidationController extends UmbControllerBase {
|
|
|
141
144
|
// Notice, the parent message uses the same key. [NL]
|
|
142
145
|
this.#parent.messages.addMessage(msg.type, path, msg.body, msg.key);
|
|
143
146
|
});
|
|
147
|
+
this.#parent.messages.finishChange();
|
|
144
148
|
}, 'observeLocalMessages');
|
|
145
149
|
}).skipHost();
|
|
146
150
|
// Notice skipHost ^^, this is because we do not want it to consume it self, as this would be a match for this consumption, instead we will look at the parent and above. [NL]
|
|
147
151
|
}
|
|
152
|
+
hostConnected() {
|
|
153
|
+
super.hostConnected();
|
|
154
|
+
if (this.#parent) {
|
|
155
|
+
this.#parent.addValidator(this);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
hostDisconnected() {
|
|
159
|
+
super.hostDisconnected();
|
|
160
|
+
if (this.#parent) {
|
|
161
|
+
this.#parent.removeValidator(this);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
148
164
|
/**
|
|
149
165
|
* Get if this context is valid.
|
|
150
166
|
* Notice this does not verify the validity.
|
|
@@ -195,15 +211,22 @@ export class UmbValidationController extends UmbControllerBase {
|
|
|
195
211
|
// TODO: clear server messages here?, well maybe only if we know we will get new server messages? Do the server messages hook into the system like another validator?
|
|
196
212
|
this.#validationMode = true;
|
|
197
213
|
const resultsStatus = await Promise.all(this.#validators.map((v) => v.validate())).then(() => true, () => false);
|
|
198
|
-
if (
|
|
214
|
+
/*if (this.#validators.length === 0 && resultsStatus === false) {
|
|
215
|
+
throw new Error('No validators to validate, but validation failed');
|
|
216
|
+
}*/
|
|
217
|
+
if (this.messages === undefined) {
|
|
199
218
|
// This Context has been destroyed while is was validating, so we should not continue.
|
|
200
219
|
return Promise.reject();
|
|
201
220
|
}
|
|
221
|
+
const hasMessages = this.messages.getHasAnyMessages();
|
|
202
222
|
// If we have any messages then we are not valid, otherwise lets check the validation results: [NL]
|
|
203
223
|
// This enables us to keep client validations though UI is not present anymore — because the client validations got defined as messages. [NL]
|
|
204
|
-
const isValid =
|
|
224
|
+
const isValid = hasMessages ? false : resultsStatus;
|
|
205
225
|
this.#isValid = isValid;
|
|
206
226
|
if (isValid === false) {
|
|
227
|
+
/*if (hasMessages === false && resultsStatus === false) {
|
|
228
|
+
throw new Error('Missing validation messages to represent why a child validation context is invalid.');
|
|
229
|
+
}*/
|
|
207
230
|
// Focus first invalid element:
|
|
208
231
|
this.focusFirstInvalidElement();
|
|
209
232
|
return Promise.reject();
|
|
@@ -237,6 +260,7 @@ export class UmbValidationController extends UmbControllerBase {
|
|
|
237
260
|
this.#validators = [];
|
|
238
261
|
}
|
|
239
262
|
destroy() {
|
|
263
|
+
this.#providerCtrl?.destroy();
|
|
240
264
|
this.#providerCtrl = undefined;
|
|
241
265
|
if (this.#parent) {
|
|
242
266
|
this.#parent.removeValidator(this);
|
|
@@ -4,4 +4,4 @@
|
|
|
4
4
|
* @param {string} path - the JSON path to the value that should be found
|
|
5
5
|
* @returns {unknown} - the found value.
|
|
6
6
|
*/
|
|
7
|
-
export declare function GetValueByJsonPath(data: unknown, path: string):
|
|
7
|
+
export declare function GetValueByJsonPath<ReturnType = unknown>(data: unknown, path: string): ReturnType | undefined;
|
|
@@ -5,7 +5,12 @@
|
|
|
5
5
|
* @returns {unknown} - the found value.
|
|
6
6
|
*/
|
|
7
7
|
export function GetValueByJsonPath(data, path) {
|
|
8
|
+
if (path === '$')
|
|
9
|
+
return data;
|
|
8
10
|
// strip $ from the path:
|
|
11
|
+
if (path.startsWith('$[')) {
|
|
12
|
+
return _GetNextArrayEntryFromPath(data, path.slice(2));
|
|
13
|
+
}
|
|
9
14
|
const strippedPath = path.startsWith('$.') ? path.slice(2) : path;
|
|
10
15
|
// get value from the path:
|
|
11
16
|
return GetNextPropertyValueFromPath(data, strippedPath);
|
|
@@ -36,48 +41,59 @@ function GetNextPropertyValueFromPath(data, path) {
|
|
|
36
41
|
return value;
|
|
37
42
|
// if the value is an array, get the value at the index:
|
|
38
43
|
if (Array.isArray(value)) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
44
|
+
return _GetNextArrayEntryFromPath(value, rest);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
// continue with the rest of the path:
|
|
48
|
+
return GetNextPropertyValueFromPath(value, rest);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* @private
|
|
53
|
+
* @param {object} array - object to traverse for the value.
|
|
54
|
+
* @param {string} path - the JSON path to the value that should be found, notice without the starting '['
|
|
55
|
+
* @returns {unknown} - the found value.
|
|
56
|
+
*/
|
|
57
|
+
function _GetNextArrayEntryFromPath(array, path) {
|
|
58
|
+
if (!array)
|
|
59
|
+
return undefined;
|
|
60
|
+
// get the value until the next ']', the value can be anything in between the brackets:
|
|
61
|
+
const lookupEnd = path.match(/\]/);
|
|
62
|
+
if (!lookupEnd)
|
|
63
|
+
return undefined;
|
|
64
|
+
// get everything before the match:
|
|
65
|
+
const entryPointer = path.slice(0, lookupEnd.index);
|
|
66
|
+
// check if the entryPointer is a JSON Path Filter ( starting with ?( and ending with ) ):
|
|
67
|
+
if (entryPointer.startsWith('?(') && entryPointer.endsWith(')')) {
|
|
68
|
+
// get the filter from the entryPointer:
|
|
69
|
+
// get the filter as a function:
|
|
70
|
+
const jsFilter = JsFilterFromJsonPathFilter(entryPointer);
|
|
71
|
+
// find the index of the value that matches the filter:
|
|
72
|
+
const index = array.findIndex(jsFilter[0]);
|
|
73
|
+
// if the index is -1, return undefined:
|
|
74
|
+
if (index === -1)
|
|
42
75
|
return undefined;
|
|
43
|
-
// get
|
|
44
|
-
const
|
|
45
|
-
//
|
|
46
|
-
if (
|
|
47
|
-
|
|
48
|
-
// get the filter as a function:
|
|
49
|
-
const jsFilter = JsFilterFromJsonPathFilter(entryPointer);
|
|
50
|
-
// find the index of the value that matches the filter:
|
|
51
|
-
const index = value.findIndex(jsFilter[0]);
|
|
52
|
-
// if the index is -1, return undefined:
|
|
53
|
-
if (index === -1)
|
|
54
|
-
return undefined;
|
|
55
|
-
// get the value at the index:
|
|
56
|
-
const data = value[index];
|
|
57
|
-
// Check for safety:
|
|
58
|
-
if (lookupEnd.index === undefined || lookupEnd.index + 1 >= rest.length) {
|
|
59
|
-
return data;
|
|
60
|
-
}
|
|
61
|
-
// continue with the rest of the path:
|
|
62
|
-
return GetNextPropertyValueFromPath(data, rest.slice(lookupEnd.index + 2)) ?? data;
|
|
63
|
-
}
|
|
64
|
-
else {
|
|
65
|
-
// get the value at the index:
|
|
66
|
-
const indexAsNumber = parseInt(entryPointer);
|
|
67
|
-
if (isNaN(indexAsNumber))
|
|
68
|
-
return undefined;
|
|
69
|
-
const data = value[indexAsNumber];
|
|
70
|
-
// Check for safety:
|
|
71
|
-
if (lookupEnd.index === undefined || lookupEnd.index + 1 >= rest.length) {
|
|
72
|
-
return data;
|
|
73
|
-
}
|
|
74
|
-
// continue with the rest of the path:
|
|
75
|
-
return GetNextPropertyValueFromPath(data, rest.slice(lookupEnd.index + 2)) ?? data;
|
|
76
|
+
// get the value at the index:
|
|
77
|
+
const entryData = array[index];
|
|
78
|
+
// Check for safety:
|
|
79
|
+
if (lookupEnd.index === undefined || lookupEnd.index + 1 >= path.length) {
|
|
80
|
+
return entryData;
|
|
76
81
|
}
|
|
82
|
+
// continue with the rest of the path:
|
|
83
|
+
return GetNextPropertyValueFromPath(entryData, path.slice(lookupEnd.index + 2)) ?? entryData;
|
|
77
84
|
}
|
|
78
85
|
else {
|
|
86
|
+
// get the value at the index:
|
|
87
|
+
const indexAsNumber = parseInt(entryPointer);
|
|
88
|
+
if (isNaN(indexAsNumber))
|
|
89
|
+
return undefined;
|
|
90
|
+
const entryData = array[indexAsNumber];
|
|
91
|
+
// Check for safety:
|
|
92
|
+
if (lookupEnd.index === undefined || lookupEnd.index + 1 >= path.length) {
|
|
93
|
+
return entryData;
|
|
94
|
+
}
|
|
79
95
|
// continue with the rest of the path:
|
|
80
|
-
return GetNextPropertyValueFromPath(
|
|
96
|
+
return GetNextPropertyValueFromPath(entryData, path.slice(lookupEnd.index + 2)) ?? entryData;
|
|
81
97
|
}
|
|
82
98
|
}
|
|
83
99
|
/**
|