From c43a5b45f6a1f13ad27ccdc2953b7495105fe440 Mon Sep 17 00:00:00 2001 From: Lone Iversen <108085781+loivsen@users.noreply.github.com> Date: Mon, 21 Nov 2022 16:31:43 +0100 Subject: [PATCH] init --- .../dashboard-models-builder.element.ts | 150 +++++++++++++++++- .../src/core/mocks/browser-handlers.ts | 2 + .../mocks/domains/modelsbuilder.handlers.ts | 50 ++++++ .../src/core/mocks/e2e-handlers.ts | 2 + .../src/core/utils/errorbox.ts | 60 +++++++ 5 files changed, 259 insertions(+), 5 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/core/mocks/domains/modelsbuilder.handlers.ts create mode 100644 src/Umbraco.Web.UI.Client/src/core/utils/errorbox.ts diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/models-builder/dashboard-models-builder.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/models-builder/dashboard-models-builder.element.ts index ee13ac50d5..ddf8490982 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/models-builder/dashboard-models-builder.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/models-builder/dashboard-models-builder.element.ts @@ -1,15 +1,155 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; -import { css, html, LitElement } from 'lit'; -import { customElement } from 'lit/decorators.js'; +import { css, html, LitElement, nothing } from 'lit'; +import { state, customElement } from 'lit/decorators.js'; +import { unsafeHTML } from 'lit/directives/unsafe-html.js'; + +import { UUIButtonState } from '@umbraco-ui/uui'; +import { UmbContextConsumerMixin } from '@umbraco-cms/context-api'; +import { UmbNotificationService, UmbNotificationDefaultData } from '@umbraco-cms/services'; +import { + ApiError, + CreatedResult, + ModelsBuilder, + ModelsBuilderResource, + ProblemDetails, +} from '@umbraco-cms/backend-api'; + +import 'src/core/utils/errorbox'; @customElement('umb-dashboard-models-builder') -export class UmbDashboardModelsBuilderElement extends LitElement { - static styles = [UUITextStyles, css``]; +export class UmbDashboardModelsBuilderElement extends UmbContextConsumerMixin(LitElement) { + static styles = [ + UUITextStyles, + css` + .headline { + display: flex; + justify-content: space-between; + align-items: center; + } + + p { + margin-block-start: 0; + margin-block-end: var(--uui-size-space-4); + } + + .models-description p { + padding-bottom: var(--uui-size-space-1); + margin-bottom: var(--uui-size-space-1); + } + + .models-description ul { + list-style-type: square; + margin: 0; + padding-left: var(--uui-size-layout-1); + } + + .error { + padding-top: var(--uui-size-space-5); + font-weight: bold; + color: var(--uui-color-danger); + } + `, + ]; + + private _notificationService?: UmbNotificationService; + + @state() + private _modelsBuilder?: ModelsBuilder; + + @state() + private _createdResult?: CreatedResult; + + @state() + private _buttonStateBuild: UUIButtonState = undefined; + + @state() + private _buttonStateReload: UUIButtonState = undefined; + + private async _getDashboardData() { + try { + const modelsBuilder = await ModelsBuilderResource.getModelsBuilderDashboard(); + this._modelsBuilder = modelsBuilder; + return true; + } catch (e) { + if (e instanceof ApiError) { + const error = e as ProblemDetails; + const data: UmbNotificationDefaultData = { + message: error.message ?? 'Something went wrong', + }; + this._notificationService?.peek('danger', { data }); + } + return false; + } + } + + private async _onGenerateModels() { + this._buttonStateBuild = 'waiting'; + const status = await this._postGenerateModels(); + this._buttonStateBuild = status ? 'success' : 'failed'; + } + + private async _postGenerateModels() { + try { + const createdResult = await ModelsBuilderResource.postModelsBuilderBuild(); + this._createdResult = createdResult; + return true; + } catch (e) { + if (e instanceof ApiError) { + const error = e as ProblemDetails; + const data: UmbNotificationDefaultData = { + message: error.message ?? 'Model generation failed', + }; + this._notificationService?.peek('danger', { data }); + } + return false; + } + } + + constructor() { + super(); + this._getDashboardData(); + this.consumeAllContexts(['umbNotificationService'], (instances) => { + this._notificationService = instances['umbNotificationService']; + }); + } + + private async _onDashboardReload() { + this._buttonStateReload = 'waiting'; + const status = await this._getDashboardData(); + this._buttonStateReload = status ? 'success' : 'failed'; + } render() { return html` -

Models Builder

+
+ Models Builder + + Reload + +
+

Version: ${this._modelsBuilder?.version}

+ +
+

${unsafeHTML(this._modelsBuilder?.modelsNamespace)}

+
+ + ${this._modelsBuilder?.outOfDateModels === true + ? html`

Models are out of date

` + : nothing} + ${this._modelsBuilder?.canGenerate === true + ? html` + Generate models + ` + : nothing} + ${this._modelsBuilder?.lastError + ? html`

Last generation failed with the following error:

+ ${this._modelsBuilder.lastError}` + : nothing}
`; } diff --git a/src/Umbraco.Web.UI.Client/src/core/mocks/browser-handlers.ts b/src/Umbraco.Web.UI.Client/src/core/mocks/browser-handlers.ts index aec1422525..a72c20b0bb 100644 --- a/src/Umbraco.Web.UI.Client/src/core/mocks/browser-handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/core/mocks/browser-handlers.ts @@ -12,6 +12,7 @@ import { handlers as telemetryHandlers } from './domains/telemetry.handlers'; import { handlers as usersHandlers } from './domains/users.handlers'; import { handlers as userGroupsHandlers } from './domains/user-groups.handlers'; import { handlers as examineManagementHandlers } from './domains/examine-management.handlers'; +import { handlers as modelsBuilderHandlers } from './domains/modelsbuilder.handlers'; const handlers = [ serverHandlers.serverVersionHandler, @@ -28,6 +29,7 @@ const handlers = [ ...usersHandlers, ...userGroupsHandlers, ...examineManagementHandlers, + ...modelsBuilderHandlers, ]; switch (import.meta.env.VITE_UMBRACO_INSTALL_STATUS) { diff --git a/src/Umbraco.Web.UI.Client/src/core/mocks/domains/modelsbuilder.handlers.ts b/src/Umbraco.Web.UI.Client/src/core/mocks/domains/modelsbuilder.handlers.ts new file mode 100644 index 0000000000..4e54347ecd --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/core/mocks/domains/modelsbuilder.handlers.ts @@ -0,0 +1,50 @@ +import { rest } from 'msw'; + +import { umbracoPath } from '@umbraco-cms/utils'; +import { CreatedResult, ModelsBuilder, OutOfDateStatus } from '@umbraco-cms/backend-api'; + +export const handlers = [ + rest.post(umbracoPath('/models-builder/build'), async (_req, res, ctx) => { + await new Promise((resolve) => setTimeout(resolve, (Math.random() + 1) * 1000)); // simulate a delay of 1-2 seconds + return res( + // Respond with a 200 status code + ctx.status(200), + ctx.json({}) + ); + }), + + rest.get(umbracoPath('/models-builder/dashboard'), async (_req, res, ctx) => { + return res( + ctx.status(200), + ctx.json({ + mode: undefined, + canGenerate: true, + outOfDateModels: true, + lastError: `[plugin:vite:import-analysis] Missing "./directives/unsafe-htl.js" export in "lit" package +C:/Users/Umbraco/Documents/Umbraco.CMS.Backoffice/src/backoffice/dashboards/models-builder/dashboard-models-builder.element.ts +at bail (file:///C:/Users/Umbraco/Documents/Umbraco.CMS.Backoffice/node_modules/vite/dist/node/chunks/dep-67e7f8ab.js:32675:8) +at resolve (file:///C:/Users/Umbraco/Documents/Umbraco.CMS.Backoffice/node_modules/vite/dist/node/chunks/dep-67e7f8ab.js:32752:10) +at resolveExports (file:///C:/Users/Umbraco/Documents/Umbraco.CMS.Backoffice/node_modules/vite/dist/node/chunks/dep-67e7f8ab.js:34128:12) +at resolveDeepImport (file:///C:/Users/Umbraco/Documents/Umbraco.CMS.Backoffice/node_modules/vite/dist/node/chunks/dep-67e7f8ab.js:34146:31) +at tryNodeResolve (file:///C:/Users/Umbraco/Documents/Umbraco.CMS.Backoffice/node_modules/vite/dist/node/chunks/dep-67e7f8ab.js:33838:20) +at Context.resolveId (file:///C:/Users/Umbraco/Documents/Umbraco.CMS.Backoffice/node_modules/vite/dist/node/chunks/dep-67e7f8ab.js:33598:28) +at async Object.resolveId (file:///C:/Users/Umbraco/Documents/Umbraco.CMS.Backoffice/node_modules/vite/dist/node/chunks/dep-67e7f8ab.js:40156:32) +at async TransformContext.resolve (file:///C:/Users/Umbraco/Documents/Umbraco.CMS.Backoffice/node_modules/vite/dist/node/chunks/dep-67e7f8ab.js:39921:23) +at async normalizeUrl (file:///C:/Users/Umbraco/Documents/Umbraco.CMS.Backoffice/node_modules/vite/dist/node/chunks/dep-67e7f8ab.js:36831:34) +at async TransformContext.transform (file:///C:/Users/Umbraco/Documents/Umbraco.CMS.Backoffice/node_modules/vit`, + version: '13.0.0', + modelsNamespace: + "

ModelsBuilder is enabled, with the following configuration:

", + trackingOutOfDateModels: true, + }) + ); + }), + + rest.get(umbracoPath('/models-builder/status'), async (_req, res, ctx) => { + return res( + // Respond with a 200 status code + ctx.status(200), + ctx.json({}) + ); + }), +]; diff --git a/src/Umbraco.Web.UI.Client/src/core/mocks/e2e-handlers.ts b/src/Umbraco.Web.UI.Client/src/core/mocks/e2e-handlers.ts index 811f3d15b2..6c59964ebe 100644 --- a/src/Umbraco.Web.UI.Client/src/core/mocks/e2e-handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/core/mocks/e2e-handlers.ts @@ -11,6 +11,7 @@ import { handlers as telemetryHandlers } from './domains/telemetry.handlers'; import { handlers as treeHandlers } from './domains/entity.handlers'; import { handlers as examineManagementHandlers } from './domains/examine-management.handlers'; +import { handlers as modelsBuilderHandlers } from './domains/modelsbuilder.handlers'; export const handlers = [ serverHandlers.serverRunningHandler, @@ -27,4 +28,5 @@ export const handlers = [ ...publishedStatusHandlers, ...treeHandlers, ...examineManagementHandlers, + ...modelsBuilderHandlers, ]; diff --git a/src/Umbraco.Web.UI.Client/src/core/utils/errorbox.ts b/src/Umbraco.Web.UI.Client/src/core/utils/errorbox.ts new file mode 100644 index 0000000000..79294e92e9 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/core/utils/errorbox.ts @@ -0,0 +1,60 @@ +import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; +import { css, html, LitElement } from 'lit'; +import { customElement } from 'lit/decorators.js'; + +/** + * A simple styled box for showing code-based error messages. + * max-height is 500px + * + * @slot the message + * + */ +@customElement('uui-error-box') +export class UUIErrorBox extends LitElement { + static styles = [ + UUITextStyles, + css` + :host { + display: block; + font-family: monospace; + } + + #container { + border: 2px solid var(--uui-color-divider-emphasis); + color: var(--uui-color-text-alt); + background-color: var(--uui-color-divider-standalone); + padding: var(--uui-size-space-2); + border-radius: var(--uui-border-radius); + line-height: var(--uui-size-10); + } + :host uui-scroll-container { + max-height: 500px; + } + + pre { + display: inline-block; + overflow-wrap: break-word; + word-wrap: break-word; + word-break: break-all; + line-break: strict; + hyphens: none; + -webkit-hyphens: none; + -moz-hyphens: none; + } + `, + ]; + + render() { + return html`
+ +
+
+
`; + } +} + +declare global { + interface HTMLElementTagNameMap { + 'uui-error-box': UUIErrorBox; + } +}