From d1b3f9464e1d0abbaa868bcdc3cfdf8d03dd72b1 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Wed, 24 Aug 2022 16:03:35 +0200 Subject: [PATCH 01/17] add schema for manifests --- src/Umbraco.Web.UI.Client/schemas/api/api.yml | 109 ++++++++++++++++++ .../temp-schema-generator/api.ts | 1 + .../temp-schema-generator/manifests.ts | 53 +++++++++ 3 files changed, 163 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/temp-schema-generator/manifests.ts diff --git a/src/Umbraco.Web.UI.Client/schemas/api/api.yml b/src/Umbraco.Web.UI.Client/schemas/api/api.yml index 974f5dc74a..a009719139 100644 --- a/src/Umbraco.Web.UI.Client/schemas/api/api.yml +++ b/src/Umbraco.Web.UI.Client/schemas/api/api.yml @@ -57,6 +57,22 @@ paths: application/json: schema: $ref: '#/components/schemas/ProblemDetails' + /manifests: + get: + operationId: Manifests + responses: + '200': + description: 200 response + content: + application/json: + schema: + $ref: '#/components/schemas/ManifestsResponse' + default: + description: default response + content: + application/json: + schema: + $ref: '#/components/schemas/ProblemDetails' /server/status: get: operationId: GetStatus @@ -341,6 +357,99 @@ components: required: - user - telemetryLevel + ManifestStandardTypes: + type: string + enum: + - section + - propertyEditorUI + - dashboard + MetaSection: + type: object + properties: + pathname: + type: string + weight: + type: number + format: float + required: + - pathname + - weight + MetaPropertyEditorUI: + type: object + properties: + icon: + type: string + group: + type: string + required: + - icon + - group + MetaDashboard: + type: object + properties: + sections: + type: array + items: + type: string + pathname: + type: string + weight: + type: number + format: float + required: + - sections + - pathname + - weight + IManifestElement: + type: object + properties: + type: + $ref: '#/components/schemas/ManifestStandardTypes' + alias: + type: string + name: + type: string + js: + type: string + elementName: + type: string + meta: + oneOf: + - $ref: '#/components/schemas/MetaSection' + - $ref: '#/components/schemas/MetaPropertyEditorUI' + - $ref: '#/components/schemas/MetaDashboard' + required: + - type + - alias + - name + - js + - elementName + - meta + IManifestEntrypoint: + type: object + properties: + type: + type: string + enum: + - entrypoint + js: + type: string + required: + - type + - js + Manifest: + oneOf: + - $ref: '#/components/schemas/IManifestElement' + - $ref: '#/components/schemas/IManifestEntrypoint' + ManifestsResponse: + type: object + properties: + manifests: + type: array + items: + $ref: '#/components/schemas/Manifest' + required: + - manifests ServerStatus: type: string enum: diff --git a/src/Umbraco.Web.UI.Client/temp-schema-generator/api.ts b/src/Umbraco.Web.UI.Client/temp-schema-generator/api.ts index 51cdd0acc6..c7eb465583 100644 --- a/src/Umbraco.Web.UI.Client/temp-schema-generator/api.ts +++ b/src/Umbraco.Web.UI.Client/temp-schema-generator/api.ts @@ -1,4 +1,5 @@ import './installer'; +import './manifests'; import './server'; import './upgrader'; import './user'; diff --git a/src/Umbraco.Web.UI.Client/temp-schema-generator/manifests.ts b/src/Umbraco.Web.UI.Client/temp-schema-generator/manifests.ts new file mode 100644 index 0000000000..ce9319ece5 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/temp-schema-generator/manifests.ts @@ -0,0 +1,53 @@ +import { body, defaultResponse, endpoint, response } from '@airtasker/spot'; + +import { ProblemDetails } from './models'; + +@endpoint({ method: 'GET', path: '/manifests' }) +export class Manifests { + @response({ status: 200 }) + response(@body body: ManifestsResponse) {} + + @defaultResponse + default(@body body: ProblemDetails) {} +} + +export type Manifest = IManifestElement | IManifestEntrypoint; +export type ManifestStandardTypes = 'section' | 'propertyEditorUI' | 'dashboard'; + +export interface ManifestsResponse { + manifests: Manifest[]; +} + +export interface IManifest { + type: string; +} + +export interface MetaSection { + pathname: string; + weight: number; +} + +export interface MetaPropertyEditorUI { + icon: string; + group: string; +} + +export interface MetaDashboard { + sections: string[]; + pathname: string; + weight: number; +} + +export interface IManifestElement extends IManifest { + type: ManifestStandardTypes; + alias: string; + name: string; + js: string; + elementName: string; + meta: MetaSection | MetaPropertyEditorUI | MetaDashboard; +} + +export interface IManifestEntrypoint extends IManifest { + type: 'entrypoint'; + js: string; +} From 47de2e25d3558cf271be95c4c49b8280cd181ffe Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 25 Aug 2022 09:34:54 +0200 Subject: [PATCH 02/17] add schema for manifests --- src/Umbraco.Web.UI.Client/schemas/api/api.yml | 168 ++++++++++++++++-- .../schemas/generated-schema.ts | 106 +++++++++++ .../temp-schema-generator/manifests.ts | 59 +++++- 3 files changed, 311 insertions(+), 22 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/schemas/api/api.yml b/src/Umbraco.Web.UI.Client/schemas/api/api.yml index a009719139..557d26d03b 100644 --- a/src/Umbraco.Web.UI.Client/schemas/api/api.yml +++ b/src/Umbraco.Web.UI.Client/schemas/api/api.yml @@ -357,12 +357,6 @@ components: required: - user - telemetryLevel - ManifestStandardTypes: - type: string - enum: - - section - - propertyEditorUI - - dashboard MetaSection: type: object properties: @@ -374,6 +368,30 @@ components: required: - pathname - weight + IManifestSection: + type: object + properties: + type: + type: string + enum: + - section + meta: + $ref: '#/components/schemas/MetaSection' + name: + type: string + js: + type: string + elementName: + type: string + alias: + type: string + required: + - type + - meta + - name + - js + - elementName + - alias MetaPropertyEditorUI: type: object properties: @@ -384,6 +402,30 @@ components: required: - icon - group + IManifestPropertyEditorUI: + type: object + properties: + type: + type: string + enum: + - propertyEditorUI + meta: + $ref: '#/components/schemas/MetaPropertyEditorUI' + name: + type: string + js: + type: string + elementName: + type: string + alias: + type: string + required: + - type + - meta + - name + - js + - elementName + - alias MetaDashboard: type: object properties: @@ -396,35 +438,113 @@ components: weight: type: number format: float + label: + type: string required: - sections - pathname - weight - IManifestElement: + - label + IManifestDashboard: type: object properties: type: - $ref: '#/components/schemas/ManifestStandardTypes' - alias: type: string + enum: + - dashboard + meta: + $ref: '#/components/schemas/MetaDashboard' name: type: string js: type: string elementName: type: string - meta: - oneOf: - - $ref: '#/components/schemas/MetaSection' - - $ref: '#/components/schemas/MetaPropertyEditorUI' - - $ref: '#/components/schemas/MetaDashboard' + alias: + type: string required: - type - - alias + - meta - name - js - elementName + - alias + MetaEditorView: + type: object + properties: + editors: + type: array + items: + type: string + pathname: + type: string + weight: + type: number + format: float + icon: + type: string + required: + - editors + - pathname + - weight + - icon + IManifestEditorView: + type: object + properties: + type: + type: string + enum: + - editorView + meta: + $ref: '#/components/schemas/MetaEditorView' + name: + type: string + js: + type: string + elementName: + type: string + alias: + type: string + required: + - type - meta + - name + - js + - elementName + - alias + MetaPropertyAction: + type: object + properties: + propertyEditors: + type: array + items: + type: string + required: + - propertyEditors + IManifestPropertyAction: + type: object + properties: + type: + type: string + enum: + - propertyAction + meta: + $ref: '#/components/schemas/MetaPropertyAction' + name: + type: string + js: + type: string + elementName: + type: string + alias: + type: string + required: + - type + - meta + - name + - js + - elementName + - alias IManifestEntrypoint: type: object properties: @@ -434,13 +554,29 @@ components: - entrypoint js: type: string + alias: + type: string required: - type - js + - alias Manifest: oneOf: - - $ref: '#/components/schemas/IManifestElement' + - $ref: '#/components/schemas/IManifestSection' + - $ref: '#/components/schemas/IManifestPropertyEditorUI' + - $ref: '#/components/schemas/IManifestDashboard' + - $ref: '#/components/schemas/IManifestEditorView' + - $ref: '#/components/schemas/IManifestPropertyAction' - $ref: '#/components/schemas/IManifestEntrypoint' + discriminator: + propertyName: type + mapping: + section: '#/components/schemas/IManifestSection' + propertyEditorUI: '#/components/schemas/IManifestPropertyEditorUI' + dashboard: '#/components/schemas/IManifestDashboard' + editorView: '#/components/schemas/IManifestEditorView' + propertyAction: '#/components/schemas/IManifestPropertyAction' + entrypoint: '#/components/schemas/IManifestEntrypoint' ManifestsResponse: type: object properties: diff --git a/src/Umbraco.Web.UI.Client/schemas/generated-schema.ts b/src/Umbraco.Web.UI.Client/schemas/generated-schema.ts index 4c9f3aa57f..8ecdb30d35 100644 --- a/src/Umbraco.Web.UI.Client/schemas/generated-schema.ts +++ b/src/Umbraco.Web.UI.Client/schemas/generated-schema.ts @@ -13,6 +13,9 @@ export interface paths { "/install/validateDatabase": { post: operations["PostInstallValidateDatabase"]; }; + "/manifests": { + get: operations["Manifests"]; + }; "/server/status": { get: operations["GetStatus"]; }; @@ -102,6 +105,93 @@ export interface components { telemetryLevel: components["schemas"]["ConsentLevel"]; database?: components["schemas"]["InstallSetupDatabaseConfiguration"]; }; + MetaSection: { + pathname: string; + /** Format: float */ + weight: number; + }; + IManifestSection: { + /** @enum {string} */ + type: "section"; + meta: components["schemas"]["MetaSection"]; + name: string; + js: string; + elementName: string; + alias: string; + }; + MetaPropertyEditorUI: { + icon: string; + group: string; + }; + IManifestPropertyEditorUI: { + /** @enum {string} */ + type: "propertyEditorUI"; + meta: components["schemas"]["MetaPropertyEditorUI"]; + name: string; + js: string; + elementName: string; + alias: string; + }; + MetaDashboard: { + sections: string[]; + pathname: string; + /** Format: float */ + weight: number; + label: string; + }; + IManifestDashboard: { + /** @enum {string} */ + type: "dashboard"; + meta: components["schemas"]["MetaDashboard"]; + name: string; + js: string; + elementName: string; + alias: string; + }; + MetaEditorView: { + editors: string[]; + pathname: string; + /** Format: float */ + weight: number; + icon: string; + }; + IManifestEditorView: { + /** @enum {string} */ + type: "editorView"; + meta: components["schemas"]["MetaEditorView"]; + name: string; + js: string; + elementName: string; + alias: string; + }; + MetaPropertyAction: { + propertyEditors: string[]; + }; + IManifestPropertyAction: { + /** @enum {string} */ + type: "propertyAction"; + meta: components["schemas"]["MetaPropertyAction"]; + name: string; + js: string; + elementName: string; + alias: string; + }; + IManifestEntrypoint: { + /** @enum {string} */ + type: "entrypoint"; + js: string; + alias: string; + }; + Manifest: + | components["schemas"]["IManifestSection"] + | components["schemas"]["IManifestPropertyEditorUI"] + | components["schemas"]["IManifestDashboard"] + | components["schemas"]["IManifestEditorView"] + | components["schemas"]["IManifestPropertyAction"] + | components["schemas"]["IManifestEntrypoint"]; + ManifestsResponse: { + manifests: components["schemas"]["Manifest"][]; + }; /** @enum {string} */ ServerStatus: "running" | "must-install" | "must-upgrade"; StatusResponse: { @@ -185,6 +275,22 @@ export interface operations { }; }; }; + Manifests: { + responses: { + /** 200 response */ + 200: { + content: { + "application/json": components["schemas"]["ManifestsResponse"]; + }; + }; + /** default response */ + default: { + content: { + "application/json": components["schemas"]["ProblemDetails"]; + }; + }; + }; + }; GetStatus: { responses: { /** 200 response */ diff --git a/src/Umbraco.Web.UI.Client/temp-schema-generator/manifests.ts b/src/Umbraco.Web.UI.Client/temp-schema-generator/manifests.ts index ce9319ece5..52c5ea4503 100644 --- a/src/Umbraco.Web.UI.Client/temp-schema-generator/manifests.ts +++ b/src/Umbraco.Web.UI.Client/temp-schema-generator/manifests.ts @@ -11,15 +11,28 @@ export class Manifests { default(@body body: ProblemDetails) {} } -export type Manifest = IManifestElement | IManifestEntrypoint; -export type ManifestStandardTypes = 'section' | 'propertyEditorUI' | 'dashboard'; +export type Manifest = + | IManifestSection + | IManifestPropertyEditorUI + | IManifestDashboard + | IManifestEditorView + | IManifestPropertyAction + | IManifestEntrypoint; +export type ManifestStandardTypes = + | 'section' + | 'propertyEditorUI' + | 'dashboard' + | 'editorView' + | 'propertyAction' + | 'entrypoint'; export interface ManifestsResponse { manifests: Manifest[]; } export interface IManifest { - type: string; + type: ManifestStandardTypes; + alias: string; } export interface MetaSection { @@ -36,15 +49,49 @@ export interface MetaDashboard { sections: string[]; pathname: string; weight: number; + label: string; +} + +export interface MetaEditorView { + editors: string[]; + pathname: string; + weight: number; + icon: string; +} + +export interface MetaPropertyAction { + propertyEditors: string[]; } export interface IManifestElement extends IManifest { - type: ManifestStandardTypes; - alias: string; name: string; js: string; elementName: string; - meta: MetaSection | MetaPropertyEditorUI | MetaDashboard; +} + +export interface IManifestSection extends IManifestElement { + type: 'section'; + meta: MetaSection; +} + +export interface IManifestPropertyEditorUI extends IManifestElement { + type: 'propertyEditorUI'; + meta: MetaPropertyEditorUI; +} + +export interface IManifestDashboard extends IManifestElement { + type: 'dashboard'; + meta: MetaDashboard; +} + +export interface IManifestEditorView extends IManifestElement { + type: 'editorView'; + meta: MetaEditorView; +} + +export interface IManifestPropertyAction extends IManifestElement { + type: 'propertyAction'; + meta: MetaPropertyAction; } export interface IManifestEntrypoint extends IManifest { From 3311af3d7f6cbc83b24a60affa4784c4dddc7206 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 25 Aug 2022 09:39:34 +0200 Subject: [PATCH 03/17] make js and label props optional --- src/Umbraco.Web.UI.Client/schemas/api/api.yml | 6 ------ .../schemas/generated-schema.ts | 12 ++++++------ .../temp-schema-generator/manifests.ts | 4 ++-- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/schemas/api/api.yml b/src/Umbraco.Web.UI.Client/schemas/api/api.yml index 557d26d03b..f0d2e83faf 100644 --- a/src/Umbraco.Web.UI.Client/schemas/api/api.yml +++ b/src/Umbraco.Web.UI.Client/schemas/api/api.yml @@ -389,7 +389,6 @@ components: - type - meta - name - - js - elementName - alias MetaPropertyEditorUI: @@ -423,7 +422,6 @@ components: - type - meta - name - - js - elementName - alias MetaDashboard: @@ -444,7 +442,6 @@ components: - sections - pathname - weight - - label IManifestDashboard: type: object properties: @@ -466,7 +463,6 @@ components: - type - meta - name - - js - elementName - alias MetaEditorView: @@ -509,7 +505,6 @@ components: - type - meta - name - - js - elementName - alias MetaPropertyAction: @@ -542,7 +537,6 @@ components: - type - meta - name - - js - elementName - alias IManifestEntrypoint: diff --git a/src/Umbraco.Web.UI.Client/schemas/generated-schema.ts b/src/Umbraco.Web.UI.Client/schemas/generated-schema.ts index 8ecdb30d35..446da4b614 100644 --- a/src/Umbraco.Web.UI.Client/schemas/generated-schema.ts +++ b/src/Umbraco.Web.UI.Client/schemas/generated-schema.ts @@ -115,7 +115,7 @@ export interface components { type: "section"; meta: components["schemas"]["MetaSection"]; name: string; - js: string; + js?: string; elementName: string; alias: string; }; @@ -128,7 +128,7 @@ export interface components { type: "propertyEditorUI"; meta: components["schemas"]["MetaPropertyEditorUI"]; name: string; - js: string; + js?: string; elementName: string; alias: string; }; @@ -137,14 +137,14 @@ export interface components { pathname: string; /** Format: float */ weight: number; - label: string; + label?: string; }; IManifestDashboard: { /** @enum {string} */ type: "dashboard"; meta: components["schemas"]["MetaDashboard"]; name: string; - js: string; + js?: string; elementName: string; alias: string; }; @@ -160,7 +160,7 @@ export interface components { type: "editorView"; meta: components["schemas"]["MetaEditorView"]; name: string; - js: string; + js?: string; elementName: string; alias: string; }; @@ -172,7 +172,7 @@ export interface components { type: "propertyAction"; meta: components["schemas"]["MetaPropertyAction"]; name: string; - js: string; + js?: string; elementName: string; alias: string; }; diff --git a/src/Umbraco.Web.UI.Client/temp-schema-generator/manifests.ts b/src/Umbraco.Web.UI.Client/temp-schema-generator/manifests.ts index 52c5ea4503..672cd6a767 100644 --- a/src/Umbraco.Web.UI.Client/temp-schema-generator/manifests.ts +++ b/src/Umbraco.Web.UI.Client/temp-schema-generator/manifests.ts @@ -49,7 +49,7 @@ export interface MetaDashboard { sections: string[]; pathname: string; weight: number; - label: string; + label?: string; } export interface MetaEditorView { @@ -65,7 +65,7 @@ export interface MetaPropertyAction { export interface IManifestElement extends IManifest { name: string; - js: string; + js?: string; elementName: string; } From a808bf8cab4e55c4f968e0d51cc2e35a5c356491 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 25 Aug 2022 09:41:26 +0200 Subject: [PATCH 04/17] mark elementName as optional --- src/Umbraco.Web.UI.Client/schemas/api/api.yml | 5 ----- src/Umbraco.Web.UI.Client/schemas/generated-schema.ts | 10 +++++----- .../temp-schema-generator/manifests.ts | 2 +- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/schemas/api/api.yml b/src/Umbraco.Web.UI.Client/schemas/api/api.yml index f0d2e83faf..6c8c0ae7f4 100644 --- a/src/Umbraco.Web.UI.Client/schemas/api/api.yml +++ b/src/Umbraco.Web.UI.Client/schemas/api/api.yml @@ -389,7 +389,6 @@ components: - type - meta - name - - elementName - alias MetaPropertyEditorUI: type: object @@ -422,7 +421,6 @@ components: - type - meta - name - - elementName - alias MetaDashboard: type: object @@ -463,7 +461,6 @@ components: - type - meta - name - - elementName - alias MetaEditorView: type: object @@ -505,7 +502,6 @@ components: - type - meta - name - - elementName - alias MetaPropertyAction: type: object @@ -537,7 +533,6 @@ components: - type - meta - name - - elementName - alias IManifestEntrypoint: type: object diff --git a/src/Umbraco.Web.UI.Client/schemas/generated-schema.ts b/src/Umbraco.Web.UI.Client/schemas/generated-schema.ts index 446da4b614..195ec03888 100644 --- a/src/Umbraco.Web.UI.Client/schemas/generated-schema.ts +++ b/src/Umbraco.Web.UI.Client/schemas/generated-schema.ts @@ -116,7 +116,7 @@ export interface components { meta: components["schemas"]["MetaSection"]; name: string; js?: string; - elementName: string; + elementName?: string; alias: string; }; MetaPropertyEditorUI: { @@ -129,7 +129,7 @@ export interface components { meta: components["schemas"]["MetaPropertyEditorUI"]; name: string; js?: string; - elementName: string; + elementName?: string; alias: string; }; MetaDashboard: { @@ -145,7 +145,7 @@ export interface components { meta: components["schemas"]["MetaDashboard"]; name: string; js?: string; - elementName: string; + elementName?: string; alias: string; }; MetaEditorView: { @@ -161,7 +161,7 @@ export interface components { meta: components["schemas"]["MetaEditorView"]; name: string; js?: string; - elementName: string; + elementName?: string; alias: string; }; MetaPropertyAction: { @@ -173,7 +173,7 @@ export interface components { meta: components["schemas"]["MetaPropertyAction"]; name: string; js?: string; - elementName: string; + elementName?: string; alias: string; }; IManifestEntrypoint: { diff --git a/src/Umbraco.Web.UI.Client/temp-schema-generator/manifests.ts b/src/Umbraco.Web.UI.Client/temp-schema-generator/manifests.ts index 672cd6a767..1dbb918077 100644 --- a/src/Umbraco.Web.UI.Client/temp-schema-generator/manifests.ts +++ b/src/Umbraco.Web.UI.Client/temp-schema-generator/manifests.ts @@ -66,7 +66,7 @@ export interface MetaPropertyAction { export interface IManifestElement extends IManifest { name: string; js?: string; - elementName: string; + elementName?: string; } export interface IManifestSection extends IManifestElement { From a3bced0c79e178eb05094cd50f5d41fb68ad8b58 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 25 Aug 2022 09:57:20 +0200 Subject: [PATCH 05/17] update all models to match new api --- src/Umbraco.Web.UI.Client/src/app.ts | 15 +-- .../backoffice-header-sections.element.ts | 14 +- .../components/backoffice-main.element.ts | 7 +- .../components/node-property.element.ts | 16 ++- .../editor-view-data-type-edit.element.ts | 18 +-- .../extensions/editor-extensions.element.ts | 15 ++- .../editor-entity/editor-entity.element.ts | 23 ++-- .../property-action-menu.element.ts | 14 +- .../property-action.element.ts | 11 +- .../backoffice/sections/section.context.ts | 15 ++- .../shared/section-dashboards.element.ts | 11 +- .../src/core/api/fetcher.ts | 1 + .../create-extension-element.function.ts | 15 ++- .../src/core/extension/extension.registry.ts | 121 +++--------------- .../core/extension/is-extension.function.ts | 8 +- .../core/extension/load-extension.function.ts | 58 +++++---- .../src/core/models/index.ts | 15 +++ .../src/mocks/domains/manifests.handlers.ts | 15 ++- .../src/temp-internal-manifests.ts | 62 ++++----- 19 files changed, 210 insertions(+), 244 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/app.ts b/src/Umbraco.Web.UI.Client/src/app.ts index 093a567342..c22d74cdfd 100644 --- a/src/Umbraco.Web.UI.Client/src/app.ts +++ b/src/Umbraco.Web.UI.Client/src/app.ts @@ -5,9 +5,9 @@ import { UUIIconRegistryEssential } from '@umbraco-ui/uui'; import { css, html, LitElement } from 'lit'; import { customElement, state } from 'lit/decorators.js'; -import { getServerStatus } from './core/api/fetcher'; +import { getManifests, getServerStatus } from './core/api/fetcher'; import { UmbContextProviderMixin } from './core/context'; -import { UmbExtensionManifest, UmbExtensionManifestCore, UmbExtensionRegistry } from './core/extension'; +import { UmbExtensionRegistry } from './core/extension'; import { internalManifests } from './temp-internal-manifests'; import type { Guard, IRoute } from 'router-slot/model'; @@ -121,17 +121,14 @@ export class UmbApp extends UmbContextProviderMixin(LitElement) { } private async _registerExtensionManifestsFromServer() { - // TODO: add schema and use fetcher - const res = await fetch('/umbraco/backoffice/manifests'); - const { manifests } = await res.json(); - manifests.forEach((manifest: UmbExtensionManifest) => this._extensionRegistry.register(manifest)); + const res = await getManifests({}); + const { manifests } = res.data; + manifests.forEach((manifest) => this._extensionRegistry.register(manifest)); } private async _registerInternalManifests() { // TODO: where do we get these from? - internalManifests.forEach((manifest: UmbExtensionManifestCore) => - this._extensionRegistry.register(manifest) - ); + internalManifests.forEach((manifest) => this._extensionRegistry.register(manifest)); } render() { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/components/backoffice-header-sections.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/components/backoffice-header-sections.element.ts index bbdd020854..aa7baa6970 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/components/backoffice-header-sections.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/components/backoffice-header-sections.element.ts @@ -2,13 +2,11 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { css, CSSResultGroup, html, LitElement } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { when } from 'lit/directives/when.js'; -import { isPathActive, path } from 'router-slot'; import { Subscription } from 'rxjs'; -import { UmbContextConsumerMixin, UmbContextProvider, UmbContextProviderMixin } from '../../core/context'; -import { UmbExtensionManifestSection } from '../../core/extension'; +import { UmbContextConsumerMixin, UmbContextProviderMixin } from '../../core/context'; +import { ManifestSection } from '../../core/models'; import { UmbSectionStore } from '../../core/stores/section.store'; -import { UmbSectionContext } from '../sections/section.context'; @customElement('umb-backoffice-header-sections') export class UmbBackofficeHeaderSections extends UmbContextProviderMixin(UmbContextConsumerMixin(LitElement)) { @@ -42,13 +40,13 @@ export class UmbBackofficeHeaderSections extends UmbContextProviderMixin(UmbCont private _open = false; @state() - private _sections: Array = []; + private _sections: Array = []; @state() - private _visibleSections: Array = []; + private _visibleSections: Array = []; @state() - private _extraSections: Array = []; + private _extraSections: Array = []; @state() private _currentSectionAlias = ''; @@ -117,7 +115,7 @@ export class UmbBackofficeHeaderSections extends UmbContextProviderMixin(UmbCont return html` ${this._visibleSections.map( - (section: UmbExtensionManifestSection) => html` + (section: ManifestSection) => html` = []; @state() - private _sections: Array = []; + private _sections: Array = []; private _routePrefix = 'section/'; private _sectionContext?: UmbSectionContext; @@ -79,7 +80,7 @@ export class UmbBackofficeMain extends UmbContextProviderMixin(UmbContextConsume this._provideSectionContext(section); }; - private _provideSectionContext(section: UmbExtensionManifestSection) { + private _provideSectionContext(section: ManifestSection) { if (!this._sectionContext) { this._sectionContext = new UmbSectionContext(section); this.provideContext('umbSectionContext', this._sectionContext); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/components/node-property.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/components/node-property.element.ts index b1cdcd8f54..ae946fb4e8 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/components/node-property.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/components/node-property.element.ts @@ -1,14 +1,16 @@ +import '../property-actions/property-action-menu/property-action-menu.element'; + import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { css, html, LitElement, PropertyValueMap } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import { distinctUntilChanged, EMPTY, of, Subscription, switchMap } from 'rxjs'; + import { UmbContextConsumerMixin } from '../../core/context'; -import { createExtensionElement, UmbExtensionManifest, UmbExtensionRegistry } from '../../core/extension'; +import { createExtensionElement, UmbExtensionRegistry } from '../../core/extension'; +import { ManifestPropertyEditorUI } from '../../core/models'; import { UmbDataTypeStore } from '../../core/stores/data-type.store'; import { DataTypeEntity } from '../../mocks/data/data-type.data'; -import '../property-actions/property-action-menu/property-action-menu.element'; - @customElement('umb-node-property') class UmbNodeProperty extends UmbContextConsumerMixin(LitElement) { static styles = [ @@ -94,16 +96,16 @@ class UmbNodeProperty extends UmbContextConsumerMixin(LitElement) { return this._extensionRegistry?.getByAlias(dataTypeEntity.propertyEditorUIAlias) ?? of(null); }) ) - .subscribe((propertyEditorUI) => { - if (propertyEditorUI) { - this._gotData(propertyEditorUI); + .subscribe((extension) => { + if (extension?.type === 'propertyEditorUI') { + this._gotData(extension); } // TODO: If gone what then... }); } } - private _gotData(_propertyEditorUI?: UmbExtensionManifest) { + private _gotData(_propertyEditorUI?: ManifestPropertyEditorUI) { if (!this._dataType || !_propertyEditorUI) { // TODO: if dataTypeKey didn't exist in store, we should do some nice UI. return; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/data-type/views/editor-view-data-type-edit.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/data-type/views/editor-view-data-type-edit.element.ts index 5fa870bdb6..f4f41aafa9 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/data-type/views/editor-view-data-type-edit.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/data-type/views/editor-view-data-type-edit.element.ts @@ -1,14 +1,16 @@ -import { css, html, LitElement } from 'lit'; +import { UUIComboboxListElement, UUIComboboxListEvent } from '@umbraco-ui/uui'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; +import { css, html, LitElement } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { ifDefined } from 'lit/directives/if-defined.js'; -import { UmbContextConsumerMixin } from '../../../../core/context'; -import type { DataTypeEntity } from '../../../../mocks/data/data-type.data'; -import type { UmbExtensionManifestPropertyEditorUI, UmbExtensionRegistry } from '../../../../core/extension'; -import { Subscription, distinctUntilChanged } from 'rxjs'; -import { UmbDataTypeContext } from '../data-type.context'; -import { UUIComboboxListElement, UUIComboboxListEvent } from '@umbraco-ui/uui'; +import { distinctUntilChanged, Subscription } from 'rxjs'; +import { UmbContextConsumerMixin } from '../../../../core/context'; +import { ManifestPropertyEditorUI } from '../../../../core/models'; +import { UmbDataTypeContext } from '../data-type.context'; + +import type { DataTypeEntity } from '../../../../mocks/data/data-type.data'; +import type { UmbExtensionRegistry } from '../../../../core/extension'; @customElement('umb-editor-view-data-type-edit') export class UmbEditorViewDataTypeEditElement extends UmbContextConsumerMixin(LitElement) { static styles = [UUITextStyles, css``]; @@ -17,7 +19,7 @@ export class UmbEditorViewDataTypeEditElement extends UmbContextConsumerMixin(Li _dataType?: DataTypeEntity; @state() - private _propertyEditorUIs: Array = []; + private _propertyEditorUIs: Array = []; private _extensionRegistry?: UmbExtensionRegistry; private _dataTypeContext?: UmbDataTypeContext; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/extensions/editor-extensions.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/extensions/editor-extensions.element.ts index de709ca97b..23bd318570 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/extensions/editor-extensions.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/extensions/editor-extensions.element.ts @@ -1,15 +1,18 @@ +import '../shared/editor-entity/editor-entity.element'; + import { html, LitElement } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { Subscription } from 'rxjs'; -import { UmbContextConsumerMixin } from '../../../core/context'; -import { UmbExtensionManifest, UmbExtensionRegistry } from '../../../core/extension'; -import '../shared/editor-entity/editor-entity.element'; +import { UmbContextConsumerMixin } from '../../../core/context'; +import { UmbExtensionRegistry } from '../../../core/extension'; +import { isManifestElementType } from '../../../core/extension/is-extension.function'; +import { ManifestCore } from '../../../core/models'; @customElement('umb-editor-extensions') export class UmbEditorExtensionsElement extends UmbContextConsumerMixin(LitElement) { @state() - private _extensions: Array = []; + private _extensions: Array = []; private _extensionRegistry?: UmbExtensionRegistry; private _extensionsSubscription?: Subscription; @@ -62,7 +65,9 @@ export class UmbEditorExtensionsElement extends UmbContextConsumerMixin(LitEleme (extension) => html` ${extension.type} - ${extension.name} + + ${isManifestElementType(extension) ? extension.name : 'Custom extension'} + ${extension.alias} ` diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-entity/editor-entity.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-entity/editor-entity.element.ts index 8d52e1095c..353027af27 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-entity/editor-entity.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-entity/editor-entity.element.ts @@ -1,12 +1,15 @@ -import { css, html, LitElement, nothing } from 'lit'; -import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; -import { customElement, property, state } from 'lit/decorators.js'; -import { UmbContextConsumerMixin } from '../../../../core/context'; -import { UmbExtensionManifestEditorView, UmbExtensionRegistry } from '../../../../core/extension'; -import { map, Subscription } from 'rxjs'; -import { IRoute, IRoutingInfo, RouterSlot } from 'router-slot'; - import '../editor-layout/editor-layout.element'; + +import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; +import { css, html, LitElement, nothing } from 'lit'; +import { customElement, property, state } from 'lit/decorators.js'; +import { IRoute, IRoutingInfo, RouterSlot } from 'router-slot'; +import { map, Subscription } from 'rxjs'; + +import { UmbContextConsumerMixin } from '../../../../core/context'; +import { UmbExtensionRegistry } from '../../../../core/extension'; +import { ManifestEditorView } from '../../../../core/models'; + @customElement('umb-editor-entity') export class UmbEditorEntity extends UmbContextConsumerMixin(LitElement) { static styles = [ @@ -62,7 +65,7 @@ export class UmbEditorEntity extends UmbContextConsumerMixin(LitElement) { name = ''; @state() - private _editorViews: Array = []; + private _editorViews: Array = []; @state() private _currentView = ''; @@ -147,7 +150,7 @@ export class UmbEditorEntity extends UmbContextConsumerMixin(LitElement) { ? html` ${this._editorViews.map( - (view: UmbExtensionManifestEditorView) => html` + (view: ManifestEditorView) => html` = []; + private _actions: Array = []; @state() private _open = false; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/property-actions/property-action/property-action.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/property-actions/property-action/property-action.element.ts index ecef8fa1ac..3cccc1a032 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/property-actions/property-action/property-action.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/property-actions/property-action/property-action.element.ts @@ -1,19 +1,22 @@ import { UUITextStyles } from '@umbraco-ui/uui'; import { CSSResultGroup, html, LitElement } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; -import { createExtensionElement, UmbExtensionManifestPropertyAction } from '../../../core/extension'; + +import { createExtensionElement } from '../../../core/extension'; +import { ManifestPropertyAction } from '../../../core/models'; + import type { UmbPropertyAction } from './property-action.model'; @customElement('umb-property-action') export class UmbPropertyActionElement extends LitElement implements UmbPropertyAction { static styles: CSSResultGroup = [UUITextStyles]; - private _propertyAction?: UmbExtensionManifestPropertyAction; + private _propertyAction?: ManifestPropertyAction; @property({ type: Object }) - public get propertyAction(): UmbExtensionManifestPropertyAction | undefined { + public get propertyAction(): ManifestPropertyAction | undefined { return this._propertyAction; } - public set propertyAction(value: UmbExtensionManifestPropertyAction | undefined) { + public set propertyAction(value: ManifestPropertyAction | undefined) { this._propertyAction = value; this._createElement(); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/section.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/section.context.ts index e783942757..e8c89397ed 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/section.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/section.context.ts @@ -1,26 +1,29 @@ -import { BehaviorSubject, Observable } from 'rxjs'; -import { UmbExtensionManifestSection } from '../../core/extension'; +import { BehaviorSubject } from 'rxjs'; + +import { ManifestSection } from '../../core/models'; export class UmbSectionContext { // TODO: figure out how fine grained we want to make our observables. - private _data: BehaviorSubject = new BehaviorSubject({ + private _data = new BehaviorSubject({ type: 'section', alias: '', name: '', + js: '', + elementName: '', meta: { pathname: '', weight: 0, }, }); - public readonly data: Observable = this._data.asObservable(); + public readonly data = this._data.asObservable(); - constructor(section: UmbExtensionManifestSection) { + constructor(section: ManifestSection) { if (!section) return; this._data.next(section); } // TODO: figure out how we want to update data - public update(data: Partial) { + public update(data: Partial) { this._data.next({ ...this._data.getValue(), ...data }); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-dashboards.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-dashboards.element.ts index d11a47cc2e..579a96604c 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-dashboards.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-dashboards.element.ts @@ -2,10 +2,11 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { css, html, LitElement, nothing } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { IRoutingInfo } from 'router-slot'; -import { map, Subscription, first } from 'rxjs'; +import { first, map, Subscription } from 'rxjs'; import { UmbContextConsumerMixin } from '../../../core/context'; -import { createExtensionElement, UmbExtensionManifestDashboard, UmbExtensionRegistry } from '../../../core/extension'; +import { createExtensionElement, UmbExtensionRegistry } from '../../../core/extension'; +import { ManifestDashboard } from '../../../core/models'; import { UmbSectionContext } from '../section.context'; @customElement('umb-section-dashboards') @@ -33,7 +34,7 @@ export class UmbSectionDashboards extends UmbContextConsumerMixin(LitElement) { ]; @state() - private _dashboards: Array = []; + private _dashboards: Array = []; @state() private _currentDashboardPathname = ''; @@ -104,7 +105,7 @@ export class UmbSectionDashboards extends UmbContextConsumerMixin(LitElement) { return { path: `${dashboard.meta.pathname}`, component: () => createExtensionElement(dashboard), - setup: (_element: UmbExtensionManifestDashboard, info: IRoutingInfo) => { + setup: (_element: ManifestDashboard, info: IRoutingInfo) => { this._currentDashboardPathname = info.match.route.path; }, }; @@ -122,7 +123,7 @@ export class UmbSectionDashboards extends UmbContextConsumerMixin(LitElement) { ? html` ${this._dashboards.map( - (dashboard: UmbExtensionManifestDashboard) => html` + (dashboard) => html` { +export async function createExtensionElement(manifest: ManifestCore): Promise { + console.log('🚀 ~ file: create-extension-element.function.ts ~ line 7 ~ createExtensionElement ~ manifest', manifest); //TODO: Write tests for these extension options: const js = await loadExtension(manifest); - if (manifest.elementName) { + console.log('🚀 ~ file: create-extension-element.function.ts ~ line 9 ~ createExtensionElement ~ js', js); + if (isManifestElementType(manifest) && manifest.elementName) { // created by manifest method providing HTMLElement return document.createElement(manifest.elementName); } @@ -15,10 +17,11 @@ export async function createExtensionElement(manifest: UmbExtensionManifest): Pr console.log('-- created by manifest method providing HTMLElement', js); return js; } - if (isExtensionType(js)) { + if ('elementName' in js) { // created by js export elementName - return js.elementName ? document.createElement(js.elementName) : Promise.resolve(undefined); + return document.createElement((js as any).elementName); } + if (hasDefaultExport(js)) { // created by default class return new js.default(); diff --git a/src/Umbraco.Web.UI.Client/src/core/extension/extension.registry.ts b/src/Umbraco.Web.UI.Client/src/core/extension/extension.registry.ts index 815853d89f..7f1a002be0 100644 --- a/src/Umbraco.Web.UI.Client/src/core/extension/extension.registry.ts +++ b/src/Umbraco.Web.UI.Client/src/core/extension/extension.registry.ts @@ -1,100 +1,19 @@ import { BehaviorSubject, map, Observable } from 'rxjs'; -export type UmbExtensionManifestJSModel = { - elementName?: string; -}; - -export type UmbExtensionManifestBase = { - //type: string; - alias: string; - name: string; - js?: string | (() => Promise); - elementName?: string; - //meta: undefined; -}; - -// Core manifest types: - -// Section: -export type UmbManifestSectionMeta = { - pathname: string; // TODO: how to we want to support pretty urls? - weight: number; -}; -export type UmbExtensionManifestSection = { - type: 'section'; - meta: UmbManifestSectionMeta; -} & UmbExtensionManifestBase; - -// propertyEditor: -export type UmbManifestPropertyEditorMeta = { - icon: string; - group: string; // TODO: use group alias or other name to indicate that it could be used to look up translation. - //groupAlias: string; - //description: string; - //configConfig: unknown; // we need a name and concept for how to setup editor-UI for -}; -export type UmbExtensionManifestPropertyEditorUI = { - type: 'propertyEditorUI'; - meta: UmbManifestPropertyEditorMeta; -} & UmbExtensionManifestBase; - -// Property Actions -export type UmbExtensionManifestPropertyAction = { - type: 'propertyAction'; - meta: UmbManifestPropertyActionMeta; -} & UmbExtensionManifestBase; - -export type UmbManifestPropertyActionMeta = { - propertyEditors: Array; -}; - -// Dashboard: -export type UmbManifestDashboardMeta = { - sections: Array; - label?: string; - pathname: string; // TODO: how to we want to support pretty urls? - weight: number; -}; -export type UmbExtensionManifestDashboard = { - type: 'dashboard'; - meta: UmbManifestDashboardMeta; -} & UmbExtensionManifestBase; - -// Editor View: -export type UmbManifestEditorViewMeta = { - editors: Array; // TODO: how to we want to filter views? - pathname: string; // TODO: how to we want to support pretty urls? - icon: string; - weight: number; -}; -export type UmbExtensionManifestEditorView = { - type: 'editorView'; - meta: UmbManifestEditorViewMeta; -} & UmbExtensionManifestBase; - -export type UmbExtensionManifestCore = - | UmbExtensionManifestSection - | UmbExtensionManifestDashboard - | UmbExtensionManifestPropertyEditorUI - | UmbExtensionManifestPropertyAction - | UmbExtensionManifestEditorView; - -// the 'Other' manifest type: - -type UmbExtensionManifestOther = { - type: string; - meta: unknown; -} & UmbExtensionManifestBase; - -export type UmbExtensionManifest = UmbExtensionManifestCore | UmbExtensionManifestOther; - -type UmbExtensionManifestCoreTypes = Pick['type']; - +import type { + ManifestCore, + ManifestDashboard, + ManifestEditorView, + ManifestEntrypoint, + ManifestPropertyAction, + ManifestPropertyEditorUI, + ManifestSection, +} from '../models'; export class UmbExtensionRegistry { - private _extensions = new BehaviorSubject>([]); + private _extensions = new BehaviorSubject>([]); public readonly extensions = this._extensions.asObservable(); - register(manifest: T): void { + register(manifest: ManifestCore): void { const extensionsValues = this._extensions.getValue(); const extension = extensionsValues.find((extension) => extension.alias === manifest.alias); @@ -106,7 +25,7 @@ export class UmbExtensionRegistry { this._extensions.next([...extensionsValues, manifest]); } - getByAlias(alias: string): Observable { + getByAlias(alias: string): Observable { // TODO: make pipes prettier/simpler/reuseable return this.extensions.pipe(map((dataTypes) => dataTypes.find((extension) => extension.alias === alias) || null)); } @@ -114,14 +33,14 @@ export class UmbExtensionRegistry { // TODO: implement unregister of extension // Typings concept, need to put all core types to get a good array return type for the provided type... - extensionsOfType(type: 'section'): Observable>; - extensionsOfType(type: 'dashboard'): Observable>; - extensionsOfType(type: 'editorView'): Observable>; - extensionsOfType(type: 'propertyEditorUI'): Observable>; - extensionsOfType(type: 'propertyAction'): Observable>; - extensionsOfType(type: UmbExtensionManifestCoreTypes): Observable>; - extensionsOfType(type: string): Observable>; - extensionsOfType(type: string): Observable>; + extensionsOfType(type: 'section'): Observable>; + extensionsOfType(type: 'dashboard'): Observable>; + extensionsOfType(type: 'editorView'): Observable>; + extensionsOfType(type: 'propertyEditorUI'): Observable>; + extensionsOfType(type: 'propertyAction'): Observable>; + extensionsOfType(type: 'entrypoint'): Observable>; + extensionsOfType(type: string): Observable>; + extensionsOfType(type: string): Observable>; extensionsOfType(type: string) { return this.extensions.pipe(map((exts) => exts.filter((ext) => ext.type === type))); } diff --git a/src/Umbraco.Web.UI.Client/src/core/extension/is-extension.function.ts b/src/Umbraco.Web.UI.Client/src/core/extension/is-extension.function.ts index 93cdabdfee..b6998ae8d8 100644 --- a/src/Umbraco.Web.UI.Client/src/core/extension/is-extension.function.ts +++ b/src/Umbraco.Web.UI.Client/src/core/extension/is-extension.function.ts @@ -1,9 +1,7 @@ -import { UmbExtensionManifestBase } from './extension.registry'; +import type { ManifestElementType } from '../models'; -export function isExtensionType(manifest: unknown): manifest is UmbExtensionManifestBase { +export function isManifestElementType(manifest: unknown): manifest is ManifestElementType { return ( - typeof manifest === 'object' && - manifest !== null && - (manifest as UmbExtensionManifestBase).elementName !== undefined + typeof manifest === 'object' && manifest !== null && (manifest as ManifestElementType).elementName !== undefined ); } diff --git a/src/Umbraco.Web.UI.Client/src/core/extension/load-extension.function.ts b/src/Umbraco.Web.UI.Client/src/core/extension/load-extension.function.ts index 73202c1a65..03f45d97bd 100644 --- a/src/Umbraco.Web.UI.Client/src/core/extension/load-extension.function.ts +++ b/src/Umbraco.Web.UI.Client/src/core/extension/load-extension.function.ts @@ -1,31 +1,37 @@ -import { UmbExtensionManifest } from './extension.registry'; +import { ManifestCore } from '../models'; -export function loadExtension(manifest: UmbExtensionManifest): Promise | Promise { - if (typeof manifest.js === 'function') { - return manifest.js() as Promise; +export type ManifestLoaderType = ManifestCore & { loader: () => Promise }; + +export function loadExtension(manifest: ManifestCore) { + // TODO: change this back to dynamic import after POC. Vite complains about the dynamic imports in the public folder but doesn't include the temp app_plugins folder in the final build. + // return import(/* @vite-ignore */ manifest.js); + if (isManifestLoaderType(manifest)) { + return manifest.loader(); } - // TODO: verify if this is acceptable solution. - if (typeof manifest.js === 'string') { - // TODO: change this back to dynamic import after POC. Vite complains about the dynamic imports in the public folder but doesn't include the temp app_plugins folder in the final build. - // return import(/* @vite-ignore */ manifest.js); - return new Promise((resolve, reject) => { - const script = document.createElement('script'); - script.type = 'text/javascript'; - //script.charset = 'utf-8'; - script.async = true; - script.type = 'module'; - script.src = manifest.js as string; - script.onload = function () { - resolve(null); - }; - script.onerror = function () { - reject(new Error(`Script load error for ${manifest.js}`)); - }; - document.body.appendChild(script); - }) as Promise; - } + return new Promise((resolve, reject) => { + if (!manifest.js) { + resolve(null); + return; + } - console.log('-- Extension does not have any referenced JS'); - return Promise.resolve(null); + const script = document.createElement('script'); + script.type = 'text/javascript'; + //script.charset = 'utf-8'; + script.async = true; + script.type = 'module'; + script.src = manifest.js; + script.crossOrigin = 'anonymous'; + script.onload = function () { + resolve(null); + }; + script.onerror = function () { + reject(new Error(`Script load error for ${manifest.js}`)); + }; + document.body.appendChild(script); + }) as Promise; +} + +export function isManifestLoaderType(manifest: ManifestCore): manifest is ManifestLoaderType { + return typeof (manifest as ManifestLoaderType).loader === 'function'; } diff --git a/src/Umbraco.Web.UI.Client/src/core/models/index.ts b/src/Umbraco.Web.UI.Client/src/core/models/index.ts index c13524064c..b987800b31 100644 --- a/src/Umbraco.Web.UI.Client/src/core/models/index.ts +++ b/src/Umbraco.Web.UI.Client/src/core/models/index.ts @@ -8,6 +8,7 @@ export type UserResponse = components['schemas']['UserResponse']; export type AllowedSectionsResponse = components['schemas']['AllowedSectionsResponse']; export type UmbracoInstaller = components['schemas']['InstallSettingsResponse']; export type UmbracoUpgrader = components['schemas']['UpgradeSettingsResponse']; +export type ManifestsResponse = components['schemas']['ManifestsResponse']; // Models export type UmbracoPerformInstallDatabaseConfiguration = components['schemas']['InstallSetupDatabaseConfiguration']; @@ -15,6 +16,20 @@ export type UmbracoInstallerDatabaseModel = components['schemas']['InstallDataba export type UmbracoInstallerUserModel = components['schemas']['InstallUserModel']; export type TelemetryModel = components['schemas']['TelemetryModel']; export type ServerStatus = components['schemas']['ServerStatus']; +export type ManifestCore = components['schemas']['Manifest']; +export type ManifestSection = components['schemas']['IManifestSection']; +export type ManifestPropertyEditorUI = components['schemas']['IManifestPropertyEditorUI']; +export type ManifestDashboard = components['schemas']['IManifestDashboard']; +export type ManifestEditorView = components['schemas']['IManifestEditorView']; +export type ManifestPropertyAction = components['schemas']['IManifestPropertyAction']; +export type ManifestEntrypoint = components['schemas']['IManifestEntrypoint']; + +export type ManifestElementType = + | ManifestSection + | ManifestPropertyAction + | ManifestPropertyEditorUI + | ManifestDashboard + | ManifestEditorView; // eslint-disable-next-line @typescript-eslint/no-explicit-any export type HTMLElementConstructor = new (...args: any[]) => T; diff --git a/src/Umbraco.Web.UI.Client/src/mocks/domains/manifests.handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/domains/manifests.handlers.ts index 07c1cafb1b..7175f30be6 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/domains/manifests.handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/domains/manifests.handlers.ts @@ -1,13 +1,15 @@ import { rest } from 'msw'; -// TODO: set up schema +import umbracoPath from '../../core/helpers/umbraco-path'; + +import type { ManifestsResponse } from '../../core/models'; + export const handlers = [ - rest.get('/umbraco/backoffice/manifests', (_req, res, ctx) => { - console.warn('Please move to schema'); + rest.get(umbracoPath('/manifests'), (_req, res, ctx) => { return res( // Respond with a 200 status code ctx.status(200), - ctx.json({ + ctx.json({ manifests: [ { type: 'section', @@ -31,6 +33,11 @@ export const handlers = [ group: 'common', }, }, + { + type: 'entrypoint', + alias: 'My.Entrypoint.Custom', + js: '/App_Plugins/custom-entrypoint.js', + }, ], }) ); diff --git a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts index d86cfbb8af..d51b2c4456 100644 --- a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts @@ -1,14 +1,14 @@ -import { UmbExtensionManifestCore } from './core/extension'; +import { ManifestCore } from './core/models'; // TODO: consider moving weight from meta to the main part of the manifest. We need it for every extension. // TODO: consider adding a label property as part of the meta. It might make sense to have an "extension" name label where one is needed. -export const internalManifests: Array = [ +export const internalManifests: Array Promise }> = [ { type: 'section', alias: 'Umb.Section.Content', name: 'Content', elementName: 'umb-content-section', - js: () => import('./backoffice/sections/content/content-section.element'), + loader: () => import('./backoffice/sections/content/content-section.element'), meta: { pathname: 'content', // TODO: how to we want to support pretty urls? weight: 50, @@ -19,28 +19,28 @@ export const internalManifests: Array = [ alias: 'Umb.Section.Media', name: 'Media', elementName: 'umb-media-section', - js: () => import('./backoffice/sections/media/media-section.element'), + loader: () => import('./backoffice/sections/media/media-section.element'), meta: { pathname: 'media', // TODO: how to we want to support pretty urls? weight: 50, }, }, - { - type: 'section', - alias: 'Umb.Section.Members', - name: 'Members', - elementName: 'umb-members-section', - meta: { - pathname: 'members', - weight: 30, - }, - }, + // { + // type: 'section', + // alias: 'Umb.Section.Members', + // name: 'Members', + // elementName: 'umb-members-section', + // meta: { + // pathname: 'members', + // weight: 30, + // }, + // }, { type: 'section', alias: 'Umb.Section.Settings', name: 'Settings', elementName: 'umb-settings-section', - js: () => import('./backoffice/sections/settings/settings-section.element'), + loader: () => import('./backoffice/sections/settings/settings-section.element'), meta: { pathname: 'settings', // TODO: how to we want to support pretty urls? weight: 20, @@ -51,7 +51,7 @@ export const internalManifests: Array = [ alias: 'Umb.Dashboard.Welcome', name: 'Welcome', elementName: 'umb-dashboard-welcome', - js: () => import('./backoffice/dashboards/welcome/dashboard-welcome.element'), + loader: () => import('./backoffice/dashboards/welcome/dashboard-welcome.element'), meta: { sections: ['Umb.Section.Content'], pathname: 'welcome', // TODO: how to we want to support pretty urls? @@ -63,7 +63,7 @@ export const internalManifests: Array = [ alias: 'Umb.Dashboard.RedirectManagement', name: 'Redirect Management', elementName: 'umb-dashboard-redirect-management', - js: () => import('./backoffice/dashboards/redirect-management/dashboard-redirect-management.element'), + loader: () => import('./backoffice/dashboards/redirect-management/dashboard-redirect-management.element'), meta: { sections: ['Umb.Section.Content'], pathname: 'redirect-management', // TODO: how to we want to support pretty urls? @@ -75,7 +75,7 @@ export const internalManifests: Array = [ alias: 'Umb.Dashboard.SettingsAbout', name: 'Settings About', elementName: 'umb-dashboard-settings-about', - js: () => import('./backoffice/dashboards/settings-about/dashboard-settings-about.element'), + loader: () => import('./backoffice/dashboards/settings-about/dashboard-settings-about.element'), meta: { label: 'About', sections: ['Umb.Section.Settings'], @@ -88,7 +88,7 @@ export const internalManifests: Array = [ alias: 'Umb.Dashboard.ExamineManagement', name: 'Examine Management', elementName: 'umb-dashboard-examine-management', - js: () => import('./backoffice/dashboards/examine-management/dashboard-examine-management.element'), + loader: () => import('./backoffice/dashboards/examine-management/dashboard-examine-management.element'), meta: { sections: ['Umb.Section.Settings'], pathname: 'examine-management', // TODO: how to we want to support pretty urls? @@ -100,7 +100,7 @@ export const internalManifests: Array = [ alias: 'Umb.Dashboard.ModelsBuilder', name: 'Models Builder', elementName: 'umb-dashboard-models-builder', - js: () => import('./backoffice/dashboards/models-builder/dashboard-models-builder.element'), + loader: () => import('./backoffice/dashboards/models-builder/dashboard-models-builder.element'), meta: { sections: ['Umb.Section.Settings'], pathname: 'models-builder', // TODO: how to we want to support pretty urls? @@ -112,7 +112,7 @@ export const internalManifests: Array = [ alias: 'Umb.Dashboard.MediaManagement', name: 'Media', elementName: 'umb-dashboard-media-management', - js: () => import('./backoffice/dashboards/media-management/dashboard-media-management.element'), + loader: () => import('./backoffice/dashboards/media-management/dashboard-media-management.element'), meta: { sections: ['Umb.Section.Media'], pathname: 'media-management', // TODO: how to we want to support pretty urls? @@ -123,7 +123,7 @@ export const internalManifests: Array = [ type: 'propertyEditorUI', alias: 'Umb.PropertyEditorUI.Text', name: 'Text', - js: () => import('./backoffice/property-editors/property-editor-text.element'), + loader: () => import('./backoffice/property-editors/property-editor-text.element'), meta: { icon: 'edit', group: 'common', @@ -134,7 +134,7 @@ export const internalManifests: Array = [ alias: 'Umb.PropertyEditorUI.Textarea', name: 'Textarea', elementName: 'umb-property-editor-textarea', - js: () => import('./backoffice/property-editors/property-editor-textarea.element'), + loader: () => import('./backoffice/property-editors/property-editor-textarea.element'), meta: { icon: 'edit', group: 'common', @@ -144,7 +144,7 @@ export const internalManifests: Array = [ type: 'propertyEditorUI', alias: 'Umb.PropertyEditorUI.ContextExample', name: 'Context Example', - js: () => import('./backoffice/property-editors/property-editor-context-example.element'), + loader: () => import('./backoffice/property-editors/property-editor-context-example.element'), meta: { icon: 'favorite', group: 'common', @@ -155,7 +155,7 @@ export const internalManifests: Array = [ alias: 'Umb.EditorView.ContentEdit', name: 'Content', elementName: 'umb-editor-view-node-edit', - js: () => import('./backoffice/editors/shared/node/views/edit/editor-view-node-edit.element'), + loader: () => import('./backoffice/editors/shared/node/views/edit/editor-view-node-edit.element'), meta: { // TODO: how do we want to filter where editor views are shown? https://our.umbraco.com/documentation/extending/Content-Apps/#setting-up-the-plugin // this is a temp solution @@ -170,7 +170,7 @@ export const internalManifests: Array = [ alias: 'Umb.EditorView.ContentInfo', name: 'Info', elementName: 'umb-editor-view-node-info', - js: () => import('./backoffice/editors/shared/node/views/info/editor-view-node-info.element'), + loader: () => import('./backoffice/editors/shared/node/views/info/editor-view-node-info.element'), meta: { // TODO: how do we want to filter where editor views are shown? https://our.umbraco.com/documentation/extending/Content-Apps/#setting-up-the-plugin // this is a temp solution @@ -185,7 +185,7 @@ export const internalManifests: Array = [ alias: 'Umb.EditorView.DataTypeEdit', name: 'Edit', elementName: 'umb-editor-view-data-type-edit', - js: () => import('./backoffice/editors/data-type/views/editor-view-data-type-edit.element'), + loader: () => import('./backoffice/editors/data-type/views/editor-view-data-type-edit.element'), meta: { // TODO: how do we want to filter where editor views are shown? https://our.umbraco.com/documentation/extending/Content-Apps/#setting-up-the-plugin // this is a temp solution @@ -200,7 +200,7 @@ export const internalManifests: Array = [ alias: 'Umb.EditorView.DocumentTypeDesign', name: 'Design', elementName: 'umb-editor-view-document-type-design', - js: () => import('./backoffice/editors/document-type/views/editor-view-document-type-design.element'), + loader: () => import('./backoffice/editors/document-type/views/editor-view-document-type-design.element'), meta: { // TODO: how do we want to filter where editor views are shown? https://our.umbraco.com/documentation/extending/Content-Apps/#setting-up-the-plugin // this is a temp solution @@ -215,7 +215,7 @@ export const internalManifests: Array = [ alias: 'Umb.PropertyAction.Copy', name: 'Copy', elementName: 'umb-property-action-copy', - js: () => import('./backoffice/property-actions/property-action-copy.element'), + loader: () => import('./backoffice/property-actions/property-action-copy.element'), meta: { propertyEditors: ['Umb.PropertyEditorUI.Text'], }, @@ -225,7 +225,7 @@ export const internalManifests: Array = [ alias: 'Umb.PropertyAction.Clear', name: 'Clear', elementName: 'umb-property-action-clear', - js: () => import('./backoffice/property-actions/property-action-clear.element'), + loader: () => import('./backoffice/property-actions/property-action-clear.element'), meta: { propertyEditors: ['Umb.PropertyEditorUI.Text'], }, @@ -235,7 +235,7 @@ export const internalManifests: Array = [ alias: 'Umb.PropertyEditorUI.ContentPicker', name: 'ContentPicker', elementName: 'umb-property-editor-content-picker', - js: () => import('./backoffice/property-editors/property-editor-content-picker.element'), + loader: () => import('./backoffice/property-editors/property-editor-content-picker.element'), meta: { icon: 'document', group: 'common', From ab402b5ad51490dd506dd8628b7f14ce0e8c43d9 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 25 Aug 2022 09:57:38 +0200 Subject: [PATCH 06/17] load custom extensions --- .../public/App_Plugins/custom-entrypoint.js | 1 + .../src/core/extension/extension.registry.ts | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/public/App_Plugins/custom-entrypoint.js diff --git a/src/Umbraco.Web.UI.Client/public/App_Plugins/custom-entrypoint.js b/src/Umbraco.Web.UI.Client/public/App_Plugins/custom-entrypoint.js new file mode 100644 index 0000000000..d55405508c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/public/App_Plugins/custom-entrypoint.js @@ -0,0 +1 @@ +console.log('Hello from the custom entrypoint!'); diff --git a/src/Umbraco.Web.UI.Client/src/core/extension/extension.registry.ts b/src/Umbraco.Web.UI.Client/src/core/extension/extension.registry.ts index 7f1a002be0..3a04353a95 100644 --- a/src/Umbraco.Web.UI.Client/src/core/extension/extension.registry.ts +++ b/src/Umbraco.Web.UI.Client/src/core/extension/extension.registry.ts @@ -1,5 +1,7 @@ import { BehaviorSubject, map, Observable } from 'rxjs'; +import { createExtensionElement } from './create-extension-element.function'; + import type { ManifestCore, ManifestDashboard, @@ -23,6 +25,11 @@ export class UmbExtensionRegistry { } this._extensions.next([...extensionsValues, manifest]); + + // If entrypoint extension, we should load it immediately + if (manifest.type === 'entrypoint') { + createExtensionElement(manifest); + } } getByAlias(alias: string): Observable { From 9a7e9bf861f7d58285970a243053dea3f0c27e11 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 25 Aug 2022 12:41:49 +0200 Subject: [PATCH 07/17] fix stories with double imports --- .../dashboard-redirect-management.stories.ts | 5 +++-- .../welcome/dashboard-welcome.stories.ts | 5 +++-- .../editors/content/editor-content.stories.ts | 7 ++++--- .../data-type/editor-data-type.stories.ts | 7 ++++--- .../editor-view-data-type-edit.stories.ts | 8 +++++--- .../editor-document-type.stories.ts | 7 ++++--- ...ditor-view-document-type-design.stories.ts | 8 +++++--- .../extensions/editor-extensions.stories.ts | 5 +++-- .../editors/media/editor-media.stories.ts | 7 ++++--- .../editor-entity/editor-entity.stories.ts | 3 ++- .../editor-layout/editor-layout.stories.ts | 3 ++- .../shared/node/editor-node.stories.ts | 7 ++++--- .../edit/editor-view-node-edit.stories.ts | 8 +++++--- .../info/editor-view-node-info.stories.ts | 8 +++++--- .../confirm/modal-layout-confirm.stories.ts | 10 ++++++---- .../modal-layout-content-picker.stories.ts | 14 +++++++++----- .../src/core/services/modal/modal.service.ts | 14 ++++++++------ .../src/core/services/modal/modal.stories.ts | 10 +++++----- .../notification/notification.stories.ts | 19 ++++++++++--------- 19 files changed, 91 insertions(+), 64 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/redirect-management/dashboard-redirect-management.stories.ts b/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/redirect-management/dashboard-redirect-management.stories.ts index c492f69ee4..99d180a303 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/redirect-management/dashboard-redirect-management.stories.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/redirect-management/dashboard-redirect-management.stories.ts @@ -1,8 +1,9 @@ +import './dashboard-redirect-management.element'; + import { Meta, Story } from '@storybook/web-components'; import { html } from 'lit-html'; -import { UmbDashboardRedirectManagementElement } from './dashboard-redirect-management.element'; -import './dashboard-redirect-management.element'; +import type { UmbDashboardRedirectManagementElement } from './dashboard-redirect-management.element'; export default { title: 'Dashboards/Redirect Management', diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/welcome/dashboard-welcome.stories.ts b/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/welcome/dashboard-welcome.stories.ts index 42028e5030..82ad05aea5 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/welcome/dashboard-welcome.stories.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/welcome/dashboard-welcome.stories.ts @@ -1,8 +1,9 @@ +import './dashboard-welcome.element'; + import { Meta, Story } from '@storybook/web-components'; import { html } from 'lit-html'; -import { UmbDashboardWelcomeElement } from './dashboard-welcome.element'; -import './dashboard-welcome.element'; +import type { UmbDashboardWelcomeElement } from './dashboard-welcome.element'; export default { title: 'Dashboards/Welcome', diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/content/editor-content.stories.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/content/editor-content.stories.ts index aebb0076f3..0dc1864bab 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/content/editor-content.stories.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/content/editor-content.stories.ts @@ -1,11 +1,12 @@ +import './editor-content.element'; + import { Meta, Story } from '@storybook/web-components'; import { html } from 'lit-html'; -import { UmbEditorContentElement } from './editor-content.element'; -import './editor-content.element'; - import { data } from '../../../mocks/data/node.data'; +import type { UmbEditorContentElement } from './editor-content.element'; + export default { title: 'Editors/Content', component: 'umb-editor-content', diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/data-type/editor-data-type.stories.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/data-type/editor-data-type.stories.ts index cdb79a4095..6e3e210769 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/data-type/editor-data-type.stories.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/data-type/editor-data-type.stories.ts @@ -1,11 +1,12 @@ +import './editor-data-type.element'; + import { Meta, Story } from '@storybook/web-components'; import { html } from 'lit-html'; -import { UmbEditorDataTypeElement } from './editor-data-type.element'; -import './editor-data-type.element'; - import { data } from '../../../mocks/data/data-type.data'; +import type { UmbEditorDataTypeElement } from './editor-data-type.element'; + export default { title: 'Editors/Data Type', component: 'umb-editor-data-type', diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/data-type/views/editor-view-data-type-edit.stories.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/data-type/views/editor-view-data-type-edit.stories.ts index 2a7cfb1ae7..ef68c2ec7c 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/data-type/views/editor-view-data-type-edit.stories.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/data-type/views/editor-view-data-type-edit.stories.ts @@ -1,10 +1,12 @@ +import './editor-view-data-type-edit.element'; + import { Meta, Story } from '@storybook/web-components'; import { html } from 'lit-html'; -import { UmbDataTypeContext } from '../data-type.context'; -import { UmbEditorViewDataTypeEditElement } from './editor-view-data-type-edit.element'; -import './editor-view-data-type-edit.element'; import { data } from '../../../../mocks/data/data-type.data'; +import { UmbDataTypeContext } from '../data-type.context'; + +import type { UmbEditorViewDataTypeEditElement } from './editor-view-data-type-edit.element'; export default { title: 'Editors/Data Type/Views/Edit', diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/document-type/editor-document-type.stories.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/document-type/editor-document-type.stories.ts index ea9a5f50f4..787b83c706 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/document-type/editor-document-type.stories.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/document-type/editor-document-type.stories.ts @@ -1,11 +1,12 @@ +import './editor-document-type.element'; + import { Meta, Story } from '@storybook/web-components'; import { html } from 'lit-html'; -import { UmbEditorDocumentTypeElement } from './editor-document-type.element'; -import './editor-document-type.element'; - import { data } from '../../../mocks/data/document-type.data'; +import type { UmbEditorDocumentTypeElement } from './editor-document-type.element'; + export default { title: 'Editors/Document Type', component: 'umb-editor-document-type', diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/document-type/views/editor-view-document-type-design.stories.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/document-type/views/editor-view-document-type-design.stories.ts index cd747c26ce..1ff23e754d 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/document-type/views/editor-view-document-type-design.stories.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/document-type/views/editor-view-document-type-design.stories.ts @@ -1,10 +1,12 @@ +import './editor-view-document-type-design.element'; + import { Meta, Story } from '@storybook/web-components'; import { html } from 'lit-html'; -import { UmbDocumentTypeContext } from '../document-type.context'; -import { UmbEditorViewDocumentTypeDesignElement } from './editor-view-document-type-design.element'; -import './editor-view-document-type-design.element'; import { data } from '../../../../mocks/data/document-type.data'; +import { UmbDocumentTypeContext } from '../document-type.context'; + +import type { UmbEditorViewDocumentTypeDesignElement } from './editor-view-document-type-design.element'; export default { title: 'Editors/Document Type/Views/Design', diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/extensions/editor-extensions.stories.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/extensions/editor-extensions.stories.ts index d084a04646..a6d35c21fb 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/extensions/editor-extensions.stories.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/extensions/editor-extensions.stories.ts @@ -1,8 +1,9 @@ +import './editor-extensions.element'; + import { Meta, Story } from '@storybook/web-components'; import { html } from 'lit-html'; -import { UmbEditorExtensionsElement } from './editor-extensions.element'; -import './editor-extensions.element'; +import type { UmbEditorExtensionsElement } from './editor-extensions.element'; export default { title: 'Editors/Extensions', diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/media/editor-media.stories.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/media/editor-media.stories.ts index d036b1cf53..62fb15dbf3 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/media/editor-media.stories.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/media/editor-media.stories.ts @@ -1,11 +1,12 @@ +import './editor-media.element'; + import { Meta, Story } from '@storybook/web-components'; import { html } from 'lit-html'; -import { UmbEditorMediaElement } from './editor-media.element'; -import './editor-media.element'; - import { data } from '../../../mocks/data/node.data'; +import type { UmbEditorMediaElement } from './editor-media.element'; + export default { title: 'Editors/Media', component: 'umb-editor-media', diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-entity/editor-entity.stories.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-entity/editor-entity.stories.ts index c66266d79d..7c17cf1266 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-entity/editor-entity.stories.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-entity/editor-entity.stories.ts @@ -1,9 +1,10 @@ -import { UmbEditorEntity } from './editor-entity.element'; import './editor-entity.element'; import { Meta, Story } from '@storybook/web-components'; import { html } from 'lit-html'; +import type { UmbEditorEntity } from './editor-entity.element'; + export default { title: 'Editors/Shared/Editor Entity', component: 'umb-editor-entity', diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-layout/editor-layout.stories.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-layout/editor-layout.stories.ts index 86cb91589b..7b4127d906 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-layout/editor-layout.stories.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-layout/editor-layout.stories.ts @@ -1,9 +1,10 @@ -import { UmbEditorLayout } from './editor-layout.element'; import './editor-layout.element'; import { Meta, Story } from '@storybook/web-components'; import { html } from 'lit-html'; +import type { UmbEditorLayout } from './editor-layout.element'; + export default { title: 'Editors/Shared/Editor Layout', component: 'umb-editor-layout', diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/node/editor-node.stories.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/node/editor-node.stories.ts index 8018fa8eb7..28ad9cfc76 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/node/editor-node.stories.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/node/editor-node.stories.ts @@ -1,11 +1,12 @@ +import './editor-node.element'; + import { Meta, Story } from '@storybook/web-components'; import { html } from 'lit-html'; -import { UmbEditorNodeElement } from './editor-node.element'; -import './editor-node.element'; - import { data } from '../../../../mocks/data/node.data'; +import type { UmbEditorNodeElement } from './editor-node.element'; + export default { title: 'Editors/Shared/Node', component: 'umb-editor-node', diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/node/views/edit/editor-view-node-edit.stories.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/node/views/edit/editor-view-node-edit.stories.ts index 1910d9d838..4a711e89c0 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/node/views/edit/editor-view-node-edit.stories.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/node/views/edit/editor-view-node-edit.stories.ts @@ -1,10 +1,12 @@ +import './editor-view-node-edit.element'; + import { Meta, Story } from '@storybook/web-components'; import { html } from 'lit-html'; -import { UmbNodeContext } from '../../node.context'; -import { UmbEditorViewNodeEditElement } from './editor-view-node-edit.element'; -import './editor-view-node-edit.element'; import { data } from '../../../../../../mocks/data/node.data'; +import { UmbNodeContext } from '../../node.context'; + +import type { UmbEditorViewNodeEditElement } from './editor-view-node-edit.element'; export default { title: 'Editors/Shared/Node/Views/Edit', diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/node/views/info/editor-view-node-info.stories.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/node/views/info/editor-view-node-info.stories.ts index da306f5605..fb47364eb2 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/node/views/info/editor-view-node-info.stories.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/node/views/info/editor-view-node-info.stories.ts @@ -1,10 +1,12 @@ +import './editor-view-node-info.element'; + import { Meta, Story } from '@storybook/web-components'; import { html } from 'lit-html'; -import { UmbNodeContext } from '../../node.context'; -import { UmbEditorViewNodeInfoElement } from './editor-view-node-info.element'; -import './editor-view-node-info.element'; import { data } from '../../../../../../mocks/data/node.data'; +import { UmbNodeContext } from '../../node.context'; + +import type { UmbEditorViewNodeInfoElement } from './editor-view-node-info.element'; export default { title: 'Editors/Shared/Node/Views/Info', diff --git a/src/Umbraco.Web.UI.Client/src/core/services/modal/layouts/confirm/modal-layout-confirm.stories.ts b/src/Umbraco.Web.UI.Client/src/core/services/modal/layouts/confirm/modal-layout-confirm.stories.ts index f1e3e1f715..93d8ba7c2a 100644 --- a/src/Umbraco.Web.UI.Client/src/core/services/modal/layouts/confirm/modal-layout-confirm.stories.ts +++ b/src/Umbraco.Web.UI.Client/src/core/services/modal/layouts/confirm/modal-layout-confirm.stories.ts @@ -1,7 +1,9 @@ +import './modal-layout-confirm.element'; + import { Meta, Story } from '@storybook/web-components'; import { html } from 'lit'; -import { UmbModalLayoutConfirmElement, UmbModalConfirmData } from './modal-layout-confirm.element'; -import './modal-layout-confirm.element'; + +import type { UmbModalLayoutConfirmElement, UmbModalConfirmData } from './modal-layout-confirm.element'; export default { title: 'API/Modals/Layouts/Confirm', @@ -17,7 +19,7 @@ const positiveData: UmbModalConfirmData = { }; export const Positive: Story = () => html` - @@ -31,7 +33,7 @@ const dangerData: UmbModalConfirmData = { }; export const Danger: Story = () => html` - diff --git a/src/Umbraco.Web.UI.Client/src/core/services/modal/layouts/content-picker/modal-layout-content-picker.stories.ts b/src/Umbraco.Web.UI.Client/src/core/services/modal/layouts/content-picker/modal-layout-content-picker.stories.ts index 3422b78379..f74f928ddc 100644 --- a/src/Umbraco.Web.UI.Client/src/core/services/modal/layouts/content-picker/modal-layout-content-picker.stories.ts +++ b/src/Umbraco.Web.UI.Client/src/core/services/modal/layouts/content-picker/modal-layout-content-picker.stories.ts @@ -1,9 +1,13 @@ -import { Meta, Story } from '@storybook/web-components'; -import { html } from 'lit'; -import { UmbModalLayoutContentPickerElement, UmbModalContentPickerData } from './modal-layout-content-picker.element'; +import '../../../../../backoffice/editors/shared/editor-layout/editor-layout.element'; import './modal-layout-content-picker.element'; -import '../../../../../backoffice/editors/shared/editor-layout/editor-layout.element'; +import { Meta, Story } from '@storybook/web-components'; +import { html } from 'lit'; + +import type { + UmbModalLayoutContentPickerElement, + UmbModalContentPickerData, +} from './modal-layout-content-picker.element'; export default { title: 'API/Modals/Layouts/Content Picker', @@ -14,7 +18,7 @@ export default { const data: UmbModalContentPickerData = {}; export const Overview: Story = () => html` - diff --git a/src/Umbraco.Web.UI.Client/src/core/services/modal/modal.service.ts b/src/Umbraco.Web.UI.Client/src/core/services/modal/modal.service.ts index ac363efc3e..285078d136 100644 --- a/src/Umbraco.Web.UI.Client/src/core/services/modal/modal.service.ts +++ b/src/Umbraco.Web.UI.Client/src/core/services/modal/modal.service.ts @@ -1,13 +1,15 @@ -import { BehaviorSubject, Observable } from 'rxjs'; -import { UmbModalHandler } from './'; -import { UmbModalConfirmData } from './layouts/confirm/modal-layout-confirm.element'; -import { UmbModalContentPickerData } from './layouts/content-picker/modal-layout-content-picker.element'; -import { UUIModalSidebarSize } from '@umbraco-ui/uui-modal-sidebar'; - // TODO: lazy load import './layouts/confirm/modal-layout-confirm.element'; import './layouts/content-picker/modal-layout-content-picker.element'; +import { UUIModalSidebarSize } from '@umbraco-ui/uui-modal-sidebar'; +import { BehaviorSubject, Observable } from 'rxjs'; + +import { UmbModalHandler } from './'; + +import type { UmbModalConfirmData } from './layouts/confirm/modal-layout-confirm.element'; +import type { UmbModalContentPickerData } from './layouts/content-picker/modal-layout-content-picker.element'; + export type UmbModelType = 'dialog' | 'sidebar'; export interface UmbModalOptions { diff --git a/src/Umbraco.Web.UI.Client/src/core/services/modal/modal.stories.ts b/src/Umbraco.Web.UI.Client/src/core/services/modal/modal.stories.ts index f2e1f77107..2677b3008f 100644 --- a/src/Umbraco.Web.UI.Client/src/core/services/modal/modal.stories.ts +++ b/src/Umbraco.Web.UI.Client/src/core/services/modal/modal.stories.ts @@ -1,18 +1,18 @@ import '../../../backoffice/components/backoffice-modal-container.element'; +import '../../../backoffice/editors/shared/editor-layout/editor-layout.element'; import '../../../core/services/modal/layouts/content-picker/modal-layout-content-picker.element'; import '../../context/context-provider.element'; -import '../../../backoffice/editors/shared/editor-layout/editor-layout.element'; - import '@umbraco-ui/uui-modal'; import '@umbraco-ui/uui-modal-container'; -import '@umbraco-ui/uui-modal-sidebar'; import '@umbraco-ui/uui-modal-dialog'; +import '@umbraco-ui/uui-modal-sidebar'; import { Meta, Story } from '@storybook/web-components'; +import { LitElement } from 'lit'; import { html } from 'lit-html'; import { customElement, property, state } from 'lit/decorators.js'; + import { UmbContextConsumerMixin } from '../../context'; -import { LitElement } from 'lit'; import { UmbModalService } from './'; export default { @@ -34,7 +34,7 @@ export default { } as Meta; @customElement('story-modal-service-example') -class StoryModalServiceExampleElement extends UmbContextConsumerMixin(LitElement) { +export class StoryModalServiceExampleElement extends UmbContextConsumerMixin(LitElement) { @property() modalLayout = 'confirm'; diff --git a/src/Umbraco.Web.UI.Client/src/core/services/notification/notification.stories.ts b/src/Umbraco.Web.UI.Client/src/core/services/notification/notification.stories.ts index 157787db0e..670ac5fa55 100644 --- a/src/Umbraco.Web.UI.Client/src/core/services/notification/notification.stories.ts +++ b/src/Umbraco.Web.UI.Client/src/core/services/notification/notification.stories.ts @@ -1,14 +1,15 @@ -import { Meta, Story } from '@storybook/web-components'; -import { LitElement, html } from 'lit'; -import { customElement } from 'lit/decorators.js'; -import { UmbNotificationService, UmbNotificationOptions, UmbNotificationColor } from '.'; -import type { UmbNotificationDefaultData } from './layouts/default'; -import { UmbContextConsumerMixin } from '../../context'; - -import '../../context/context-provider.element'; import '../../../backoffice/components/backoffice-notification-container.element'; +import '../../context/context-provider.element'; import './layouts/default'; +import { Meta, Story } from '@storybook/web-components'; +import { html, LitElement } from 'lit'; +import { customElement } from 'lit/decorators.js'; + +import { UmbNotificationColor, UmbNotificationOptions, UmbNotificationService } from '.'; +import { UmbContextConsumerMixin } from '../../context'; + +import type { UmbNotificationDefaultData } from './layouts/default'; export default { title: 'API/Notifications/Overview', component: 'ucp-notification-layout-default', @@ -21,7 +22,7 @@ export default { } as Meta; @customElement('story-notification-default-example') -class StoryNotificationDefaultExampleElement extends UmbContextConsumerMixin(LitElement) { +export class StoryNotificationDefaultExampleElement extends UmbContextConsumerMixin(LitElement) { private _notificationService?: UmbNotificationService; connectedCallback(): void { From 2c9ba6f81cbdb4b7156f75cb41de695b69abff5c Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 25 Aug 2022 12:42:15 +0200 Subject: [PATCH 08/17] add custom eslint rule to check for correct type imports --- src/Umbraco.Web.UI.Client/.eslintrc.json | 5 +-- .../eslint-local-rules.cjs | 36 +++++++++++++++++++ src/Umbraco.Web.UI.Client/package-lock.json | 13 +++++++ src/Umbraco.Web.UI.Client/package.json | 11 +++--- 4 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/eslint-local-rules.cjs diff --git a/src/Umbraco.Web.UI.Client/.eslintrc.json b/src/Umbraco.Web.UI.Client/.eslintrc.json index 32cc406cec..55525707e8 100644 --- a/src/Umbraco.Web.UI.Client/.eslintrc.json +++ b/src/Umbraco.Web.UI.Client/.eslintrc.json @@ -2,7 +2,7 @@ "ignorePatterns": ["vite.*.ts"], "root": true, "extends": ["eslint:recommended", "plugin:import/recommended", "prettier"], - "plugins": ["import"], + "plugins": ["import", "eslint-plugin-local-rules"], "overrides": [ { "files": ["**/*.ts"], @@ -31,7 +31,8 @@ }, "rules": { "no-var": "error", - "import/no-unresolved": "error" + "import/no-unresolved": "error", + "local-rules/bad-type-import": "error" }, "settings": { "import/parsers": { diff --git a/src/Umbraco.Web.UI.Client/eslint-local-rules.cjs b/src/Umbraco.Web.UI.Client/eslint-local-rules.cjs new file mode 100644 index 0000000000..b124352065 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/eslint-local-rules.cjs @@ -0,0 +1,36 @@ +'use strict'; + +/* + * A eslint rule that ensures the use of the `import type` operator from the `src/core/models/index.ts` file. + */ +// eslint-disable-next-line no-undef +/** @type {import('eslint').Rule.RuleModule} */ +module.exports = { + 'bad-type-import': { + meta: { + type: 'problem', + docs: { + description: 'Ensures the use of the `import type` operator from the `src/core/models/index.ts` file.', + category: 'Best Practices', + recommended: true, + }, + fixable: 'code', + schema: [], + }, + create: function (context) { + return { + ImportDeclaration: function (node) { + if (node.source.parent.importKind !== 'type' && (node.source.value.endsWith('core/models') || node.source.value === 'router-slot/model')) { + const sourceCode = context.getSourceCode(); + const nodeSource = sourceCode.getText(node); + context.report({ + node, + message: 'Use `import type` instead of `import`.', + fix: fixer => fixer.replaceText(node, nodeSource.replace('import', 'import type')), + }); + } + }, + }; + } + } +}; diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json index 4faa01f6d5..b3af37461e 100644 --- a/src/Umbraco.Web.UI.Client/package-lock.json +++ b/src/Umbraco.Web.UI.Client/package-lock.json @@ -49,6 +49,7 @@ "eslint-plugin-import": "^2.26.0", "eslint-plugin-lit": "^1.6.1", "eslint-plugin-lit-a11y": "^2.2.2", + "eslint-plugin-local-rules": "^1.3.1", "eslint-plugin-storybook": "^0.6.4", "lit-html": "^2.3.1", "msw": "^0.45.0", @@ -12288,6 +12289,12 @@ "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", "dev": true }, + "node_modules/eslint-plugin-local-rules": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-local-rules/-/eslint-plugin-local-rules-1.3.1.tgz", + "integrity": "sha512-ezuHRUXzRwFY3jFaX9vz8vxLLdLLIrbXBnVM6rip71/zjnIBaExY2vsm316temX+P3tasjQ2ciadWOTnnOUCgA==", + "dev": true + }, "node_modules/eslint-plugin-storybook": { "version": "0.6.4", "resolved": "https://registry.npmjs.org/eslint-plugin-storybook/-/eslint-plugin-storybook-0.6.4.tgz", @@ -35952,6 +35959,12 @@ } } }, + "eslint-plugin-local-rules": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-local-rules/-/eslint-plugin-local-rules-1.3.1.tgz", + "integrity": "sha512-ezuHRUXzRwFY3jFaX9vz8vxLLdLLIrbXBnVM6rip71/zjnIBaExY2vsm316temX+P3tasjQ2ciadWOTnnOUCgA==", + "dev": true + }, "eslint-plugin-storybook": { "version": "0.6.4", "resolved": "https://registry.npmjs.org/eslint-plugin-storybook/-/eslint-plugin-storybook-0.6.4.tgz", diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index 271937fec6..37ad82bc6a 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -38,16 +38,16 @@ "dependencies": { "@umbraco-ui/uui": "^1.0.0", "@umbraco-ui/uui-css": "^1.0.0", + "@umbraco-ui/uui-modal": "file:umbraco-ui-uui-modal-0.0.0.tgz", + "@umbraco-ui/uui-modal-container": "file:umbraco-ui-uui-modal-container-0.0.0.tgz", + "@umbraco-ui/uui-modal-dialog": "file:umbraco-ui-uui-modal-dialog-0.0.0.tgz", + "@umbraco-ui/uui-modal-sidebar": "file:umbraco-ui-uui-modal-sidebar-0.0.0.tgz", "element-internals-polyfill": "^1.1.9", "lit": "^2.3.1", "openapi-typescript-fetch": "^1.1.3", "router-slot": "^1.5.5", "rxjs": "^7.5.6", - "uuid": "^8.3.2", - "@umbraco-ui/uui-modal": "file:umbraco-ui-uui-modal-0.0.0.tgz", - "@umbraco-ui/uui-modal-container": "file:umbraco-ui-uui-modal-container-0.0.0.tgz", - "@umbraco-ui/uui-modal-dialog": "file:umbraco-ui-uui-modal-dialog-0.0.0.tgz", - "@umbraco-ui/uui-modal-sidebar": "file:umbraco-ui-uui-modal-sidebar-0.0.0.tgz" + "uuid": "^8.3.2" }, "devDependencies": { "@babel/core": "^7.18.13", @@ -76,6 +76,7 @@ "eslint-plugin-import": "^2.26.0", "eslint-plugin-lit": "^1.6.1", "eslint-plugin-lit-a11y": "^2.2.2", + "eslint-plugin-local-rules": "^1.3.1", "eslint-plugin-storybook": "^0.6.4", "lit-html": "^2.3.1", "msw": "^0.45.0", From bada418bb9ad407c69ea1f13d5ab90b41882ea1a Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 25 Aug 2022 14:08:36 +0200 Subject: [PATCH 09/17] eslint fix types --- src/Umbraco.Web.UI.Client/e2e/installer.spec.ts | 3 ++- src/Umbraco.Web.UI.Client/e2e/upgrader.spec.ts | 2 +- src/Umbraco.Web.UI.Client/src/app.ts | 2 +- .../components/backoffice-header-sections.element.ts | 2 +- .../src/backoffice/components/backoffice-main.element.ts | 2 +- .../src/backoffice/components/node-property.element.ts | 2 +- .../data-type/views/editor-view-data-type-edit.element.ts | 2 +- .../backoffice/editors/extensions/editor-extensions.element.ts | 2 +- .../editors/shared/editor-entity/editor-entity.element.ts | 2 +- .../property-action-menu/property-action-menu.element.ts | 2 +- .../property-action/property-action.element.ts | 2 +- .../src/backoffice/sections/section.context.ts | 2 +- .../backoffice/sections/shared/section-dashboards.element.ts | 3 ++- .../src/installer/installer-consent.element.ts | 2 +- src/Umbraco.Web.UI.Client/src/installer/installer-context.ts | 2 +- .../src/installer/installer-database.element.ts | 2 +- .../src/installer/installer-error.element.ts | 2 +- src/Umbraco.Web.UI.Client/src/installer/installer.element.ts | 2 +- .../src/mocks/domains/install.handlers.ts | 2 +- src/Umbraco.Web.UI.Client/src/mocks/domains/server.handlers.ts | 2 +- .../src/mocks/domains/upgrade.handlers.ts | 2 +- src/Umbraco.Web.UI.Client/src/mocks/domains/user.handlers.ts | 2 +- src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts | 2 +- .../src/upgrader/upgrader-view.element.ts | 2 +- 24 files changed, 26 insertions(+), 24 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/e2e/installer.spec.ts b/src/Umbraco.Web.UI.Client/e2e/installer.spec.ts index 9f701c17f3..b504058db8 100644 --- a/src/Umbraco.Web.UI.Client/e2e/installer.spec.ts +++ b/src/Umbraco.Web.UI.Client/e2e/installer.spec.ts @@ -1,9 +1,10 @@ import { rest } from 'msw'; import umbracoPath from '../src/core/helpers/umbraco-path'; -import { ProblemDetails, StatusResponse } from '../src/core/models'; import { expect, test } from '../test'; +import type { ProblemDetails, StatusResponse } from '../src/core/models'; + test.describe('installer tests', () => { test.beforeEach(async ({ page, worker }) => { await worker.use( diff --git a/src/Umbraco.Web.UI.Client/e2e/upgrader.spec.ts b/src/Umbraco.Web.UI.Client/e2e/upgrader.spec.ts index 8421f333e7..43ee82f78e 100644 --- a/src/Umbraco.Web.UI.Client/e2e/upgrader.spec.ts +++ b/src/Umbraco.Web.UI.Client/e2e/upgrader.spec.ts @@ -1,7 +1,7 @@ import { rest } from 'msw'; import umbracoPath from '../src/core/helpers/umbraco-path'; -import { ProblemDetails, StatusResponse } from '../src/core/models'; +import type { ProblemDetails, StatusResponse } from '../src/core/models'; import { expect, test } from '../test'; test.describe('upgrader tests', () => { diff --git a/src/Umbraco.Web.UI.Client/src/app.ts b/src/Umbraco.Web.UI.Client/src/app.ts index c22d74cdfd..02f80c23d8 100644 --- a/src/Umbraco.Web.UI.Client/src/app.ts +++ b/src/Umbraco.Web.UI.Client/src/app.ts @@ -10,8 +10,8 @@ import { UmbContextProviderMixin } from './core/context'; import { UmbExtensionRegistry } from './core/extension'; import { internalManifests } from './temp-internal-manifests'; -import type { Guard, IRoute } from 'router-slot/model'; import type { ServerStatus } from './core/models'; +import type { Guard, IRoute } from 'router-slot/model'; @customElement('umb-app') export class UmbApp extends UmbContextProviderMixin(LitElement) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/components/backoffice-header-sections.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/components/backoffice-header-sections.element.ts index aa7baa6970..eaaef3a9a0 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/components/backoffice-header-sections.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/components/backoffice-header-sections.element.ts @@ -5,7 +5,7 @@ import { when } from 'lit/directives/when.js'; import { Subscription } from 'rxjs'; import { UmbContextConsumerMixin, UmbContextProviderMixin } from '../../core/context'; -import { ManifestSection } from '../../core/models'; +import type { ManifestSection } from '../../core/models'; import { UmbSectionStore } from '../../core/stores/section.store'; @customElement('umb-backoffice-header-sections') diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/components/backoffice-main.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/components/backoffice-main.element.ts index 97eb8ac0c2..234f88c835 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/components/backoffice-main.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/components/backoffice-main.element.ts @@ -7,7 +7,7 @@ import { Subscription } from 'rxjs'; import { UmbContextConsumerMixin, UmbContextProviderMixin } from '../../core/context'; import { createExtensionElement } from '../../core/extension'; -import { ManifestSection } from '../../core/models'; +import type { ManifestSection } from '../../core/models'; import { UmbSectionStore } from '../../core/stores/section.store'; import { UmbSectionContext } from '../sections/section.context'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/components/node-property.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/components/node-property.element.ts index ae946fb4e8..7c16c3f09f 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/components/node-property.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/components/node-property.element.ts @@ -7,7 +7,7 @@ import { distinctUntilChanged, EMPTY, of, Subscription, switchMap } from 'rxjs'; import { UmbContextConsumerMixin } from '../../core/context'; import { createExtensionElement, UmbExtensionRegistry } from '../../core/extension'; -import { ManifestPropertyEditorUI } from '../../core/models'; +import type { ManifestPropertyEditorUI } from '../../core/models'; import { UmbDataTypeStore } from '../../core/stores/data-type.store'; import { DataTypeEntity } from '../../mocks/data/data-type.data'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/data-type/views/editor-view-data-type-edit.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/data-type/views/editor-view-data-type-edit.element.ts index f4f41aafa9..916a6af190 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/data-type/views/editor-view-data-type-edit.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/data-type/views/editor-view-data-type-edit.element.ts @@ -6,7 +6,7 @@ import { ifDefined } from 'lit/directives/if-defined.js'; import { distinctUntilChanged, Subscription } from 'rxjs'; import { UmbContextConsumerMixin } from '../../../../core/context'; -import { ManifestPropertyEditorUI } from '../../../../core/models'; +import type { ManifestPropertyEditorUI } from '../../../../core/models'; import { UmbDataTypeContext } from '../data-type.context'; import type { DataTypeEntity } from '../../../../mocks/data/data-type.data'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/extensions/editor-extensions.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/extensions/editor-extensions.element.ts index 23bd318570..fa8a98ffdb 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/extensions/editor-extensions.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/extensions/editor-extensions.element.ts @@ -7,7 +7,7 @@ import { Subscription } from 'rxjs'; import { UmbContextConsumerMixin } from '../../../core/context'; import { UmbExtensionRegistry } from '../../../core/extension'; import { isManifestElementType } from '../../../core/extension/is-extension.function'; -import { ManifestCore } from '../../../core/models'; +import type { ManifestCore } from '../../../core/models'; @customElement('umb-editor-extensions') export class UmbEditorExtensionsElement extends UmbContextConsumerMixin(LitElement) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-entity/editor-entity.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-entity/editor-entity.element.ts index 353027af27..8a2220e081 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-entity/editor-entity.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/shared/editor-entity/editor-entity.element.ts @@ -8,7 +8,7 @@ import { map, Subscription } from 'rxjs'; import { UmbContextConsumerMixin } from '../../../../core/context'; import { UmbExtensionRegistry } from '../../../../core/extension'; -import { ManifestEditorView } from '../../../../core/models'; +import type { ManifestEditorView } from '../../../../core/models'; @customElement('umb-editor-entity') export class UmbEditorEntity extends UmbContextConsumerMixin(LitElement) { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/property-actions/property-action-menu/property-action-menu.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/property-actions/property-action-menu/property-action-menu.element.ts index 40a5836813..ad2b51e97e 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/property-actions/property-action-menu/property-action-menu.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/property-actions/property-action-menu/property-action-menu.element.ts @@ -7,7 +7,7 @@ import { map, Subscription } from 'rxjs'; import { UmbContextConsumerMixin, UmbContextProviderMixin } from '../../../core/context'; import { UmbExtensionRegistry } from '../../../core/extension'; -import { ManifestPropertyAction } from '../../../core/models'; +import type { ManifestPropertyAction } from '../../../core/models'; import { UmbPropertyActionMenuContext } from './property-action-menu.context'; @customElement('umb-property-action-menu') diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/property-actions/property-action/property-action.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/property-actions/property-action/property-action.element.ts index 3cccc1a032..75d5c7d73b 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/property-actions/property-action/property-action.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/property-actions/property-action/property-action.element.ts @@ -3,7 +3,7 @@ import { CSSResultGroup, html, LitElement } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import { createExtensionElement } from '../../../core/extension'; -import { ManifestPropertyAction } from '../../../core/models'; +import type { ManifestPropertyAction } from '../../../core/models'; import type { UmbPropertyAction } from './property-action.model'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/section.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/section.context.ts index e8c89397ed..8b5d8b64ed 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/section.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/section.context.ts @@ -1,6 +1,6 @@ import { BehaviorSubject } from 'rxjs'; -import { ManifestSection } from '../../core/models'; +import type { ManifestSection } from '../../core/models'; export class UmbSectionContext { // TODO: figure out how fine grained we want to make our observables. diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-dashboards.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-dashboards.element.ts index 579a96604c..fd4662b525 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-dashboards.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/shared/section-dashboards.element.ts @@ -6,9 +6,10 @@ import { first, map, Subscription } from 'rxjs'; import { UmbContextConsumerMixin } from '../../../core/context'; import { createExtensionElement, UmbExtensionRegistry } from '../../../core/extension'; -import { ManifestDashboard } from '../../../core/models'; import { UmbSectionContext } from '../section.context'; +import type { ManifestDashboard } from '../../../core/models'; + @customElement('umb-section-dashboards') export class UmbSectionDashboards extends UmbContextConsumerMixin(LitElement) { static styles = [ diff --git a/src/Umbraco.Web.UI.Client/src/installer/installer-consent.element.ts b/src/Umbraco.Web.UI.Client/src/installer/installer-consent.element.ts index be11bd5f45..edd051de63 100644 --- a/src/Umbraco.Web.UI.Client/src/installer/installer-consent.element.ts +++ b/src/Umbraco.Web.UI.Client/src/installer/installer-consent.element.ts @@ -4,7 +4,7 @@ import { unsafeHTML } from 'lit/directives/unsafe-html.js'; import { Subscription } from 'rxjs'; import { UmbContextConsumerMixin } from '../core/context'; -import { TelemetryModel } from '../core/models'; +import type { TelemetryModel } from '../core/models'; import { UmbInstallerContext } from './installer-context'; @customElement('umb-installer-consent') diff --git a/src/Umbraco.Web.UI.Client/src/installer/installer-context.ts b/src/Umbraco.Web.UI.Client/src/installer/installer-context.ts index 2d8fb4db4e..27691f8ea4 100644 --- a/src/Umbraco.Web.UI.Client/src/installer/installer-context.ts +++ b/src/Umbraco.Web.UI.Client/src/installer/installer-context.ts @@ -1,7 +1,7 @@ import { BehaviorSubject, ReplaySubject } from 'rxjs'; import { getInstallSettings, postInstallSetup } from '../core/api/fetcher'; -import { PostInstallRequest, UmbracoInstaller } from '../core/models'; +import type { PostInstallRequest, UmbracoInstaller } from '../core/models'; export class UmbInstallerContext { private _data = new BehaviorSubject({ diff --git a/src/Umbraco.Web.UI.Client/src/installer/installer-database.element.ts b/src/Umbraco.Web.UI.Client/src/installer/installer-database.element.ts index 4e3614bcbe..f52e9f1c12 100644 --- a/src/Umbraco.Web.UI.Client/src/installer/installer-database.element.ts +++ b/src/Umbraco.Web.UI.Client/src/installer/installer-database.element.ts @@ -5,7 +5,7 @@ import { Subscription } from 'rxjs'; import { postInstallSetup, postInstallValidateDatabase } from '../core/api/fetcher'; import { UmbContextConsumerMixin } from '../core/context'; -import { UmbracoInstallerDatabaseModel, UmbracoPerformInstallDatabaseConfiguration } from '../core/models'; +import type { UmbracoInstallerDatabaseModel, UmbracoPerformInstallDatabaseConfiguration } from '../core/models'; import { UmbInstallerContext } from './installer-context'; @customElement('umb-installer-database') diff --git a/src/Umbraco.Web.UI.Client/src/installer/installer-error.element.ts b/src/Umbraco.Web.UI.Client/src/installer/installer-error.element.ts index 053d15f9ed..bdd87bba0e 100644 --- a/src/Umbraco.Web.UI.Client/src/installer/installer-error.element.ts +++ b/src/Umbraco.Web.UI.Client/src/installer/installer-error.element.ts @@ -1,7 +1,7 @@ import { css, CSSResultGroup, html, LitElement, nothing } from 'lit'; import { customElement, property } from 'lit/decorators.js'; -import { ProblemDetails } from '../core/models'; +import type { ProblemDetails } from '../core/models'; @customElement('umb-installer-error') export class UmbInstallerError extends LitElement { diff --git a/src/Umbraco.Web.UI.Client/src/installer/installer.element.ts b/src/Umbraco.Web.UI.Client/src/installer/installer.element.ts index 2935e73208..a9ee78c830 100644 --- a/src/Umbraco.Web.UI.Client/src/installer/installer.element.ts +++ b/src/Umbraco.Web.UI.Client/src/installer/installer.element.ts @@ -10,7 +10,7 @@ import { customElement, state } from 'lit/decorators.js'; import { postInstallSetup } from '../core/api/fetcher'; import { UmbContextProviderMixin } from '../core/context'; -import { ProblemDetails } from '../core/models'; +import type { ProblemDetails } from '../core/models'; import { UmbInstallerContext } from './installer-context'; @customElement('umb-installer') diff --git a/src/Umbraco.Web.UI.Client/src/mocks/domains/install.handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/domains/install.handlers.ts index 969a588b54..d72ef78b14 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/domains/install.handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/domains/install.handlers.ts @@ -1,7 +1,7 @@ import { rest } from 'msw'; import umbracoPath from '../../core/helpers/umbraco-path'; -import { +import type { PostInstallRequest, ProblemDetails, UmbracoInstaller, diff --git a/src/Umbraco.Web.UI.Client/src/mocks/domains/server.handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/domains/server.handlers.ts index 5666b48de8..417a8b8706 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/domains/server.handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/domains/server.handlers.ts @@ -1,7 +1,7 @@ import { rest } from 'msw'; import umbracoPath from '../../core/helpers/umbraco-path'; -import { StatusResponse, VersionResponse } from '../../core/models'; +import type { StatusResponse, VersionResponse } from '../../core/models'; export const serverRunningHandler = rest.get(umbracoPath('/server/status'), (_req, res, ctx) => { return res( diff --git a/src/Umbraco.Web.UI.Client/src/mocks/domains/upgrade.handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/domains/upgrade.handlers.ts index 3006a21baa..6b00f51461 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/domains/upgrade.handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/domains/upgrade.handlers.ts @@ -1,7 +1,7 @@ import { rest } from 'msw'; import umbracoPath from '../../core/helpers/umbraco-path'; -import { PostInstallRequest, UmbracoUpgrader } from '../../core/models'; +import type { PostInstallRequest, UmbracoUpgrader } from '../../core/models'; export const handlers = [ rest.get(umbracoPath('/upgrade/settings'), (_req, res, ctx) => { diff --git a/src/Umbraco.Web.UI.Client/src/mocks/domains/user.handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/domains/user.handlers.ts index 111c38aa7c..4d31e91e55 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/domains/user.handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/domains/user.handlers.ts @@ -1,7 +1,7 @@ import { rest } from 'msw'; import umbracoPath from '../../core/helpers/umbraco-path'; -import { AllowedSectionsResponse, UserResponse } from '../../core/models'; +import type { AllowedSectionsResponse, UserResponse } from '../../core/models'; let isAuthenticated = false; diff --git a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts index d51b2c4456..a9b95749af 100644 --- a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts @@ -1,4 +1,4 @@ -import { ManifestCore } from './core/models'; +import type { ManifestCore } from './core/models'; // TODO: consider moving weight from meta to the main part of the manifest. We need it for every extension. // TODO: consider adding a label property as part of the meta. It might make sense to have an "extension" name label where one is needed. diff --git a/src/Umbraco.Web.UI.Client/src/upgrader/upgrader-view.element.ts b/src/Umbraco.Web.UI.Client/src/upgrader/upgrader-view.element.ts index 8b694109de..d51d7d5bd3 100644 --- a/src/Umbraco.Web.UI.Client/src/upgrader/upgrader-view.element.ts +++ b/src/Umbraco.Web.UI.Client/src/upgrader/upgrader-view.element.ts @@ -2,7 +2,7 @@ import { css, CSSResultGroup, html, LitElement } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { ifDefined } from 'lit/directives/if-defined.js'; -import { UmbracoUpgrader } from '../core/models'; +import type { UmbracoUpgrader } from '../core/models'; /** * @element umb-upgrader-view From 9c1dd23d2d804421806696fba0a1a273325ee4ca Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 25 Aug 2022 15:12:13 +0200 Subject: [PATCH 10/17] include custom types in schema --- src/Umbraco.Web.UI.Client/schemas/api/api.yml | 16 ++++++++++++++++ .../schemas/generated-schema.ts | 9 ++++++++- .../temp-schema-generator/manifests.ts | 13 +++++++++++-- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/schemas/api/api.yml b/src/Umbraco.Web.UI.Client/schemas/api/api.yml index 6c8c0ae7f4..330f2db671 100644 --- a/src/Umbraco.Web.UI.Client/schemas/api/api.yml +++ b/src/Umbraco.Web.UI.Client/schemas/api/api.yml @@ -549,6 +549,20 @@ components: - type - js - alias + IManifestCustom: + type: object + properties: + type: + type: string + enum: + - custom + meta: + type: object + alias: + type: string + required: + - type + - alias Manifest: oneOf: - $ref: '#/components/schemas/IManifestSection' @@ -557,6 +571,7 @@ components: - $ref: '#/components/schemas/IManifestEditorView' - $ref: '#/components/schemas/IManifestPropertyAction' - $ref: '#/components/schemas/IManifestEntrypoint' + - $ref: '#/components/schemas/IManifestCustom' discriminator: propertyName: type mapping: @@ -566,6 +581,7 @@ components: editorView: '#/components/schemas/IManifestEditorView' propertyAction: '#/components/schemas/IManifestPropertyAction' entrypoint: '#/components/schemas/IManifestEntrypoint' + custom: '#/components/schemas/IManifestCustom' ManifestsResponse: type: object properties: diff --git a/src/Umbraco.Web.UI.Client/schemas/generated-schema.ts b/src/Umbraco.Web.UI.Client/schemas/generated-schema.ts index 195ec03888..add5f409e3 100644 --- a/src/Umbraco.Web.UI.Client/schemas/generated-schema.ts +++ b/src/Umbraco.Web.UI.Client/schemas/generated-schema.ts @@ -182,13 +182,20 @@ export interface components { js: string; alias: string; }; + IManifestCustom: { + /** @enum {string} */ + type: "custom"; + meta?: { [key: string]: unknown }; + alias: string; + }; Manifest: | components["schemas"]["IManifestSection"] | components["schemas"]["IManifestPropertyEditorUI"] | components["schemas"]["IManifestDashboard"] | components["schemas"]["IManifestEditorView"] | components["schemas"]["IManifestPropertyAction"] - | components["schemas"]["IManifestEntrypoint"]; + | components["schemas"]["IManifestEntrypoint"] + | components["schemas"]["IManifestCustom"]; ManifestsResponse: { manifests: components["schemas"]["Manifest"][]; }; diff --git a/src/Umbraco.Web.UI.Client/temp-schema-generator/manifests.ts b/src/Umbraco.Web.UI.Client/temp-schema-generator/manifests.ts index 1dbb918077..47bf3b281b 100644 --- a/src/Umbraco.Web.UI.Client/temp-schema-generator/manifests.ts +++ b/src/Umbraco.Web.UI.Client/temp-schema-generator/manifests.ts @@ -17,7 +17,9 @@ export type Manifest = | IManifestDashboard | IManifestEditorView | IManifestPropertyAction - | IManifestEntrypoint; + | IManifestEntrypoint + | IManifestCustom; + export type ManifestStandardTypes = | 'section' | 'propertyEditorUI' @@ -31,7 +33,7 @@ export interface ManifestsResponse { } export interface IManifest { - type: ManifestStandardTypes; + type: string; alias: string; } @@ -63,10 +65,17 @@ export interface MetaPropertyAction { propertyEditors: string[]; } +export interface IManifestCustom extends IManifest { + type: 'custom'; + meta?: {}; +} + export interface IManifestElement extends IManifest { + type: ManifestStandardTypes; name: string; js?: string; elementName?: string; + meta?: {}; } export interface IManifestSection extends IManifestElement { From b5ca93d0a28f97e68c8f7009522e49d00f772d2c Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 25 Aug 2022 15:12:48 +0200 Subject: [PATCH 11/17] rename ManifestCore to ManifestTypes --- .../extensions/editor-extensions.element.ts | 5 +++-- .../src/core/extension/extension.registry.ts | 16 +++++++++------- .../core/extension/load-extension.function.ts | 8 ++++---- .../src/core/models/index.ts | 3 ++- .../src/temp-internal-manifests.ts | 4 ++-- 5 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editors/extensions/editor-extensions.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editors/extensions/editor-extensions.element.ts index fa8a98ffdb..1f1950d6a3 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editors/extensions/editor-extensions.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editors/extensions/editor-extensions.element.ts @@ -7,12 +7,13 @@ import { Subscription } from 'rxjs'; import { UmbContextConsumerMixin } from '../../../core/context'; import { UmbExtensionRegistry } from '../../../core/extension'; import { isManifestElementType } from '../../../core/extension/is-extension.function'; -import type { ManifestCore } from '../../../core/models'; + +import type { ManifestTypes } from '../../../core/models'; @customElement('umb-editor-extensions') export class UmbEditorExtensionsElement extends UmbContextConsumerMixin(LitElement) { @state() - private _extensions: Array = []; + private _extensions: Array = []; private _extensionRegistry?: UmbExtensionRegistry; private _extensionsSubscription?: Subscription; diff --git a/src/Umbraco.Web.UI.Client/src/core/extension/extension.registry.ts b/src/Umbraco.Web.UI.Client/src/core/extension/extension.registry.ts index 3a04353a95..f830563458 100644 --- a/src/Umbraco.Web.UI.Client/src/core/extension/extension.registry.ts +++ b/src/Umbraco.Web.UI.Client/src/core/extension/extension.registry.ts @@ -3,19 +3,20 @@ import { BehaviorSubject, map, Observable } from 'rxjs'; import { createExtensionElement } from './create-extension-element.function'; import type { - ManifestCore, + ManifestTypes, ManifestDashboard, ManifestEditorView, ManifestEntrypoint, ManifestPropertyAction, ManifestPropertyEditorUI, ManifestSection, + ManifestCustom, } from '../models'; export class UmbExtensionRegistry { - private _extensions = new BehaviorSubject>([]); + private _extensions = new BehaviorSubject>([]); public readonly extensions = this._extensions.asObservable(); - register(manifest: ManifestCore): void { + register(manifest: ManifestTypes): void { const extensionsValues = this._extensions.getValue(); const extension = extensionsValues.find((extension) => extension.alias === manifest.alias); @@ -32,7 +33,8 @@ export class UmbExtensionRegistry { } } - getByAlias(alias: string): Observable { + getByAlias(alias: string): Observable; + getByAlias(alias: string) { // TODO: make pipes prettier/simpler/reuseable return this.extensions.pipe(map((dataTypes) => dataTypes.find((extension) => extension.alias === alias) || null)); } @@ -46,9 +48,9 @@ export class UmbExtensionRegistry { extensionsOfType(type: 'propertyEditorUI'): Observable>; extensionsOfType(type: 'propertyAction'): Observable>; extensionsOfType(type: 'entrypoint'): Observable>; - extensionsOfType(type: string): Observable>; - extensionsOfType(type: string): Observable>; - extensionsOfType(type: string) { + extensionsOfType(type: 'custom'): Observable>; + extensionsOfType(type: string): Observable>; + extensionsOfType(type: string): Observable> { return this.extensions.pipe(map((exts) => exts.filter((ext) => ext.type === type))); } } diff --git a/src/Umbraco.Web.UI.Client/src/core/extension/load-extension.function.ts b/src/Umbraco.Web.UI.Client/src/core/extension/load-extension.function.ts index 03f45d97bd..556f60b063 100644 --- a/src/Umbraco.Web.UI.Client/src/core/extension/load-extension.function.ts +++ b/src/Umbraco.Web.UI.Client/src/core/extension/load-extension.function.ts @@ -1,8 +1,8 @@ -import { ManifestCore } from '../models'; +import { ManifestTypes } from '../models'; -export type ManifestLoaderType = ManifestCore & { loader: () => Promise }; +export type ManifestLoaderType = ManifestTypes & { loader: () => Promise }; -export function loadExtension(manifest: ManifestCore) { +export function loadExtension(manifest: ManifestTypes) { // TODO: change this back to dynamic import after POC. Vite complains about the dynamic imports in the public folder but doesn't include the temp app_plugins folder in the final build. // return import(/* @vite-ignore */ manifest.js); if (isManifestLoaderType(manifest)) { @@ -32,6 +32,6 @@ export function loadExtension(manifest: ManifestCore) { }) as Promise; } -export function isManifestLoaderType(manifest: ManifestCore): manifest is ManifestLoaderType { +export function isManifestLoaderType(manifest: ManifestTypes): manifest is ManifestLoaderType { return typeof (manifest as ManifestLoaderType).loader === 'function'; } diff --git a/src/Umbraco.Web.UI.Client/src/core/models/index.ts b/src/Umbraco.Web.UI.Client/src/core/models/index.ts index b987800b31..924d783b5b 100644 --- a/src/Umbraco.Web.UI.Client/src/core/models/index.ts +++ b/src/Umbraco.Web.UI.Client/src/core/models/index.ts @@ -16,13 +16,14 @@ export type UmbracoInstallerDatabaseModel = components['schemas']['InstallDataba export type UmbracoInstallerUserModel = components['schemas']['InstallUserModel']; export type TelemetryModel = components['schemas']['TelemetryModel']; export type ServerStatus = components['schemas']['ServerStatus']; -export type ManifestCore = components['schemas']['Manifest']; +export type ManifestTypes = components['schemas']['Manifest']; export type ManifestSection = components['schemas']['IManifestSection']; export type ManifestPropertyEditorUI = components['schemas']['IManifestPropertyEditorUI']; export type ManifestDashboard = components['schemas']['IManifestDashboard']; export type ManifestEditorView = components['schemas']['IManifestEditorView']; export type ManifestPropertyAction = components['schemas']['IManifestPropertyAction']; export type ManifestEntrypoint = components['schemas']['IManifestEntrypoint']; +export type ManifestCustom = components['schemas']['IManifestCustom']; export type ManifestElementType = | ManifestSection diff --git a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts index a9b95749af..48fa4ad186 100644 --- a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts @@ -1,8 +1,8 @@ -import type { ManifestCore } from './core/models'; +import type { ManifestTypes } from './core/models'; // TODO: consider moving weight from meta to the main part of the manifest. We need it for every extension. // TODO: consider adding a label property as part of the meta. It might make sense to have an "extension" name label where one is needed. -export const internalManifests: Array Promise }> = [ +export const internalManifests: Array Promise }> = [ { type: 'section', alias: 'Umb.Section.Content', From d9552ce04ab89ee52d87299efa236dbf9c57ccf3 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 25 Aug 2022 15:13:00 +0200 Subject: [PATCH 12/17] check that returned js might potentially be a new element --- .../extension/create-extension-element.function.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/core/extension/create-extension-element.function.ts b/src/Umbraco.Web.UI.Client/src/core/extension/create-extension-element.function.ts index b8ac4eb38b..b090e73053 100644 --- a/src/Umbraco.Web.UI.Client/src/core/extension/create-extension-element.function.ts +++ b/src/Umbraco.Web.UI.Client/src/core/extension/create-extension-element.function.ts @@ -1,13 +1,11 @@ -import { ManifestCore } from '../models'; +import { ManifestTypes } from '../models'; import { hasDefaultExport } from './has-default-export.function'; import { isManifestElementType } from './is-extension.function'; import { loadExtension } from './load-extension.function'; -export async function createExtensionElement(manifest: ManifestCore): Promise { - console.log('🚀 ~ file: create-extension-element.function.ts ~ line 7 ~ createExtensionElement ~ manifest', manifest); +export async function createExtensionElement(manifest: ManifestTypes): Promise { //TODO: Write tests for these extension options: const js = await loadExtension(manifest); - console.log('🚀 ~ file: create-extension-element.function.ts ~ line 9 ~ createExtensionElement ~ js', js); if (isManifestElementType(manifest) && manifest.elementName) { // created by manifest method providing HTMLElement return document.createElement(manifest.elementName); @@ -17,9 +15,9 @@ export async function createExtensionElement(manifest: ManifestCore): Promise Date: Thu, 25 Aug 2022 15:46:38 +0200 Subject: [PATCH 13/17] ensure that we load server-side manifests dynamically and our mocks are not included in the production build --- .../public/App_Plugins/custom-entrypoint.js | 1 - .../create-extension-element.function.ts | 12 ++- .../core/extension/load-extension.function.ts | 36 ++++---- .../mocks/App_Plugins/custom-entrypoint.js | 4 + .../mocks}/App_Plugins/property-editor.js | 0 .../mocks}/App_Plugins/section.js | 0 .../src/mocks/browser-handlers.ts | 12 ++- .../src/mocks/domains/manifests.handlers.ts | 82 ++++++++++--------- .../src/mocks/e2e-handlers.ts | 8 +- 9 files changed, 87 insertions(+), 68 deletions(-) delete mode 100644 src/Umbraco.Web.UI.Client/public/App_Plugins/custom-entrypoint.js create mode 100644 src/Umbraco.Web.UI.Client/src/mocks/App_Plugins/custom-entrypoint.js rename src/Umbraco.Web.UI.Client/{public => src/mocks}/App_Plugins/property-editor.js (100%) rename src/Umbraco.Web.UI.Client/{public => src/mocks}/App_Plugins/section.js (100%) diff --git a/src/Umbraco.Web.UI.Client/public/App_Plugins/custom-entrypoint.js b/src/Umbraco.Web.UI.Client/public/App_Plugins/custom-entrypoint.js deleted file mode 100644 index d55405508c..0000000000 --- a/src/Umbraco.Web.UI.Client/public/App_Plugins/custom-entrypoint.js +++ /dev/null @@ -1 +0,0 @@ -console.log('Hello from the custom entrypoint!'); diff --git a/src/Umbraco.Web.UI.Client/src/core/extension/create-extension-element.function.ts b/src/Umbraco.Web.UI.Client/src/core/extension/create-extension-element.function.ts index b090e73053..2e03d273e2 100644 --- a/src/Umbraco.Web.UI.Client/src/core/extension/create-extension-element.function.ts +++ b/src/Umbraco.Web.UI.Client/src/core/extension/create-extension-element.function.ts @@ -6,15 +6,19 @@ import { loadExtension } from './load-extension.function'; export async function createExtensionElement(manifest: ManifestTypes): Promise { //TODO: Write tests for these extension options: const js = await loadExtension(manifest); + if (isManifestElementType(manifest) && manifest.elementName) { // created by manifest method providing HTMLElement return document.createElement(manifest.elementName); } + + // TODO: Do we need this except for the default() loader? if (js) { if (js instanceof HTMLElement) { console.log('-- created by manifest method providing HTMLElement', js); return js; } + if (isManifestElementType(js) && js.elementName) { // created by js export elementName return document.createElement(js.elementName); @@ -24,7 +28,11 @@ export async function createExtensionElement(manifest: ManifestTypes): Promise Promise }; +export type ManifestJSType = ManifestTypes & { js: string }; -export function loadExtension(manifest: ManifestTypes) { - // TODO: change this back to dynamic import after POC. Vite complains about the dynamic imports in the public folder but doesn't include the temp app_plugins folder in the final build. - // return import(/* @vite-ignore */ manifest.js); +export async function loadExtension(manifest: ManifestTypes): Promise { if (isManifestLoaderType(manifest)) { return manifest.loader(); } - return new Promise((resolve, reject) => { - if (!manifest.js) { - resolve(null); - return; + if (isManifestJSType(manifest) && manifest.js) { + try { + return await import(/* @vite-ignore */ manifest.js); + } catch { + console.warn('-- Extension failed to load script', manifest.js); + return Promise.resolve(null); } + } - const script = document.createElement('script'); - script.type = 'text/javascript'; - //script.charset = 'utf-8'; - script.async = true; - script.type = 'module'; - script.src = manifest.js; - script.crossOrigin = 'anonymous'; - script.onload = function () { - resolve(null); - }; - script.onerror = function () { - reject(new Error(`Script load error for ${manifest.js}`)); - }; - document.body.appendChild(script); - }) as Promise; + return Promise.resolve(null); } export function isManifestLoaderType(manifest: ManifestTypes): manifest is ManifestLoaderType { return typeof (manifest as ManifestLoaderType).loader === 'function'; } + +export function isManifestJSType(manifest: ManifestTypes): manifest is ManifestJSType { + return (manifest as ManifestJSType).js !== undefined; +} diff --git a/src/Umbraco.Web.UI.Client/src/mocks/App_Plugins/custom-entrypoint.js b/src/Umbraco.Web.UI.Client/src/mocks/App_Plugins/custom-entrypoint.js new file mode 100644 index 0000000000..8de2547b92 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/mocks/App_Plugins/custom-entrypoint.js @@ -0,0 +1,4 @@ +console.log('Hello from the custom entrypoint file!'); +export default function () { + console.log('Hello from the custom entrypoint inside the default function!'); +} diff --git a/src/Umbraco.Web.UI.Client/public/App_Plugins/property-editor.js b/src/Umbraco.Web.UI.Client/src/mocks/App_Plugins/property-editor.js similarity index 100% rename from src/Umbraco.Web.UI.Client/public/App_Plugins/property-editor.js rename to src/Umbraco.Web.UI.Client/src/mocks/App_Plugins/property-editor.js diff --git a/src/Umbraco.Web.UI.Client/public/App_Plugins/section.js b/src/Umbraco.Web.UI.Client/src/mocks/App_Plugins/section.js similarity index 100% rename from src/Umbraco.Web.UI.Client/public/App_Plugins/section.js rename to src/Umbraco.Web.UI.Client/src/mocks/App_Plugins/section.js diff --git a/src/Umbraco.Web.UI.Client/src/mocks/browser-handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/browser-handlers.ts index 3df67a6277..5154cd1d05 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/browser-handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/browser-handlers.ts @@ -2,7 +2,7 @@ import { handlers as contentHandlers } from './domains/content.handlers'; import { handlers as dataTypeHandlers } from './domains/data-type.handlers'; import { handlers as documentTypeHandlers } from './domains/document-type.handlers'; import { handlers as installHandlers } from './domains/install.handlers'; -import { handlers as manifestsHandlers } from './domains/manifests.handlers'; +import * as manifestsHandlers from './domains/manifests.handlers'; import * as serverHandlers from './domains/server.handlers'; import { handlers as upgradeHandlers } from './domains/upgrade.handlers'; import { handlers as userHandlers } from './domains/user.handlers'; @@ -12,7 +12,6 @@ const handlers = [ ...contentHandlers, ...installHandlers, ...upgradeHandlers, - ...manifestsHandlers, ...userHandlers, ...dataTypeHandlers, ...documentTypeHandlers, @@ -29,4 +28,13 @@ switch (import.meta.env.VITE_UMBRACO_INSTALL_STATUS) { handlers.push(serverHandlers.serverRunningHandler); } +switch (import.meta.env.MODE) { + case 'development': + handlers.push(manifestsHandlers.manifestDevelopmentHandler); + break; + + default: + handlers.push(manifestsHandlers.manifestEmptyHandler); +} + export { handlers }; diff --git a/src/Umbraco.Web.UI.Client/src/mocks/domains/manifests.handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/domains/manifests.handlers.ts index 7175f30be6..d2288693c2 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/domains/manifests.handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/domains/manifests.handlers.ts @@ -4,42 +4,50 @@ import umbracoPath from '../../core/helpers/umbraco-path'; import type { ManifestsResponse } from '../../core/models'; -export const handlers = [ - rest.get(umbracoPath('/manifests'), (_req, res, ctx) => { - return res( - // Respond with a 200 status code - ctx.status(200), - ctx.json({ - manifests: [ - { - type: 'section', - alias: 'My.Section.Custom', - name: 'Custom Section', - js: '/App_Plugins/section.js', - elementName: 'my-section-custom', - meta: { - pathname: 'my-custom', - weight: 1, - }, +export const manifestDevelopmentHandler = rest.get(umbracoPath('/manifests'), (_req, res, ctx) => { + return res( + // Respond with a 200 status code + ctx.status(200), + ctx.json({ + manifests: [ + { + type: 'section', + alias: 'My.Section.Custom', + name: 'Custom Section', + js: '/src/mocks/App_Plugins/section.js', + elementName: 'my-section-custom', + meta: { + pathname: 'my-custom', + weight: 1, }, - { - type: 'propertyEditorUI', - alias: 'My.PropertyEditorUI.Custom', - name: 'My Custom Property Editor UI', - js: '/App_Plugins/property-editor.js', - elementName: 'my-property-editor-ui-custom', - meta: { - icon: 'document', - group: 'common', - }, + }, + { + type: 'propertyEditorUI', + alias: 'My.PropertyEditorUI.Custom', + name: 'My Custom Property Editor UI', + js: '/src/mocks/App_Plugins/property-editor.js', + elementName: 'my-property-editor-ui-custom', + meta: { + icon: 'document', + group: 'common', }, - { - type: 'entrypoint', - alias: 'My.Entrypoint.Custom', - js: '/App_Plugins/custom-entrypoint.js', - }, - ], - }) - ); - }), -]; + }, + { + type: 'entrypoint', + alias: 'My.Entrypoint.Custom', + js: '/src/mocks/App_Plugins/custom-entrypoint.js', + }, + ], + }) + ); +}); + +export const manifestEmptyHandler = rest.get(umbracoPath('/manifests'), (_req, res, ctx) => { + return res( + // Respond with a 200 status code + ctx.status(200), + ctx.json({ + manifests: [], + }) + ); +}); diff --git a/src/Umbraco.Web.UI.Client/src/mocks/e2e-handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/e2e-handlers.ts index 7e20f40369..f573be6393 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/e2e-handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/e2e-handlers.ts @@ -1,19 +1,19 @@ import { handlers as contentHandlers } from './domains/content.handlers'; +import { handlers as dataTypeHandlers } from './domains/data-type.handlers'; +import { handlers as documentTypeHandlers } from './domains/document-type.handlers'; import { handlers as installHandlers } from './domains/install.handlers'; -import { handlers as manifestsHandlers } from './domains/manifests.handlers'; +import * as manifestsHandlers from './domains/manifests.handlers'; import * as serverHandlers from './domains/server.handlers'; import { handlers as upgradeHandlers } from './domains/upgrade.handlers'; import { handlers as userHandlers } from './domains/user.handlers'; -import { handlers as dataTypeHandlers } from './domains/data-type.handlers'; -import { handlers as documentTypeHandlers } from './domains/document-type.handlers'; export const handlers = [ serverHandlers.serverRunningHandler, serverHandlers.serverVersionHandler, + manifestsHandlers.manifestDevelopmentHandler, ...contentHandlers, ...installHandlers, ...upgradeHandlers, - ...manifestsHandlers, ...userHandlers, ...dataTypeHandlers, ...documentTypeHandlers, From a74f9886f8ce910cec43b049f8732abb467b2f36 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 25 Aug 2022 15:58:27 +0200 Subject: [PATCH 14/17] import types --- src/Umbraco.Web.UI.Client/eslint-local-rules.cjs | 2 +- src/Umbraco.Web.UI.Client/src/core/api/fetcher.ts | 2 +- .../src/core/context/context-consumer.mixin.ts | 2 +- .../src/core/context/context-provider.mixin.ts | 2 +- .../src/core/extension/create-extension-element.function.ts | 3 ++- .../src/core/extension/has-default-export.function.ts | 2 +- .../src/core/extension/load-extension.function.ts | 2 +- src/Umbraco.Web.UI.Client/src/core/helpers/umbraco-path.ts | 2 +- src/Umbraco.Web.UI.Client/src/core/models/index.ts | 2 +- 9 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/eslint-local-rules.cjs b/src/Umbraco.Web.UI.Client/eslint-local-rules.cjs index b124352065..eeddac50c8 100644 --- a/src/Umbraco.Web.UI.Client/eslint-local-rules.cjs +++ b/src/Umbraco.Web.UI.Client/eslint-local-rules.cjs @@ -20,7 +20,7 @@ module.exports = { create: function (context) { return { ImportDeclaration: function (node) { - if (node.source.parent.importKind !== 'type' && (node.source.value.endsWith('core/models') || node.source.value === 'router-slot/model')) { + if (node.source.parent.importKind !== 'type' && (node.source.value.endsWith('/models') || node.source.value.endsWith('/generated-schema') || node.source.value === 'router-slot/model')) { const sourceCode = context.getSourceCode(); const nodeSource = sourceCode.getText(node); context.report({ diff --git a/src/Umbraco.Web.UI.Client/src/core/api/fetcher.ts b/src/Umbraco.Web.UI.Client/src/core/api/fetcher.ts index 9a1b15d88f..4da48cf721 100644 --- a/src/Umbraco.Web.UI.Client/src/core/api/fetcher.ts +++ b/src/Umbraco.Web.UI.Client/src/core/api/fetcher.ts @@ -1,6 +1,6 @@ import { Fetcher } from 'openapi-typescript-fetch'; -import { paths } from '../../../schemas/generated-schema'; +import type { paths } from '../../../schemas/generated-schema'; const fetcher = Fetcher.for(); diff --git a/src/Umbraco.Web.UI.Client/src/core/context/context-consumer.mixin.ts b/src/Umbraco.Web.UI.Client/src/core/context/context-consumer.mixin.ts index 4162344031..5e639f9898 100644 --- a/src/Umbraco.Web.UI.Client/src/core/context/context-consumer.mixin.ts +++ b/src/Umbraco.Web.UI.Client/src/core/context/context-consumer.mixin.ts @@ -1,4 +1,4 @@ -import { HTMLElementConstructor } from '../models'; +import type { HTMLElementConstructor } from '../models'; import { UmbContextConsumer } from './context-consumer'; export declare class UmbContextConsumerInterface { diff --git a/src/Umbraco.Web.UI.Client/src/core/context/context-provider.mixin.ts b/src/Umbraco.Web.UI.Client/src/core/context/context-provider.mixin.ts index 26a4c95e66..a8784e091e 100644 --- a/src/Umbraco.Web.UI.Client/src/core/context/context-provider.mixin.ts +++ b/src/Umbraco.Web.UI.Client/src/core/context/context-provider.mixin.ts @@ -1,4 +1,4 @@ -import { HTMLElementConstructor } from '../models'; +import type { HTMLElementConstructor } from '../models'; import { UmbContextProvider } from './context-provider'; export declare class UmbContextProviderMixinInterface { diff --git a/src/Umbraco.Web.UI.Client/src/core/extension/create-extension-element.function.ts b/src/Umbraco.Web.UI.Client/src/core/extension/create-extension-element.function.ts index 2e03d273e2..0775639aa3 100644 --- a/src/Umbraco.Web.UI.Client/src/core/extension/create-extension-element.function.ts +++ b/src/Umbraco.Web.UI.Client/src/core/extension/create-extension-element.function.ts @@ -1,8 +1,9 @@ -import { ManifestTypes } from '../models'; import { hasDefaultExport } from './has-default-export.function'; import { isManifestElementType } from './is-extension.function'; import { loadExtension } from './load-extension.function'; +import type { ManifestTypes } from '../models'; + export async function createExtensionElement(manifest: ManifestTypes): Promise { //TODO: Write tests for these extension options: const js = await loadExtension(manifest); diff --git a/src/Umbraco.Web.UI.Client/src/core/extension/has-default-export.function.ts b/src/Umbraco.Web.UI.Client/src/core/extension/has-default-export.function.ts index d8b965ced5..de21ac631b 100644 --- a/src/Umbraco.Web.UI.Client/src/core/extension/has-default-export.function.ts +++ b/src/Umbraco.Web.UI.Client/src/core/extension/has-default-export.function.ts @@ -1,4 +1,4 @@ -import { HTMLElementConstructor } from '../models'; +import type { HTMLElementConstructor } from '../models'; export function hasDefaultExport(object: unknown): object is { default: HTMLElementConstructor } { return typeof object === 'object' && object !== null && 'default' in object; diff --git a/src/Umbraco.Web.UI.Client/src/core/extension/load-extension.function.ts b/src/Umbraco.Web.UI.Client/src/core/extension/load-extension.function.ts index 066f30cb62..933127b559 100644 --- a/src/Umbraco.Web.UI.Client/src/core/extension/load-extension.function.ts +++ b/src/Umbraco.Web.UI.Client/src/core/extension/load-extension.function.ts @@ -1,4 +1,4 @@ -import { ManifestTypes } from '../models'; +import type { ManifestTypes } from '../models'; export type ManifestLoaderType = ManifestTypes & { loader: () => Promise }; export type ManifestJSType = ManifestTypes & { js: string }; diff --git a/src/Umbraco.Web.UI.Client/src/core/helpers/umbraco-path.ts b/src/Umbraco.Web.UI.Client/src/core/helpers/umbraco-path.ts index 89c92816cb..f77f30c645 100644 --- a/src/Umbraco.Web.UI.Client/src/core/helpers/umbraco-path.ts +++ b/src/Umbraco.Web.UI.Client/src/core/helpers/umbraco-path.ts @@ -1,6 +1,6 @@ import { Path } from 'msw'; -import { paths } from '../../../schemas/generated-schema'; +import type { paths } from '../../../schemas/generated-schema'; export default function umbracoPath(path: keyof paths): Path { return `/umbraco/backoffice${path}`; diff --git a/src/Umbraco.Web.UI.Client/src/core/models/index.ts b/src/Umbraco.Web.UI.Client/src/core/models/index.ts index 924d783b5b..e479692ca9 100644 --- a/src/Umbraco.Web.UI.Client/src/core/models/index.ts +++ b/src/Umbraco.Web.UI.Client/src/core/models/index.ts @@ -1,4 +1,4 @@ -import { components } from '../../../schemas/generated-schema'; +import type { components } from '../../../schemas/generated-schema'; export type PostInstallRequest = components['schemas']['InstallSetupRequest']; export type StatusResponse = components['schemas']['StatusResponse']; From c262f537de124c7489f6143a62ec447cadc19f72 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Fri, 26 Aug 2022 09:59:47 +0200 Subject: [PATCH 15/17] add vscode launch configuration --- src/Umbraco.Web.UI.Client/.vscode/launch.json | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/.vscode/launch.json diff --git a/src/Umbraco.Web.UI.Client/.vscode/launch.json b/src/Umbraco.Web.UI.Client/.vscode/launch.json new file mode 100644 index 0000000000..094ba1adaf --- /dev/null +++ b/src/Umbraco.Web.UI.Client/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "chrome", + "request": "launch", + "name": "Launch Chrome against localhost", + "url": "http://localhost:5173", + "webRoot": "${workspaceFolder}" + } + ] +} From 0391b105661f3ac9ee3a85056f0adf4d01df62f5 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Fri, 26 Aug 2022 13:39:09 +0200 Subject: [PATCH 16/17] catch more errors --- .../core/extension/load-extension.function.ts | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/core/extension/load-extension.function.ts b/src/Umbraco.Web.UI.Client/src/core/extension/load-extension.function.ts index 933127b559..969d97aaef 100644 --- a/src/Umbraco.Web.UI.Client/src/core/extension/load-extension.function.ts +++ b/src/Umbraco.Web.UI.Client/src/core/extension/load-extension.function.ts @@ -4,17 +4,17 @@ export type ManifestLoaderType = ManifestTypes & { loader: () => Promise { - if (isManifestLoaderType(manifest)) { - return manifest.loader(); - } - - if (isManifestJSType(manifest) && manifest.js) { - try { - return await import(/* @vite-ignore */ manifest.js); - } catch { - console.warn('-- Extension failed to load script', manifest.js); - return Promise.resolve(null); + try { + if (isManifestLoaderType(manifest)) { + return manifest.loader(); } + + if (isManifestJSType(manifest) && manifest.js) { + return await import(/* @vite-ignore */ manifest.js); + } + } catch { + console.warn('-- Extension failed to load script', manifest); + return Promise.resolve(null); } return Promise.resolve(null); From f14f9672f82876af65518bca5b1e2876c0faefc5 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Fri, 26 Aug 2022 13:39:40 +0200 Subject: [PATCH 17/17] remove unused loader functions --- .../extension/create-extension-element.function.ts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/core/extension/create-extension-element.function.ts b/src/Umbraco.Web.UI.Client/src/core/extension/create-extension-element.function.ts index 0775639aa3..354f44be0c 100644 --- a/src/Umbraco.Web.UI.Client/src/core/extension/create-extension-element.function.ts +++ b/src/Umbraco.Web.UI.Client/src/core/extension/create-extension-element.function.ts @@ -15,16 +15,6 @@ export async function createExtensionElement(manifest: ManifestTypes): Promise