Skip to content

Commit 023b49a

Browse files
committed
make the notification layout handle structured list
1 parent 577e201 commit 023b49a

File tree

3 files changed

+53
-20
lines changed

3 files changed

+53
-20
lines changed

src/packages/core/notification/layouts/default/notification-layout-default.element.ts

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
import { html, LitElement, customElement, property, ifDefined } from '@umbraco-cms/backoffice/external/lit';
1+
import {
2+
html,
3+
LitElement,
4+
customElement,
5+
property,
6+
ifDefined,
7+
nothing,
8+
css,
9+
} from '@umbraco-cms/backoffice/external/lit';
210
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
311
import type { UmbNotificationDefaultData, UmbNotificationHandler } from '@umbraco-cms/backoffice/notification';
412

@@ -16,11 +24,46 @@ export class UmbNotificationLayoutDefaultElement extends LitElement {
1624
return html`
1725
<uui-toast-notification-layout id="layout" headline="${ifDefined(this.data.headline)}" class="uui-text">
1826
<div id="message">${this.data.message}</div>
27+
${this.#renderStructuredList(this.data.structuredList)}
1928
</uui-toast-notification-layout>
2029
`;
2130
}
2231

23-
static override styles = [UmbTextStyles];
32+
#renderStructuredList(list: unknown) {
33+
if (!this.data.structuredList) return nothing;
34+
if (typeof list !== 'object' || list === null) return nothing;
35+
36+
return html`${Object.entries(list).map(
37+
([property, errors]) =>
38+
html`<div class="structured-list">
39+
<span>${property}:</span>
40+
<ul>
41+
${this.#renderListItem(errors)}
42+
</ul>
43+
</div>`,
44+
)}`;
45+
}
46+
47+
#renderListItem(items: unknown) {
48+
if (Array.isArray(items)) {
49+
return items.map((item) => html`<li>${item}</li>`);
50+
} else {
51+
return html`<li>${items}</li>`;
52+
}
53+
}
54+
55+
static override styles = [
56+
UmbTextStyles,
57+
css`
58+
.structured-list ul {
59+
margin: 0;
60+
}
61+
.structured-list span {
62+
display: block;
63+
padding: var(--uui-size-3) 0 var(--uui-size-1);
64+
}
65+
`,
66+
];
2467
}
2568

2669
declare global {

src/packages/core/notification/notification.context.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { UmbBasicState } from '@umbraco-cms/backoffice/observable-api';
1212
export interface UmbNotificationDefaultData {
1313
message: string;
1414
headline?: string;
15+
structuredList?: Record<string, Array<unknown>>;
1516
}
1617

1718
/**

src/packages/core/resources/resource.controller.ts

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
/* eslint-disable @typescript-eslint/no-explicit-any */
22
import { UMB_AUTH_CONTEXT } from '../auth/index.js';
33
import { isApiError, isCancelError, isCancelablePromise } from './apiTypeValidators.function.js';
4-
import { html } from '@umbraco-cms/backoffice/external/lit';
54
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
65
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
76
import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api';
8-
import { UMB_NOTIFICATION_CONTEXT, type UmbNotificationOptions } from '@umbraco-cms/backoffice/notification';
7+
import {
8+
UMB_NOTIFICATION_CONTEXT,
9+
type UmbNotificationDefaultData,
10+
type UmbNotificationOptions,
11+
} from '@umbraco-cms/backoffice/notification';
912
import type { UmbDataSourceResponse } from '@umbraco-cms/backoffice/repository';
1013

1114
export type ErrorMessageText = { property: string; messages: string[] };
@@ -39,20 +42,6 @@ export class UmbResourceController extends UmbControllerBase {
3942
this.cancel();
4043
}
4144

42-
#buildApiErrorMessage(error: ErrorMessageText) {
43-
if (!error) return undefined;
44-
if (typeof error !== 'object') return undefined;
45-
46-
const entries: Array<ErrorMessageText> = [];
47-
Object.entries(error).forEach(([property, message]) => {
48-
entries.push({ property, messages: Array.isArray(message) ? message : [message] });
49-
});
50-
51-
const template = html` ${entries.map((e) => e.messages.map((msg: string) => html`<div>${msg}</div>`))}`;
52-
53-
return template;
54-
}
55-
5645
/**
5746
* Base execute function with a try/catch block and return a tuple with the result and the error.
5847
*/
@@ -146,11 +135,11 @@ export class UmbResourceController extends UmbControllerBase {
146135
default:
147136
// Other errors
148137
if (this.#notificationContext) {
149-
const message = this.#buildApiErrorMessage(error?.body?.errors);
150138
this.#notificationContext.peek('danger', {
151139
data: {
152140
headline: error.body?.title ?? error.name ?? 'Server Error',
153-
message: message ?? error.body?.detail ?? error.message ?? 'Something went wrong',
141+
message: error.body?.detail ?? error.message ?? 'Something went wrong',
142+
structuredList: error.body.errors,
154143
},
155144
...options,
156145
});

0 commit comments

Comments
 (0)