make the notification layout handle structured list

This commit is contained in:
Lone Iversen
2024-07-04 11:17:32 +02:00
parent efb9541cd4
commit acbc497200
3 changed files with 53 additions and 20 deletions

View File

@@ -1,4 +1,12 @@
import { html, LitElement, customElement, property, ifDefined } from '@umbraco-cms/backoffice/external/lit';
import {
html,
LitElement,
customElement,
property,
ifDefined,
nothing,
css,
} from '@umbraco-cms/backoffice/external/lit';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import type { UmbNotificationDefaultData, UmbNotificationHandler } from '@umbraco-cms/backoffice/notification';
@@ -16,11 +24,46 @@ export class UmbNotificationLayoutDefaultElement extends LitElement {
return html`
<uui-toast-notification-layout id="layout" headline="${ifDefined(this.data.headline)}" class="uui-text">
<div id="message">${this.data.message}</div>
${this.#renderStructuredList(this.data.structuredList)}
</uui-toast-notification-layout>
`;
}
static override styles = [UmbTextStyles];
#renderStructuredList(list: unknown) {
if (!this.data.structuredList) return nothing;
if (typeof list !== 'object' || list === null) return nothing;
return html`${Object.entries(list).map(
([property, errors]) =>
html`<div class="structured-list">
<span>${property}:</span>
<ul>
${this.#renderListItem(errors)}
</ul>
</div>`,
)}`;
}
#renderListItem(items: unknown) {
if (Array.isArray(items)) {
return items.map((item) => html`<li>${item}</li>`);
} else {
return html`<li>${items}</li>`;
}
}
static override styles = [
UmbTextStyles,
css`
.structured-list ul {
margin: 0;
}
.structured-list span {
display: block;
padding: var(--uui-size-3) 0 var(--uui-size-1);
}
`,
];
}
declare global {

View File

@@ -12,6 +12,7 @@ import { UmbBasicState } from '@umbraco-cms/backoffice/observable-api';
export interface UmbNotificationDefaultData {
message: string;
headline?: string;
structuredList?: Record<string, Array<unknown>>;
}
/**

View File

@@ -1,11 +1,14 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { UMB_AUTH_CONTEXT } from '../auth/index.js';
import { isApiError, isCancelError, isCancelablePromise } from './apiTypeValidators.function.js';
import { html } from '@umbraco-cms/backoffice/external/lit';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api';
import { UMB_NOTIFICATION_CONTEXT, type UmbNotificationOptions } from '@umbraco-cms/backoffice/notification';
import {
UMB_NOTIFICATION_CONTEXT,
type UmbNotificationDefaultData,
type UmbNotificationOptions,
} from '@umbraco-cms/backoffice/notification';
import type { UmbDataSourceResponse } from '@umbraco-cms/backoffice/repository';
export type ErrorMessageText = { property: string; messages: string[] };
@@ -39,20 +42,6 @@ export class UmbResourceController extends UmbControllerBase {
this.cancel();
}
#buildApiErrorMessage(error: ErrorMessageText) {
if (!error) return undefined;
if (typeof error !== 'object') return undefined;
const entries: Array<ErrorMessageText> = [];
Object.entries(error).forEach(([property, message]) => {
entries.push({ property, messages: Array.isArray(message) ? message : [message] });
});
const template = html` ${entries.map((e) => e.messages.map((msg: string) => html`<div>${msg}</div>`))}`;
return template;
}
/**
* Base execute function with a try/catch block and return a tuple with the result and the error.
*/
@@ -146,11 +135,11 @@ export class UmbResourceController extends UmbControllerBase {
default:
// Other errors
if (this.#notificationContext) {
const message = this.#buildApiErrorMessage(error?.body?.errors);
this.#notificationContext.peek('danger', {
data: {
headline: error.body?.title ?? error.name ?? 'Server Error',
message: message ?? error.body?.detail ?? error.message ?? 'Something went wrong',
message: error.body?.detail ?? error.message ?? 'Something went wrong',
structuredList: error.body.errors,
},
...options,
});