diff --git a/src/Umbraco.Web.UI.Client/.eslintrc.json b/src/Umbraco.Web.UI.Client/.eslintrc.json index 6f7f532665..a3bfe0790b 100644 --- a/src/Umbraco.Web.UI.Client/.eslintrc.json +++ b/src/Umbraco.Web.UI.Client/.eslintrc.json @@ -31,10 +31,6 @@ }, "rules": { "no-var": "error", - "quotes": [ - "error", - "single" - ], "import/no-unresolved": "error" }, "settings": { @@ -50,4 +46,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/Umbraco.Web.UI.Client/.prettierrc.json b/src/Umbraco.Web.UI.Client/.prettierrc.json index 093d881bf2..6080de481e 100644 --- a/src/Umbraco.Web.UI.Client/.prettierrc.json +++ b/src/Umbraco.Web.UI.Client/.prettierrc.json @@ -3,5 +3,6 @@ "singleQuote": true, "semi": true, "bracketSpacing": true, - "bracketSameLine": true + "bracketSameLine": true, + "useTabs": true } diff --git a/src/Umbraco.Web.UI.Client/src/app.ts b/src/Umbraco.Web.UI.Client/src/app.ts index 10d44403b7..0e3c527958 100644 --- a/src/Umbraco.Web.UI.Client/src/app.ts +++ b/src/Umbraco.Web.UI.Client/src/app.ts @@ -14,120 +14,120 @@ import { IRoute } from 'router-slot/model'; @customElement('umb-app') export class UmbApp extends UmbContextProviderMixin(LitElement) { - static styles = css` - :host, - #router-slot { - display: block; - width: 100%; - height: 100vh; - } - `; + static styles = css` + :host, + #router-slot { + display: block; + width: 100%; + height: 100vh; + } + `; - @state() - private _routes: IRoute[] = [ - { - path: 'login', - component: () => import('./auth/login/login.element'), - }, - { - path: 'install', - component: () => import('./installer/installer.element'), - }, - { - path: 'upgrade', - component: () => import('./upgrader/upgrader.element'), - guards: [this._isAuthorizedGuard.bind(this)], - }, - { - path: '**', - component: () => import('./backoffice/backoffice.element'), - guards: [this._isAuthorizedGuard.bind(this)], - }, - ]; + @state() + private _routes: IRoute[] = [ + { + path: 'login', + component: () => import('./auth/login/login.element'), + }, + { + path: 'install', + component: () => import('./installer/installer.element'), + }, + { + path: 'upgrade', + component: () => import('./upgrader/upgrader.element'), + guards: [this._isAuthorizedGuard.bind(this)], + }, + { + path: '**', + component: () => import('./backoffice/backoffice.element'), + guards: [this._isAuthorizedGuard.bind(this)], + }, + ]; - private _extensionRegistry: UmbExtensionRegistry = new UmbExtensionRegistry(); - private _iconRegistry: UUIIconRegistryEssential = new UUIIconRegistryEssential(); - private _serverStatus: ServerStatus = 'running'; + private _extensionRegistry: UmbExtensionRegistry = new UmbExtensionRegistry(); + private _iconRegistry: UUIIconRegistryEssential = new UUIIconRegistryEssential(); + private _serverStatus: ServerStatus = 'running'; - constructor() { - super(); - this._setup(); - } + constructor() { + super(); + this._setup(); + } - private async _setup() { - this._iconRegistry.attach(this); - this.provideContext('umbExtensionRegistry', this._extensionRegistry); + private async _setup() { + this._iconRegistry.attach(this); + this.provideContext('umbExtensionRegistry', this._extensionRegistry); - await this._registerExtensionManifestsFromServer(); - await this._registerInternalManifests(); - await this._setInitStatus(); - this._redirect(); - } + await this._registerExtensionManifestsFromServer(); + await this._registerInternalManifests(); + await this._setInitStatus(); + this._redirect(); + } - private async _setInitStatus() { - try { - const { data } = await getServerStatus({}); - this._serverStatus = data.serverStatus; - } catch (error) { - console.log(error); - } - } + private async _setInitStatus() { + try { + const { data } = await getServerStatus({}); + this._serverStatus = data.serverStatus; + } catch (error) { + console.log(error); + } + } - private _redirect() { - switch (this._serverStatus) { - case 'must-install': - history.replaceState(null, '', '/install'); - break; + private _redirect() { + switch (this._serverStatus) { + case 'must-install': + history.replaceState(null, '', '/install'); + break; - case 'must-upgrade': - history.replaceState(null, '', '/upgrade'); - break; + case 'must-upgrade': + history.replaceState(null, '', '/upgrade'); + break; - case 'running': { - const pathname = - window.location.pathname === '/install' || window.location.pathname === '/upgrade' - ? '/' - : window.location.pathname; - history.replaceState(null, '', pathname); - break; - } - } - } + case 'running': { + const pathname = + window.location.pathname === '/install' || window.location.pathname === '/upgrade' + ? '/' + : window.location.pathname; + history.replaceState(null, '', pathname); + break; + } + } + } - private _isAuthorized(): boolean { - return sessionStorage.getItem('is-authenticated') === 'true'; - } + private _isAuthorized(): boolean { + return sessionStorage.getItem('is-authenticated') === 'true'; + } - private _isAuthorizedGuard(): boolean { - if (this._isAuthorized()) { - return true; - } + private _isAuthorizedGuard(): boolean { + if (this._isAuthorized()) { + return true; + } - history.replaceState(null, '', '/login'); - return false; - } + history.replaceState(null, '', '/login'); + return false; + } - 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)); - } + 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)); + } - private async _registerInternalManifests() { - // TODO: where do we get these from? - internalManifests.forEach((manifest: UmbExtensionManifestCore) => - this._extensionRegistry.register(manifest) - ); - } + private async _registerInternalManifests() { + // TODO: where do we get these from? + internalManifests.forEach((manifest: UmbExtensionManifestCore) => + this._extensionRegistry.register(manifest) + ); + } - render() { - return html``; - } + render() { + return html``; + } } declare global { - interface HTMLElementTagNameMap { - 'umb-app': UmbApp; - } + interface HTMLElementTagNameMap { + 'umb-app': UmbApp; + } } diff --git a/src/Umbraco.Web.UI.Client/src/auth/auth-layout.element.ts b/src/Umbraco.Web.UI.Client/src/auth/auth-layout.element.ts index 611717ea44..fb36ac0327 100644 --- a/src/Umbraco.Web.UI.Client/src/auth/auth-layout.element.ts +++ b/src/Umbraco.Web.UI.Client/src/auth/auth-layout.element.ts @@ -3,70 +3,70 @@ import { customElement } from 'lit/decorators.js'; @customElement('umb-auth-layout') export class UmbAuthLayout extends LitElement { - static styles: CSSResultGroup = [ - css` - #background { - position: fixed; - overflow: hidden; - background-position: 50%; - background-repeat: no-repeat; - background-size: cover; - background-image: url('/login.jpeg'); - width: 100vw; - height: 100vh; - } + static styles: CSSResultGroup = [ + css` + #background { + position: fixed; + overflow: hidden; + background-position: 50%; + background-repeat: no-repeat; + background-size: cover; + background-image: url('/login.jpeg'); + width: 100vw; + height: 100vh; + } - #logo { - position: fixed; - top: var(--uui-size-space-5); - left: var(--uui-size-space-5); - height: 30px; - } + #logo { + position: fixed; + top: var(--uui-size-space-5); + left: var(--uui-size-space-5); + height: 30px; + } - #logo img { - height: 100%; - } + #logo img { + height: 100%; + } - #container { - position: relative; - display: flex; - align-items: center; - justify-content: center; - width: 100vw; - height: 100vh; - } + #container { + position: relative; + display: flex; + align-items: center; + justify-content: center; + width: 100vw; + height: 100vh; + } - #box { - width: 500px; - padding: var(--uui-size-space-6) var(--uui-size-space-5) var(--uui-size-space-5) var(--uui-size-space-5); - } + #box { + width: 500px; + padding: var(--uui-size-space-6) var(--uui-size-space-5) var(--uui-size-space-5) var(--uui-size-space-5); + } - #email, - #password { - width: 100%; - } - `, - ]; + #email, + #password { + width: 100%; + } + `, + ]; - render() { - return html` -
+ render() { + return html` +
- + -
- - - -
- `; - } +
+ + + +
+ `; + } } declare global { - interface HTMLElementTagNameMap { - 'umb-auth-layout': UmbAuthLayout; - } + interface HTMLElementTagNameMap { + 'umb-auth-layout': UmbAuthLayout; + } } diff --git a/src/Umbraco.Web.UI.Client/src/auth/login/login.element.ts b/src/Umbraco.Web.UI.Client/src/auth/login/login.element.ts index 04253795be..7d9cda0384 100644 --- a/src/Umbraco.Web.UI.Client/src/auth/login/login.element.ts +++ b/src/Umbraco.Web.UI.Client/src/auth/login/login.element.ts @@ -9,112 +9,112 @@ import '../auth-layout.element'; @customElement('umb-login') export default class UmbLogin extends LitElement { - static styles: CSSResultGroup = [ - UUITextStyles, - css` - #email, - #password { - width: 100%; - } - `, - ]; + static styles: CSSResultGroup = [ + UUITextStyles, + css` + #email, + #password { + width: 100%; + } + `, + ]; - @state() - private _loggingIn = false; + @state() + private _loggingIn = false; - private _handleSubmit = (e: SubmitEvent) => { - e.preventDefault(); + private _handleSubmit = (e: SubmitEvent) => { + e.preventDefault(); - const form = e.target as HTMLFormElement; - if (!form) return; + const form = e.target as HTMLFormElement; + if (!form) return; - const isValid = form.checkValidity(); - if (!isValid) return; + const isValid = form.checkValidity(); + if (!isValid) return; - const formData = new FormData(form); + const formData = new FormData(form); - const username = formData.get('email') as string; - const password = formData.get('password') as string; - const persist = formData.has('persist'); + const username = formData.get('email') as string; + const password = formData.get('password') as string; + const persist = formData.has('persist'); - this._login(username, password, persist); - }; + this._login(username, password, persist); + }; - private async _login(username: string, password: string, persist: boolean) { - this._loggingIn = true; + private async _login(username: string, password: string, persist: boolean) { + this._loggingIn = true; - try { - await postUserLogin({ username, password, persist }); - this._loggingIn = false; - history.pushState(null, '', '/section'); - } catch (error) { - console.log(error); - this._loggingIn = false; - } - } + try { + await postUserLogin({ username, password, persist }); + this._loggingIn = false; + history.pushState(null, '', '/section'); + } catch (error) { + console.log(error); + this._loggingIn = false; + } + } - private _greetings: Array = [ - 'Happy super Sunday', - 'Happy marvelous Monday', - 'Happy tubular Tuesday', - 'Happy wonderful Wednesday', - 'Happy thunderous Thursday', - 'Happy funky Friday', - 'Happy Saturday', - ]; + private _greetings: Array = [ + 'Happy super Sunday', + 'Happy marvelous Monday', + 'Happy tubular Tuesday', + 'Happy wonderful Wednesday', + 'Happy thunderous Thursday', + 'Happy funky Friday', + 'Happy Saturday', + ]; - @state() - private _greeting: string = this._greetings[new Date().getDay()]; + @state() + private _greeting: string = this._greetings[new Date().getDay()]; - render() { - return html` - -
-

${this._greeting}

- -
- - Email - - + render() { + return html` + +
+

${this._greeting}

+ + + + Email + + - - Password - - + + Password + + - - Remember me - + + Remember me + - - - - -
-
- `; - } + + + +
+
+
+ `; + } } declare global { - interface HTMLElementTagNameMap { - 'umb-login': UmbLogin; - } + interface HTMLElementTagNameMap { + 'umb-login': UmbLogin; + } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts index c77cd7f0c5..957af35b5f 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts @@ -17,40 +17,40 @@ import './components/section-sidebar.element'; @defineElement('umb-backoffice') export default class UmbBackoffice extends UmbContextProviderMixin(LitElement) { - static styles = [ - UUITextStyles, - css` - :host { - display: flex; - flex-direction: column; - height: 100%; - width: 100%; - color: var(--uui-color-text); - font-size: 14px; - box-sizing: border-box; - } - `, - ]; + static styles = [ + UUITextStyles, + css` + :host { + display: flex; + flex-direction: column; + height: 100%; + width: 100%; + color: var(--uui-color-text); + font-size: 14px; + box-sizing: border-box; + } + `, + ]; - constructor() { - super(); + constructor() { + super(); - this.provideContext('umbNodeStore', new UmbNodeStore()); - this.provideContext('umbDataTypeStore', new UmbDataTypeStore()); - this.provideContext('umbNotificationService', new UmbNotificationService()); - } + this.provideContext('umbNodeStore', new UmbNodeStore()); + this.provideContext('umbDataTypeStore', new UmbDataTypeStore()); + this.provideContext('umbNotificationService', new UmbNotificationService()); + } - render() { - return html` - - - - `; - } + render() { + return html` + + + + `; + } } declare global { - interface HTMLElementTagNameMap { - 'umb-backoffice': UmbBackoffice; - } + interface HTMLElementTagNameMap { + 'umb-backoffice': UmbBackoffice; + } } 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 41e3d4f7a9..64739ae765 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 @@ -11,149 +11,149 @@ import { UmbExtensionManifestSection, UmbExtensionRegistry } from '../../core/ex @customElement('umb-backoffice-header-sections') export class UmbBackofficeHeaderSections extends UmbContextConsumerMixin(LitElement) { - static styles: CSSResultGroup = [ - UUITextStyles, - css` - #tabs { - color: var(--uui-color-header-contrast); - height: 60px; - font-size: 16px; - --uui-tab-text: var(--uui-color-header-contrast); - --uui-tab-text-hover: var(--uui-color-header-contrast-emphasis); - --uui-tab-text-active: var(--uui-color-header-contrast-emphasis); - --uui-tab-background: var(--uui-color-header-background); - } + static styles: CSSResultGroup = [ + UUITextStyles, + css` + #tabs { + color: var(--uui-color-header-contrast); + height: 60px; + font-size: 16px; + --uui-tab-text: var(--uui-color-header-contrast); + --uui-tab-text-hover: var(--uui-color-header-contrast-emphasis); + --uui-tab-text-active: var(--uui-color-header-contrast-emphasis); + --uui-tab-background: var(--uui-color-header-background); + } - #dropdown { - background-color: white; - border-radius: var(--uui-border-radius); - width: 100%; - height: 100%; - box-sizing: border-box; - box-shadow: var(--uui-shadow-depth-3); - min-width: 200px; - color: black; /* Change to variable */ - } - `, - ]; + #dropdown { + background-color: white; + border-radius: var(--uui-border-radius); + width: 100%; + height: 100%; + box-sizing: border-box; + box-shadow: var(--uui-shadow-depth-3); + min-width: 200px; + color: black; /* Change to variable */ + } + `, + ]; - @state() - private _open = false; + @state() + private _open = false; - @state() - private _allowedSection: Array = []; + @state() + private _allowedSection: Array = []; - @state() - private _sections: Array = []; + @state() + private _sections: Array = []; - @state() - private _visibleSections: Array = []; + @state() + private _visibleSections: Array = []; - @state() - private _extraSections: Array = []; + @state() + private _extraSections: Array = []; - @state() - private _currentSectionAlias = ''; + @state() + private _currentSectionAlias = ''; - private _extensionRegistry?: UmbExtensionRegistry; + private _extensionRegistry?: UmbExtensionRegistry; - private _sectionSubscription?: Subscription; + private _sectionSubscription?: Subscription; - constructor() { - super(); + constructor() { + super(); - this.consumeContext('umbExtensionRegistry', (extensionRegistry: UmbExtensionRegistry) => { - this._extensionRegistry = extensionRegistry; - this._useSections(); - }); - } + this.consumeContext('umbExtensionRegistry', (extensionRegistry: UmbExtensionRegistry) => { + this._extensionRegistry = extensionRegistry; + this._useSections(); + }); + } - private _handleMore(e: MouseEvent) { - e.stopPropagation(); - this._open = !this._open; - } + private _handleMore(e: MouseEvent) { + e.stopPropagation(); + this._open = !this._open; + } - private _handleTabClick(e: PointerEvent) { - const tab = e.currentTarget as HTMLElement; + private _handleTabClick(e: PointerEvent) { + const tab = e.currentTarget as HTMLElement; - // TODO: we need to be able to prevent the tab from setting the active state - if (tab.id === 'moreTab') { - return; - } - } + // TODO: we need to be able to prevent the tab from setting the active state + if (tab.id === 'moreTab') { + return; + } + } - private _handleLabelClick() { - const moreTab = this.shadowRoot?.getElementById('moreTab'); - moreTab?.setAttribute('active', 'true'); + private _handleLabelClick() { + const moreTab = this.shadowRoot?.getElementById('moreTab'); + moreTab?.setAttribute('active', 'true'); - this._open = false; - } + this._open = false; + } - private async _useSections() { - this._sectionSubscription?.unsubscribe(); + private async _useSections() { + this._sectionSubscription?.unsubscribe(); - const { data } = await getUserSections({}); - this._allowedSection = data.sections; + const { data } = await getUserSections({}); + this._allowedSection = data.sections; - this._sectionSubscription = this._extensionRegistry - ?.extensionsOfType('section') - .pipe(map((extensions) => extensions.sort((a, b) => b.meta.weight - a.meta.weight))) - .subscribe((sections) => { - this._sections = sections.filter((section) => this._allowedSection.includes(section.alias)); - this._visibleSections = this._sections; - }); - } + this._sectionSubscription = this._extensionRegistry + ?.extensionsOfType('section') + .pipe(map((extensions) => extensions.sort((a, b) => b.meta.weight - a.meta.weight))) + .subscribe((sections) => { + this._sections = sections.filter((section) => this._allowedSection.includes(section.alias)); + this._visibleSections = this._sections; + }); + } - disconnectedCallback(): void { - super.disconnectedCallback(); - this._sectionSubscription?.unsubscribe(); - } + disconnectedCallback(): void { + super.disconnectedCallback(); + this._sectionSubscription?.unsubscribe(); + } - render() { - return html` - - ${this._visibleSections.map( - (section: UmbExtensionManifestSection) => html` - - ` - )} - ${this._renderExtraSections()} - - `; - } + render() { + return html` + + ${this._visibleSections.map( + (section: UmbExtensionManifestSection) => html` + + ` + )} + ${this._renderExtraSections()} + + `; + } - private _renderExtraSections() { - return when( - this._extraSections.length > 0, - () => html` - - - - - + private _renderExtraSections() { + return when( + this._extraSections.length > 0, + () => html` + + + + + - - - - ` - ); - } + + + + ` + ); + } } declare global { - interface HTMLElementTagNameMap { - 'umb-backoffice-header-sections': UmbBackofficeHeaderSections; - } + interface HTMLElementTagNameMap { + 'umb-backoffice-header-sections': UmbBackofficeHeaderSections; + } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/components/backoffice-header-tools.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/components/backoffice-header-tools.element.ts index fdabd01b34..0958b10c39 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/components/backoffice-header-tools.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/components/backoffice-header-tools.element.ts @@ -4,40 +4,40 @@ import { customElement } from 'lit/decorators.js'; @customElement('umb-backoffice-header-tools') export class UmbBackofficeHeaderTools extends LitElement { - static styles: CSSResultGroup = [ - UUITextStyles, - css` - #tools { - display: flex; - align-items: center; - gap: var(--uui-size-space-2); - } + static styles: CSSResultGroup = [ + UUITextStyles, + css` + #tools { + display: flex; + align-items: center; + gap: var(--uui-size-space-2); + } - .tool { - font-size: 18px; - } - `, - ]; + .tool { + font-size: 18px; + } + `, + ]; - render() { - return html` -
- - - - - - - - - -
- `; - } + render() { + return html` +
+ + + + + + + + + +
+ `; + } } declare global { - interface HTMLElementTagNameMap { - 'umb-backoffice-header-tools': UmbBackofficeHeaderTools; - } + interface HTMLElementTagNameMap { + 'umb-backoffice-header-tools': UmbBackofficeHeaderTools; + } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/components/backoffice-header.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/components/backoffice-header.element.ts index a1caaa3aaa..2220edd6bd 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/components/backoffice-header.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/components/backoffice-header.element.ts @@ -7,54 +7,54 @@ import './backoffice-header-tools.element'; @customElement('umb-backoffice-header') export class UmbBackofficeHeader extends LitElement { - static styles: CSSResultGroup = [ - UUITextStyles, - css` - :host { - width: 100%; - } + static styles: CSSResultGroup = [ + UUITextStyles, + css` + :host { + width: 100%; + } - #appHeader { - background-color: var(--uui-color-header-surface); - display: flex; - align-items: center; - justify-content: space-between; - padding: 0 var(--uui-size-space-5); - } + #appHeader { + background-color: var(--uui-color-header-surface); + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 var(--uui-size-space-5); + } - #logo { - --uui-button-padding-top-factor: 1; - --uui-button-padding-bottom-factor: 0.5; - margin-right: var(--uui-size-space-2); - } + #logo { + --uui-button-padding-top-factor: 1; + --uui-button-padding-bottom-factor: 0.5; + margin-right: var(--uui-size-space-2); + } - #logo img { - height: var(--uui-size-10); - width: var(--uui-size-10); - } + #logo img { + height: var(--uui-size-10); + width: var(--uui-size-10); + } - #sections { - flex: 1 1 auto; - } - `, - ]; + #sections { + flex: 1 1 auto; + } + `, + ]; - render() { - return html` -
- + render() { + return html` +
+ - - -
- `; - } + + +
+ `; + } } declare global { - interface HTMLElementTagNameMap { - 'umb-backoffice-header': UmbBackofficeHeader; - } + interface HTMLElementTagNameMap { + 'umb-backoffice-header': UmbBackofficeHeader; + } } 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 3f91a840a8..4632c07b09 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 @@ -9,72 +9,72 @@ import { createExtensionElement, UmbExtensionManifestSection, UmbExtensionRegist @defineElement('umb-backoffice-main') export class UmbBackofficeMain extends UmbContextConsumerMixin(LitElement) { - static styles = [ - UUITextStyles, - css` - :host { - background-color: var(--uui-color-background); - display: block; - width: 100%; - height: 100%; - } - `, - ]; + static styles = [ + UUITextStyles, + css` + :host { + background-color: var(--uui-color-background); + display: block; + width: 100%; + height: 100%; + } + `, + ]; - @state() - private _routes: Array = []; + @state() + private _routes: Array = []; - @state() - private _sections: Array = []; + @state() + private _sections: Array = []; - private _extensionRegistry?: UmbExtensionRegistry; - private _sectionSubscription?: Subscription; + private _extensionRegistry?: UmbExtensionRegistry; + private _sectionSubscription?: Subscription; - constructor() { - super(); + constructor() { + super(); - this.consumeContext('umbExtensionRegistry', (_instance: UmbExtensionRegistry) => { - this._extensionRegistry = _instance; - this._useSections(); - }); - } + this.consumeContext('umbExtensionRegistry', (_instance: UmbExtensionRegistry) => { + this._extensionRegistry = _instance; + this._useSections(); + }); + } - private _useSections() { - this._sectionSubscription?.unsubscribe(); + private _useSections() { + this._sectionSubscription?.unsubscribe(); - this._sectionSubscription = this._extensionRegistry - ?.extensionsOfType('section') - .pipe(map((extensions) => extensions.sort((a, b) => b.meta.weight - a.meta.weight))) - .subscribe((sections) => { - this._routes = []; - this._sections = sections as Array; + this._sectionSubscription = this._extensionRegistry + ?.extensionsOfType('section') + .pipe(map((extensions) => extensions.sort((a, b) => b.meta.weight - a.meta.weight))) + .subscribe((sections) => { + this._routes = []; + this._sections = sections as Array; - this._routes = this._sections.map((section) => { - return { - path: 'section/' + section.meta.pathname, - component: () => createExtensionElement(section), - }; - }); + this._routes = this._sections.map((section) => { + return { + path: 'section/' + section.meta.pathname, + component: () => createExtensionElement(section), + }; + }); - this._routes.push({ - path: '**', - redirectTo: 'section/' + this._sections[0].meta.pathname, - }); - }); - } + this._routes.push({ + path: '**', + redirectTo: 'section/' + this._sections[0].meta.pathname, + }); + }); + } - disconnectedCallback(): void { - super.disconnectedCallback(); - this._sectionSubscription?.unsubscribe(); - } + disconnectedCallback(): void { + super.disconnectedCallback(); + this._sectionSubscription?.unsubscribe(); + } - render() { - return html``; - } + render() { + return html``; + } } declare global { - interface HTMLElementTagNameMap { - 'umb-backoffice-main': UmbBackofficeMain; - } + interface HTMLElementTagNameMap { + 'umb-backoffice-main': UmbBackofficeMain; + } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/components/backoffice-notification-container.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/components/backoffice-notification-container.element.ts index 26757b355e..31f51102ea 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/components/backoffice-notification-container.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/components/backoffice-notification-container.element.ts @@ -8,68 +8,68 @@ import { UmbNotificationService } from '../../core/services/notification.service @customElement('umb-backoffice-notification-container') export class UmbBackofficeNotificationContainer extends UmbContextConsumerMixin(LitElement) { - static styles: CSSResultGroup = [ - UUITextStyles, - css` - #notifications { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 70px; - height: auto; - padding: var(--uui-size-layout-1); - } - `, - ]; + static styles: CSSResultGroup = [ + UUITextStyles, + css` + #notifications { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 70px; + height: auto; + padding: var(--uui-size-layout-1); + } + `, + ]; - @state() - private _notifications: any[] = []; + @state() + private _notifications: any[] = []; - private _notificationService?: UmbNotificationService; - private _notificationSubscription?: Subscription; + private _notificationService?: UmbNotificationService; + private _notificationSubscription?: Subscription; - constructor() { - super(); + constructor() { + super(); - this.consumeContext('umbNotificationService', (notificationService: UmbNotificationService) => { - this._notificationService = notificationService; - this._useNotifications(); - }); - } + this.consumeContext('umbNotificationService', (notificationService: UmbNotificationService) => { + this._notificationService = notificationService; + this._useNotifications(); + }); + } - private _useNotifications() { - this._notificationSubscription?.unsubscribe(); + private _useNotifications() { + this._notificationSubscription?.unsubscribe(); - this._notificationService?.notifications.subscribe((notifications: Array) => { - this._notifications = notifications; - }); + this._notificationService?.notifications.subscribe((notifications: Array) => { + this._notifications = notifications; + }); - // TODO: listen to close event and remove notification from store. - } + // TODO: listen to close event and remove notification from store. + } - disconnectedCallback(): void { - super.disconnectedCallback(); - this._notificationSubscription?.unsubscribe(); - } + disconnectedCallback(): void { + super.disconnectedCallback(); + this._notificationSubscription?.unsubscribe(); + } - render() { - return html` - - ${repeat( - this._notifications, - (notification) => notification.key, - (notification) => html` - - ` - )} - - `; - } + render() { + return html` + + ${repeat( + this._notifications, + (notification) => notification.key, + (notification) => html` + + ` + )} + + `; + } } declare global { - interface HTMLElementTagNameMap { - 'umb-backoffice-notification-container': UmbBackofficeNotificationContainer; - } + interface HTMLElementTagNameMap { + 'umb-backoffice-notification-container': UmbBackofficeNotificationContainer; + } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/components/editor-layout.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/components/editor-layout.element.ts index f471cead01..ae7376b5eb 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/components/editor-layout.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/components/editor-layout.element.ts @@ -4,78 +4,78 @@ import { customElement } from 'lit/decorators.js'; @customElement('umb-editor-layout') class UmbEditorLayout extends LitElement { - static styles = [ - UUITextStyles, - css` - :host { - display: block; - width: 100%; - height: 100%; - } + static styles = [ + UUITextStyles, + css` + :host { + display: block; + width: 100%; + height: 100%; + } - #editor-frame { - background-color: var(--uui-color-background); - width: 100%; - height: 100%; - display: flex; - flex-direction: column; - } + #editor-frame { + background-color: var(--uui-color-background); + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + } - #header { - background-color: var(--uui-color-surface); - width: 100%; - display: flex; - flex: none; - gap: 16px; - align-items: center; - border-bottom: 1px solid var(--uui-color-border); - } + #header { + background-color: var(--uui-color-surface); + width: 100%; + display: flex; + flex: none; + gap: 16px; + align-items: center; + border-bottom: 1px solid var(--uui-color-border); + } - #main { - padding: var(--uui-size-6); - display: flex; - flex: 1; - flex-direction: column; - gap: 16px; - } + #main { + padding: var(--uui-size-6); + display: flex; + flex: 1; + flex-direction: column; + gap: 16px; + } - #footer { - display: flex; - flex: none; - justify-content: end; - align-items: center; - height: 70px; - width: 100%; - gap: 16px; - padding-right: 24px; - border-top: 1px solid var(--uui-color-border); - background-color: var(--uui-color-surface); - box-sizing: border-box; - } - `, - ]; + #footer { + display: flex; + flex: none; + justify-content: end; + align-items: center; + height: 70px; + width: 100%; + gap: 16px; + padding-right: 24px; + border-top: 1px solid var(--uui-color-border); + background-color: var(--uui-color-surface); + box-sizing: border-box; + } + `, + ]; - render() { - return html` -
- - - - - -
- `; - } + render() { + return html` +
+ + + + + +
+ `; + } } declare global { - interface HTMLElementTagNameMap { - 'umb-editor-layout': UmbEditorLayout; - } + interface HTMLElementTagNameMap { + 'umb-editor-layout': UmbEditorLayout; + } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/components/editor-property-layout.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/components/editor-property-layout.element.ts index fae108eb89..c814c7ba03 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/components/editor-property-layout.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/components/editor-property-layout.element.ts @@ -4,27 +4,27 @@ import { customElement } from 'lit/decorators.js'; @customElement('umb-editor-property-layout') class UmbEditorPropertyLayout extends LitElement { - static styles = [ - UUITextStyles, - css` - :host { - display: grid; - grid-template-columns: 200px 600px; - gap: 32px; - } - `, - ]; + static styles = [ + UUITextStyles, + css` + :host { + display: grid; + grid-template-columns: 200px 600px; + gap: 32px; + } + `, + ]; - render() { - return html` - - - `; - } + render() { + return html` + + + `; + } } declare global { - interface HTMLElementTagNameMap { - 'umb-editor-property-layout': UmbEditorPropertyLayout; - } + interface HTMLElementTagNameMap { + 'umb-editor-property-layout': UmbEditorPropertyLayout; + } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/components/node-editor.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/components/node-editor.element.ts index ced2b0aefe..5e7df0d665 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/components/node-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/components/node-editor.element.ts @@ -16,229 +16,229 @@ import '../editor-views/editor-view-node-info.element'; @customElement('umb-node-editor') export class UmbNodeEditor extends UmbContextConsumerMixin(LitElement) { - static styles = [ - UUITextStyles, - css` - :host { - display: block; - width: 100%; - height: 100%; - } + static styles = [ + UUITextStyles, + css` + :host { + display: block; + width: 100%; + height: 100%; + } - uui-input { - width: 100%; - margin-left: 16px; - } + uui-input { + width: 100%; + margin-left: 16px; + } - uui-tab-group { - --uui-tab-divider: var(--uui-color-border); - border-left: 1px solid var(--uui-color-border); - flex-wrap: nowrap; - height: 60px; - } + uui-tab-group { + --uui-tab-divider: var(--uui-color-border); + border-left: 1px solid var(--uui-color-border); + flex-wrap: nowrap; + height: 60px; + } - uui-tab { - font-size: 0.8rem; - } + uui-tab { + font-size: 0.8rem; + } - uui-box hr { - margin-bottom: var(--uui-size-6); - } - `, - ]; + uui-box hr { + margin-bottom: var(--uui-size-6); + } + `, + ]; - @property() - id!: string; + @property() + id!: string; - @state() - _node?: DocumentNode; + @state() + _node?: DocumentNode; - @state() - private _routes: Array = []; + @state() + private _routes: Array = []; - @state() - private _editorViews: Array = []; + @state() + private _editorViews: Array = []; - @state() - private _currentView = ''; + @state() + private _currentView = ''; - private _nodeStore?: UmbNodeStore; - private _nodeSubscription?: Subscription; + private _nodeStore?: UmbNodeStore; + private _nodeSubscription?: Subscription; - private _notificationService?: UmbNotificationService; + private _notificationService?: UmbNotificationService; - private _extensionRegistry?: UmbExtensionRegistry; - private _editorViewsSubscription?: Subscription; + private _extensionRegistry?: UmbExtensionRegistry; + private _editorViewsSubscription?: Subscription; - private _routerFolder = ''; + private _routerFolder = ''; - constructor() { - super(); + constructor() { + super(); - this.consumeContext('umbNodeStore', (store: UmbNodeStore) => { - this._nodeStore = store; - this._useNode(); - }); + this.consumeContext('umbNodeStore', (store: UmbNodeStore) => { + this._nodeStore = store; + this._useNode(); + }); - this.consumeContext('umbNotificationService', (service: UmbNotificationService) => { - this._notificationService = service; - }); + this.consumeContext('umbNotificationService', (service: UmbNotificationService) => { + this._notificationService = service; + }); - this.consumeContext('umbExtensionRegistry', (extensionRegistry: UmbExtensionRegistry) => { - this._extensionRegistry = extensionRegistry; - this._useEditorViews(); - }); + this.consumeContext('umbExtensionRegistry', (extensionRegistry: UmbExtensionRegistry) => { + this._extensionRegistry = extensionRegistry; + this._useEditorViews(); + }); - this.addEventListener('property-value-change', this._onPropertyValueChange); - } + this.addEventListener('property-value-change', this._onPropertyValueChange); + } - connectedCallback(): void { - super.connectedCallback(); - /* TODO: find a way to construct absolute urls */ - this._routerFolder = window.location.pathname.split('/view')[0]; - } + connectedCallback(): void { + super.connectedCallback(); + /* TODO: find a way to construct absolute urls */ + this._routerFolder = window.location.pathname.split('/view')[0]; + } - private _onPropertyValueChange = (e: Event) => { - const target = e.composedPath()[0] as any; + private _onPropertyValueChange = (e: Event) => { + const target = e.composedPath()[0] as any; - // TODO: Set value. - const property = this._node?.properties.find((x) => x.alias === target.property.alias); - if (property) { - // TODO: Dont set the temp value, but set it on the data part of our model. - property.tempValue = target.value; - } else { - console.error('property was not found', target.property.alias); - } - }; + // TODO: Set value. + const property = this._node?.properties.find((x) => x.alias === target.property.alias); + if (property) { + // TODO: Dont set the temp value, but set it on the data part of our model. + property.tempValue = target.value; + } else { + console.error('property was not found', target.property.alias); + } + }; - private _useNode() { - this._nodeSubscription?.unsubscribe(); + private _useNode() { + this._nodeSubscription?.unsubscribe(); - this._nodeSubscription = this._nodeStore?.getById(parseInt(this.id)).subscribe((node) => { - if (!node) return; // TODO: Handle nicely if there is no node. - this._node = node; - // TODO: merge observables - this._createRoutes(); - }); - } + this._nodeSubscription = this._nodeStore?.getById(parseInt(this.id)).subscribe((node) => { + if (!node) return; // TODO: Handle nicely if there is no node. + this._node = node; + // TODO: merge observables + this._createRoutes(); + }); + } - private _useEditorViews() { - this._editorViewsSubscription?.unsubscribe(); + private _useEditorViews() { + this._editorViewsSubscription?.unsubscribe(); - // TODO: how do we know which editor to show the views for? - this._editorViewsSubscription = this._extensionRegistry?.extensions - .pipe( - map((extensions: Array) => - extensions - .filter((extension) => extension.type === 'editorView') - .sort((a: any, b: any) => b.meta.weight - a.meta.weight) - ) - ) - .subscribe((dashboards: Array) => { - this._editorViews = dashboards as Array; - // TODO: merge observables - this._createRoutes(); - }); - } + // TODO: how do we know which editor to show the views for? + this._editorViewsSubscription = this._extensionRegistry?.extensions + .pipe( + map((extensions: Array) => + extensions + .filter((extension) => extension.type === 'editorView') + .sort((a: any, b: any) => b.meta.weight - a.meta.weight) + ) + ) + .subscribe((dashboards: Array) => { + this._editorViews = dashboards as Array; + // TODO: merge observables + this._createRoutes(); + }); + } - private _onSaveAndPublish() { - this._onSave(); - } + private _onSaveAndPublish() { + this._onSave(); + } - private _onSave() { - // TODO: What if store is not present, what if node is not loaded.... - if (this._node) { - this._nodeStore?.save([this._node]).then(() => { - this._notificationService?.peek('Document saved'); - }); - } - } + private _onSave() { + // TODO: What if store is not present, what if node is not loaded.... + if (this._node) { + this._nodeStore?.save([this._node]).then(() => { + this._notificationService?.peek('Document saved'); + }); + } + } - private _onSaveAndPreview() { - this._onSave(); - } + private _onSaveAndPreview() { + this._onSave(); + } - private async _createRoutes() { - if (this._node && this._editorViews.length > 0) { - this._routes = []; + private async _createRoutes() { + if (this._node && this._editorViews.length > 0) { + this._routes = []; - this._routes = this._editorViews.map((view) => { - return { - path: `view/${view.meta.pathname}`, - component: () => document.createElement(view.elementName), - setup: (element: HTMLElement, info: IRoutingInfo) => { - // TODO: make interface for EditorViews - const editorView = element as any; - // TODO: how do we pass data to views? Maybe we should use a context? - editorView.node = this._node; - this._currentView = info.match.route.path; - }, - }; - }); - this._routes.push({ - path: '**', - redirectTo: `view/${this._editorViews?.[0].meta.pathname}`, - }); + this._routes = this._editorViews.map((view) => { + return { + path: `view/${view.meta.pathname}`, + component: () => document.createElement(view.elementName), + setup: (element: HTMLElement, info: IRoutingInfo) => { + // TODO: make interface for EditorViews + const editorView = element as any; + // TODO: how do we pass data to views? Maybe we should use a context? + editorView.node = this._node; + this._currentView = info.match.route.path; + }, + }; + }); + this._routes.push({ + path: '**', + redirectTo: `view/${this._editorViews?.[0].meta.pathname}`, + }); - this.requestUpdate(); - await this.updateComplete; + this.requestUpdate(); + await this.updateComplete; - this._forceRouteRender(); - } - } + this._forceRouteRender(); + } + } - // TODO: Fgure out why this has been necessary for this case. Come up with another case - private _forceRouteRender() { - const routerSlotEl = this.shadowRoot?.querySelector('router-slot') as RouterSlot; - if (routerSlotEl) { - routerSlotEl.render(); - } - } + // TODO: Fgure out why this has been necessary for this case. Come up with another case + private _forceRouteRender() { + const routerSlotEl = this.shadowRoot?.querySelector('router-slot') as RouterSlot; + if (routerSlotEl) { + routerSlotEl.render(); + } + } - disconnectedCallback(): void { - super.disconnectedCallback(); - this._nodeSubscription?.unsubscribe(); - delete this._node; - } + disconnectedCallback(): void { + super.disconnectedCallback(); + this._nodeSubscription?.unsubscribe(); + delete this._node; + } - render() { - return html` - - - - ${this._editorViews.map( - (view: UmbExtensionManifestEditorView) => html` - - - ${view.name} - - ` - )} - + render() { + return html` + + + + ${this._editorViews.map( + (view: UmbExtensionManifestEditorView) => html` + + + ${view.name} + + ` + )} + - + -
- - - -
-
- `; - } +
+ + + +
+
+ `; + } } export default UmbNodeEditor; declare global { - interface HTMLElementTagNameMap { - 'umb-node-editor': UmbNodeEditor; - } + interface HTMLElementTagNameMap { + 'umb-node-editor': UmbNodeEditor; + } } 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 d49eb74eff..7e4079993f 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 @@ -10,152 +10,152 @@ import { DataTypeEntity } from '../../mocks/data/content.data'; @customElement('umb-node-property') class UmbNodeProperty extends UmbContextConsumerMixin(LitElement) { - static styles = [ - UUITextStyles, - css` - :host { - display: block; - } - p { - color: var(--uui-color-text-alt); - } - `, - ]; + static styles = [ + UUITextStyles, + css` + :host { + display: block; + } + p { + color: var(--uui-color-text-alt); + } + `, + ]; - private _property: any; // TODO: property data model interface.. - @property() - public get property(): any { - return this._property; - } - public set property(value: any) { - this._property = value; - this._useDataType(); - } + private _property: any; // TODO: property data model interface.. + @property() + public get property(): any { + return this._property; + } + public set property(value: any) { + this._property = value; + this._useDataType(); + } - @property() - value?: string; + @property() + value?: string; - // TODO: make interface for UMBPropertyEditorElement - @state() - private _element?: { value?: string } & HTMLElement; // TODO: invent interface for propertyEditorUI. + // TODO: make interface for UMBPropertyEditorElement + @state() + private _element?: { value?: string } & HTMLElement; // TODO: invent interface for propertyEditorUI. - private _dataType?: DataTypeEntity; - private _extensionRegistry?: UmbExtensionRegistry; - private _dataTypeStore?: UmbDataTypeStore; - private _dataTypeSubscription?: Subscription; + private _dataType?: DataTypeEntity; + private _extensionRegistry?: UmbExtensionRegistry; + private _dataTypeStore?: UmbDataTypeStore; + private _dataTypeSubscription?: Subscription; - constructor() { - super(); + constructor() { + super(); - /** TODO: Use DI for these types of services. */ - this.consumeContext('umbDataTypeStore', (_instance: UmbDataTypeStore) => { - this._dataTypeStore = _instance; - this._useDataType(); - }); - this.consumeContext('umbExtensionRegistry', (_instance: UmbExtensionRegistry) => { - this._extensionRegistry = _instance; - this._useDataType(); - }); + /** TODO: Use DI for these types of services. */ + this.consumeContext('umbDataTypeStore', (_instance: UmbDataTypeStore) => { + this._dataTypeStore = _instance; + this._useDataType(); + }); + this.consumeContext('umbExtensionRegistry', (_instance: UmbExtensionRegistry) => { + this._extensionRegistry = _instance; + this._useDataType(); + }); - // TODO: solution to know when both contexts are available - } + // TODO: solution to know when both contexts are available + } - // TODO: use subscribtion, rename to _useDataType: - private _useDataType() { - this._dataTypeSubscription?.unsubscribe(); - if (this._property.dataTypeKey && this._extensionRegistry && this._dataTypeStore) { - this._dataTypeSubscription = this._dataTypeStore - .getByKey(this._property.dataTypeKey) - .pipe( - switchMap((dataTypeEntity) => { - if (!dataTypeEntity) { - return EMPTY; - } - this._dataType = dataTypeEntity; + // TODO: use subscribtion, rename to _useDataType: + private _useDataType() { + this._dataTypeSubscription?.unsubscribe(); + if (this._property.dataTypeKey && this._extensionRegistry && this._dataTypeStore) { + this._dataTypeSubscription = this._dataTypeStore + .getByKey(this._property.dataTypeKey) + .pipe( + switchMap((dataTypeEntity) => { + if (!dataTypeEntity) { + return EMPTY; + } + this._dataType = dataTypeEntity; - return this._extensionRegistry?.getByAlias(dataTypeEntity.propertyEditorUIAlias) ?? of(null); - }) - ) - .subscribe((propertyEditorUI) => { - if (propertyEditorUI) { - this._gotData(propertyEditorUI); - } - // TODO: If gone what then... - }); - } - } + return this._extensionRegistry?.getByAlias(dataTypeEntity.propertyEditorUIAlias) ?? of(null); + }) + ) + .subscribe((propertyEditorUI) => { + if (propertyEditorUI) { + this._gotData(propertyEditorUI); + } + // TODO: If gone what then... + }); + } + } - private _gotData(_propertyEditorUI?: UmbExtensionManifest) { - if (!this._dataType || !_propertyEditorUI) { - // TODO: if dataTypeKey didn't exist in store, we should do some nice UI. - return; - } + private _gotData(_propertyEditorUI?: UmbExtensionManifest) { + if (!this._dataType || !_propertyEditorUI) { + // TODO: if dataTypeKey didn't exist in store, we should do some nice UI. + return; + } - createExtensionElement(_propertyEditorUI) - .then((el) => { - const oldValue = this._element; - this._element = el; + createExtensionElement(_propertyEditorUI) + .then((el) => { + const oldValue = this._element; + this._element = el; - // TODO: Set/Parse Data-Type-UI-configuration + // TODO: Set/Parse Data-Type-UI-configuration - if (oldValue) { - oldValue.removeEventListener('property-editor-change', this._onPropertyEditorChange as any as EventListener); - } + if (oldValue) { + oldValue.removeEventListener('property-editor-change', this._onPropertyEditorChange as any as EventListener); + } - /* NYT lav callback: */ - if (this._element) { - this._element.addEventListener( - 'property-editor-change', - this._onPropertyEditorChange as any as EventListener - ); - this._element.value = this.value; // Be aware its duplicated code - } - this.requestUpdate('element', oldValue); - }) - .catch(() => { - // TODO: loading JS failed so we should do some nice UI. (This does only happen if extension has a js prop, otherwise we concluded that no source was needed resolved the load.) - }); - } + /* NYT lav callback: */ + if (this._element) { + this._element.addEventListener( + 'property-editor-change', + this._onPropertyEditorChange as any as EventListener + ); + this._element.value = this.value; // Be aware its duplicated code + } + this.requestUpdate('element', oldValue); + }) + .catch(() => { + // TODO: loading JS failed so we should do some nice UI. (This does only happen if extension has a js prop, otherwise we concluded that no source was needed resolved the load.) + }); + } - private _onPropertyEditorChange = (e: CustomEvent) => { - this.value = (e.target as any).value; - this.dispatchEvent(new CustomEvent('property-value-change', { bubbles: true, composed: true })); - // No need for this event to leave scope. - e.stopPropagation(); - }; + private _onPropertyEditorChange = (e: CustomEvent) => { + this.value = (e.target as any).value; + this.dispatchEvent(new CustomEvent('property-value-change', { bubbles: true, composed: true })); + // No need for this event to leave scope. + e.stopPropagation(); + }; - /** Lit does not currently handle dynamic tag names, therefor we are doing some manual rendering */ - // TODO: Refactor into a base class for dynamic-tag element? we will be using this a lot for extensions. - // This could potentially hook into Lit and parse all properties defined in the specific class on to the dynamic-element. (see static elementProperties: PropertyDeclarationMap;) - willUpdate(changedProperties: PropertyValueMap | Map) { - super.willUpdate(changedProperties); + /** Lit does not currently handle dynamic tag names, therefor we are doing some manual rendering */ + // TODO: Refactor into a base class for dynamic-tag element? we will be using this a lot for extensions. + // This could potentially hook into Lit and parse all properties defined in the specific class on to the dynamic-element. (see static elementProperties: PropertyDeclarationMap;) + willUpdate(changedProperties: PropertyValueMap | Map) { + super.willUpdate(changedProperties); - const hasChangedProps = changedProperties.has('value'); - if (hasChangedProps && this._element) { - this._element.value = this.value; // Be aware its duplicated code - } - } + const hasChangedProps = changedProperties.has('value'); + if (hasChangedProps && this._element) { + this._element.value = this.value; // Be aware its duplicated code + } + } - disconnectedCallback(): void { - super.disconnectedCallback(); - this._dataTypeSubscription?.unsubscribe(); - } + disconnectedCallback(): void { + super.disconnectedCallback(); + this._dataTypeSubscription?.unsubscribe(); + } - render() { - return html` - -
- ${this.property.label} -

${this.property.description}

-
-
${this._element}
-
- `; - } + render() { + return html` + +
+ ${this.property.label} +

${this.property.description}

+
+
${this._element}
+
+ `; + } } declare global { - interface HTMLElementTagNameMap { - 'umb-node-property': UmbNodeProperty; - } + interface HTMLElementTagNameMap { + 'umb-node-property': UmbNodeProperty; + } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/components/section-dashboards.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/components/section-dashboards.element.ts index 95c40b3988..16b77f7d52 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/components/section-dashboards.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/components/section-dashboards.element.ts @@ -9,108 +9,108 @@ import { createExtensionElement, UmbExtensionManifestDashboard, UmbExtensionRegi @customElement('umb-section-dashboards') export class UmbSectionDashboards extends UmbContextConsumerMixin(LitElement) { - static styles = [ - UUITextStyles, - css` - :host { - display: block; - width: 100%; - } + static styles = [ + UUITextStyles, + css` + :host { + display: block; + width: 100%; + } - #tabs { - background-color: var(--uui-color-surface); - height: 70px; - } + #tabs { + background-color: var(--uui-color-surface); + height: 70px; + } - #router-slot { - width: 100%; - box-sizing: border-box; - padding: var(--uui-size-space-5); - display: block; - } - `, - ]; + #router-slot { + width: 100%; + box-sizing: border-box; + padding: var(--uui-size-space-5); + display: block; + } + `, + ]; - @state() - private _dashboards: Array = []; + @state() + private _dashboards: Array = []; - @state() - private _current = ''; + @state() + private _current = ''; - @state() - private _routes: Array = []; + @state() + private _routes: Array = []; - private _extensionRegistry?: UmbExtensionRegistry; - private _dashboardsSubscription?: Subscription; + private _extensionRegistry?: UmbExtensionRegistry; + private _dashboardsSubscription?: Subscription; - constructor() { - super(); + constructor() { + super(); - this.consumeContext('umbExtensionRegistry', (_instance: UmbExtensionRegistry) => { - this._extensionRegistry = _instance; - this._useDashboards(); - }); - } + this.consumeContext('umbExtensionRegistry', (_instance: UmbExtensionRegistry) => { + this._extensionRegistry = _instance; + this._useDashboards(); + }); + } - private _useDashboards() { - this._dashboardsSubscription?.unsubscribe(); + private _useDashboards() { + this._dashboardsSubscription?.unsubscribe(); - this._dashboardsSubscription = this._extensionRegistry - ?.extensionsOfType('dashboard') - .pipe(map((extensions) => extensions.sort((a, b) => b.meta.weight - a.meta.weight))) - .subscribe((dashboards) => { - this._dashboards = dashboards; - this._routes = []; + this._dashboardsSubscription = this._extensionRegistry + ?.extensionsOfType('dashboard') + .pipe(map((extensions) => extensions.sort((a, b) => b.meta.weight - a.meta.weight))) + .subscribe((dashboards) => { + this._dashboards = dashboards; + this._routes = []; - this._routes = this._dashboards.map((dashboard) => { - return { - path: `${dashboard.meta.pathname}`, - component: () => createExtensionElement(dashboard), - setup: (_element: UmbExtensionManifestDashboard, info: IRoutingInfo) => { - this._current = info.match.route.path; - }, - }; - }); + this._routes = this._dashboards.map((dashboard) => { + return { + path: `${dashboard.meta.pathname}`, + component: () => createExtensionElement(dashboard), + setup: (_element: UmbExtensionManifestDashboard, info: IRoutingInfo) => { + this._current = info.match.route.path; + }, + }; + }); - this._routes.push({ - path: '**', - redirectTo: this._dashboards[0].meta.pathname, - }); - }); - } + this._routes.push({ + path: '**', + redirectTo: this._dashboards[0].meta.pathname, + }); + }); + } - private _handleTabClick(e: PointerEvent, dashboard: UmbExtensionManifestDashboard) { - // TODO: generate URL from context/location. Or use Router-link concept? - history.pushState(null, '', `/section/content/dashboard/${dashboard.meta.pathname}`); - this._current = dashboard.name; - } + private _handleTabClick(e: PointerEvent, dashboard: UmbExtensionManifestDashboard) { + // TODO: generate URL from context/location. Or use Router-link concept? + history.pushState(null, '', `/section/content/dashboard/${dashboard.meta.pathname}`); + this._current = dashboard.name; + } - disconnectedCallback() { - super.disconnectedCallback(); - this._dashboardsSubscription?.unsubscribe(); - } + disconnectedCallback() { + super.disconnectedCallback(); + this._dashboardsSubscription?.unsubscribe(); + } - render() { - return html` - - ${this._dashboards.map( - (dashboard: UmbExtensionManifestDashboard) => html` - - ` - )} - - - `; - } + render() { + return html` + + ${this._dashboards.map( + (dashboard: UmbExtensionManifestDashboard) => html` + + ` + )} + + + `; + } } export default UmbSectionDashboards; declare global { - interface HTMLElementTagNameMap { - 'umb-section-dashboards': UmbSectionDashboards; - } + interface HTMLElementTagNameMap { + 'umb-section-dashboards': UmbSectionDashboards; + } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/components/section-sidebar.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/components/section-sidebar.element.ts index c93cdb3161..765d568bdf 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/components/section-sidebar.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/components/section-sidebar.element.ts @@ -4,28 +4,28 @@ import { customElement } from 'lit/decorators.js'; @customElement('umb-section-sidebar') export class UmbSectionSidebar extends LitElement { - static styles = [ - UUITextStyles, - css` - :host { - flex: 0 0 300px; - background-color: var(--uui-color-surface); - height: 100%; - border-right: 1px solid var(--uui-color-border); - font-weight: 500; - display: flex; - flex-direction: column; - } - `, - ]; + static styles = [ + UUITextStyles, + css` + :host { + flex: 0 0 300px; + background-color: var(--uui-color-surface); + height: 100%; + border-right: 1px solid var(--uui-color-border); + font-weight: 500; + display: flex; + flex-direction: column; + } + `, + ]; - render() { - return html``; - } + render() { + return html``; + } } declare global { - interface HTMLElementTagNameMap { - 'umb-section-sidebar': UmbSectionSidebar; - } + interface HTMLElementTagNameMap { + 'umb-section-sidebar': UmbSectionSidebar; + } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/dashboard-redirect-management.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/dashboard-redirect-management.element.ts index 61ed9d24e0..ac72f13414 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/dashboard-redirect-management.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/dashboard-redirect-management.element.ts @@ -4,19 +4,19 @@ import { customElement } from 'lit/decorators.js'; @customElement('umb-dashboard-redirect-management') export class UmbDashboardRedirectManagement extends LitElement { - static styles = [UUITextStyles, css``]; + static styles = [UUITextStyles, css``]; - render() { - return html` - -

Redirect Management

-
- `; - } + render() { + return html` + +

Redirect Management

+
+ `; + } } declare global { - interface HTMLElementTagNameMap { - 'umb-dashboard-redirect-management': UmbDashboardRedirectManagement; - } + interface HTMLElementTagNameMap { + 'umb-dashboard-redirect-management': UmbDashboardRedirectManagement; + } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/dashboard-welcome.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/dashboard-welcome.element.ts index e4a513b7c2..377ce3b17a 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/dashboard-welcome.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/dashboards/dashboard-welcome.element.ts @@ -4,20 +4,20 @@ import { customElement } from 'lit/decorators.js'; @customElement('umb-dashboard-welcome') export class UmbDashboardWelcome extends LitElement { - static styles = [UUITextStyles, css``]; + static styles = [UUITextStyles, css``]; - render() { - return html` - -

Welcome

-

You can find details about the POC in the readme.md file.

-
- `; - } + render() { + return html` + +

Welcome

+

You can find details about the POC in the readme.md file.

+
+ `; + } } declare global { - interface HTMLElementTagNameMap { - 'umb-dashboard-welcome': UmbDashboardWelcome; - } + interface HTMLElementTagNameMap { + 'umb-dashboard-welcome': UmbDashboardWelcome; + } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editor-views/editor-view-node-edit.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editor-views/editor-view-node-edit.element.ts index c26e034d3b..aa46a45795 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editor-views/editor-view-node-edit.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editor-views/editor-view-node-edit.element.ts @@ -4,39 +4,39 @@ import { customElement, property } from 'lit/decorators.js'; @customElement('umb-editor-view-node-edit') export class UmbEditorViewNodeEdit extends LitElement { - static styles = [ - UUITextStyles, - css` - hr { - border: 0; - /* TODO: Use correct color property */ - border-top: 1px solid #e7e7e7; - } - `, - ]; + static styles = [ + UUITextStyles, + css` + hr { + border: 0; + /* TODO: Use correct color property */ + border-top: 1px solid #e7e7e7; + } + `, + ]; - @property() - node: any; + @property() + node: any; - render() { - return html` - - - ${this.node?.properties.map( - (property: any) => html` - -
- ` - )} -
- `; - } + render() { + return html` + + + ${this.node?.properties.map( + (property: any) => html` + +
+ ` + )} +
+ `; + } } export default UmbEditorViewNodeEdit; declare global { - interface HTMLElementTagNameMap { - 'umb-editor-view-node-edit': UmbEditorViewNodeEdit; - } + interface HTMLElementTagNameMap { + 'umb-editor-view-node-edit': UmbEditorViewNodeEdit; + } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/editor-views/editor-view-node-info.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/editor-views/editor-view-node-info.element.ts index 9e9aef0797..98d1eb594f 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/editor-views/editor-view-node-info.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/editor-views/editor-view-node-info.element.ts @@ -4,20 +4,20 @@ import { customElement, property } from 'lit/decorators.js'; @customElement('umb-editor-view-node-info') export class UmbEditorViewNodeInfo extends LitElement { - static styles = [UUITextStyles, css``]; + static styles = [UUITextStyles, css``]; - @property() - node: any; + @property() + node: any; - render() { - return html`
Info Editor View
`; - } + render() { + return html`
Info Editor View
`; + } } export default UmbEditorViewNodeInfo; declare global { - interface HTMLElementTagNameMap { - 'umb-editor-view-node-info': UmbEditorViewNodeInfo; - } + interface HTMLElementTagNameMap { + 'umb-editor-view-node-info': UmbEditorViewNodeInfo; + } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/property-editors/property-editor-context-example.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/property-editors/property-editor-context-example.element.ts index fa56b8abdd..7a5689cbd9 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/property-editors/property-editor-context-example.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/property-editors/property-editor-context-example.element.ts @@ -5,26 +5,26 @@ import { UmbNotificationService } from '../../core/services/notification.service @customElement('umb-property-editor-context-example') export default class UmbPropertyEditorContextExample extends UmbContextConsumerMixin(LitElement) { - private _notificationService?: UmbNotificationService; + private _notificationService?: UmbNotificationService; - constructor() { - super(); - // TODO: how to deal with single consumption, or situation where you dont want to store the service.. - this.consumeContext('umbNotificationService', (service: UmbNotificationService) => { - this._notificationService = service; - }); - } - private _onClick = () => { - this._notificationService?.peek('Hello from property editor'); - }; + constructor() { + super(); + // TODO: how to deal with single consumption, or situation where you dont want to store the service.. + this.consumeContext('umbNotificationService', (service: UmbNotificationService) => { + this._notificationService = service; + }); + } + private _onClick = () => { + this._notificationService?.peek('Hello from property editor'); + }; - render() { - return html``; - } + render() { + return html``; + } } declare global { - interface HTMLElementTagNameMap { - 'umb-property-editor-context-example': UmbPropertyEditorContextExample; - } + interface HTMLElementTagNameMap { + 'umb-property-editor-context-example': UmbPropertyEditorContextExample; + } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/property-editors/property-editor-text.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/property-editors/property-editor-text.element.ts index dced3c3927..d2a6949c2a 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/property-editors/property-editor-text.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/property-editors/property-editor-text.element.ts @@ -4,30 +4,30 @@ import { customElement, property } from 'lit/decorators.js'; @customElement('umb-property-editor-text') export default class UmbPropertyEditorText extends LitElement { - static styles = [ - UUITextStyles, - css` - uui-input { - width: 100%; - } - `, - ]; + static styles = [ + UUITextStyles, + css` + uui-input { + width: 100%; + } + `, + ]; - @property() - value = ''; + @property() + value = ''; - private onInput(e: InputEvent) { - this.value = (e.target as HTMLInputElement).value; - this.dispatchEvent(new CustomEvent('property-editor-change', { bubbles: true, composed: true })); - } + private onInput(e: InputEvent) { + this.value = (e.target as HTMLInputElement).value; + this.dispatchEvent(new CustomEvent('property-editor-change', { bubbles: true, composed: true })); + } - render() { - return html``; - } + render() { + return html``; + } } declare global { - interface HTMLElementTagNameMap { - 'umb-property-editor-text': UmbPropertyEditorText; - } + interface HTMLElementTagNameMap { + 'umb-property-editor-text': UmbPropertyEditorText; + } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/property-editors/property-editor-textarea.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/property-editors/property-editor-textarea.element.ts index 90e5ba71da..f6b1c41014 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/property-editors/property-editor-textarea.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/property-editors/property-editor-textarea.element.ts @@ -4,30 +4,30 @@ import { customElement, property } from 'lit/decorators.js'; @customElement('umb-property-editor-textarea') class UmbPropertyEditorTextarea extends LitElement { - static styles = [ - UUITextStyles, - css` - uui-textarea { - width: 100%; - } - `, - ]; + static styles = [ + UUITextStyles, + css` + uui-textarea { + width: 100%; + } + `, + ]; - @property() - value = ''; + @property() + value = ''; - private onInput(e: InputEvent) { - this.value = (e.target as HTMLInputElement).value; - this.dispatchEvent(new CustomEvent('property-editor-change', { bubbles: true, composed: true })); - } + private onInput(e: InputEvent) { + this.value = (e.target as HTMLInputElement).value; + this.dispatchEvent(new CustomEvent('property-editor-change', { bubbles: true, composed: true })); + } - render() { - return html``; - } + render() { + return html``; + } } declare global { - interface HTMLElementTagNameMap { - 'umb-property-editor-textarea': UmbPropertyEditorTextarea; - } + interface HTMLElementTagNameMap { + 'umb-property-editor-textarea': UmbPropertyEditorTextarea; + } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/content/content-section-tree.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/content/content-section-tree.element.ts index a484ce8732..9c9a367d42 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/content/content-section-tree.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/content/content-section-tree.element.ts @@ -5,49 +5,49 @@ import { data } from '../../../mocks/data/content.data'; @customElement('umb-content-section-tree') class UmbContentSectionTree extends LitElement { - static styles = [ - UUITextStyles, - css` - h3 { - padding: var(--uui-size-4) var(--uui-size-8); - } - `, - ]; + static styles = [ + UUITextStyles, + css` + h3 { + padding: var(--uui-size-4) var(--uui-size-8); + } + `, + ]; - @property() - public currentNodeId?: string; + @property() + public currentNodeId?: string; - // simplified tree data for testing - @state() - _tree: Array = data; + // simplified tree data for testing + @state() + _tree: Array = data; - @state() - _section?: string; + @state() + _section?: string; - render() { - return html` - -

Content

-
+ render() { + return html` + +

Content

+
- - `; - } + + `; + } } declare global { - interface HTMLElementTagNameMap { - 'umb-content-section-tree': UmbContentSectionTree; - } + interface HTMLElementTagNameMap { + 'umb-content-section-tree': UmbContentSectionTree; + } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/content/content-section.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/content/content-section.element.ts index 9797b9e3a0..b1dad45aec 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/content/content-section.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/content/content-section.element.ts @@ -7,56 +7,56 @@ import './content-section-tree.element'; @customElement('umb-content-section') export class UmbContentSection extends LitElement { - static styles = [ - UUITextStyles, - css` - :host, - #router-slot { - display: flex; - width: 100%; - height: 100%; - } - `, - ]; + static styles = [ + UUITextStyles, + css` + :host, + #router-slot { + display: flex; + width: 100%; + height: 100%; + } + `, + ]; - @state() - private _routes: Array = [ - { - path: 'dashboard', - component: () => import('../../components/section-dashboards.element'), - setup: () => { - this._currentNodeId = undefined; - }, - }, - { - path: 'node/:nodeId', - component: () => import('../../components/node-editor.element'), - setup: (component: HTMLElement, info: IRoutingInfo) => { - this._currentNodeId = info.match.params.nodeId; - component.id = this._currentNodeId; - }, - }, - { - path: '**', - redirectTo: 'dashboard', - }, - ]; + @state() + private _routes: Array = [ + { + path: 'dashboard', + component: () => import('../../components/section-dashboards.element'), + setup: () => { + this._currentNodeId = undefined; + }, + }, + { + path: 'node/:nodeId', + component: () => import('../../components/node-editor.element'), + setup: (component: HTMLElement, info: IRoutingInfo) => { + this._currentNodeId = info.match.params.nodeId; + component.id = this._currentNodeId; + }, + }, + { + path: '**', + redirectTo: 'dashboard', + }, + ]; - @state() - private _currentNodeId?: string; + @state() + private _currentNodeId?: string; - render() { - return html` - - - - - `; - } + render() { + return html` + + + + + `; + } } declare global { - interface HTMLElementTagNameMap { - 'umb-content-section': UmbContentSection; - } + interface HTMLElementTagNameMap { + 'umb-content-section': UmbContentSection; + } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/sections/settings/settings-section.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/sections/settings/settings-section.element.ts index 72720dcd15..92d95baf90 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/sections/settings/settings-section.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/sections/settings/settings-section.element.ts @@ -7,75 +7,75 @@ import { UmbExtensionManifest, UmbExtensionRegistry } from '../../../core/extens @customElement('umb-settings-section') export class UmbSettingsSection extends UmbContextConsumerMixin(LitElement) { - static styles = [ - UUITextStyles, - css` - :host { - display: block; - padding: var(--uui-size-space-5); - } - `, - ]; + static styles = [ + UUITextStyles, + css` + :host { + display: block; + padding: var(--uui-size-space-5); + } + `, + ]; - @state() - private _extensions: Array = []; + @state() + private _extensions: Array = []; - private _extensionRegistry?: UmbExtensionRegistry; - private _extensionsSubscription?: Subscription; + private _extensionRegistry?: UmbExtensionRegistry; + private _extensionsSubscription?: Subscription; - constructor() { - super(); + constructor() { + super(); - this.consumeContext('umbExtensionRegistry', (_instance: UmbExtensionRegistry) => { - this._extensionRegistry = _instance; + this.consumeContext('umbExtensionRegistry', (_instance: UmbExtensionRegistry) => { + this._extensionRegistry = _instance; - this._extensionsSubscription?.unsubscribe(); + this._extensionsSubscription?.unsubscribe(); - // TODO: Niels: Could we make it easier to unsubscribe? If we invented a Pattern/Mixin/class ala Lit-Controllers we could make it auto unsubscribe. - // ContextConsumers could be turned into single classes which uses the 'Controller' ability to hook into connected and disconnected. - // Generally that means that a web component must have the ControllerMixin?? and then controllers can easily be attached, they would know about life cycle and thereby be able to unsubscribe on disconnected etc. - // - // All code regarding subscription could be boiled down to: - // OurUmbracoSubscribeMethod(this, this._extensionRegistry.extensions, (extensions) => {}); // uses `this` to append the subscription to the controller array. - // Or: - // this.attachSubscription(this._extensionRegistry.extensions, (extensions) => {}); - this._extensionsSubscription = this._extensionRegistry.extensions.subscribe((extensions) => { - this._extensions = [...extensions]; // TODO: Though, this is a shallow clone, wouldn't we either do a deep clone or no clone at all? - }); + // TODO: Niels: Could we make it easier to unsubscribe? If we invented a Pattern/Mixin/class ala Lit-Controllers we could make it auto unsubscribe. + // ContextConsumers could be turned into single classes which uses the 'Controller' ability to hook into connected and disconnected. + // Generally that means that a web component must have the ControllerMixin?? and then controllers can easily be attached, they would know about life cycle and thereby be able to unsubscribe on disconnected etc. + // + // All code regarding subscription could be boiled down to: + // OurUmbracoSubscribeMethod(this, this._extensionRegistry.extensions, (extensions) => {}); // uses `this` to append the subscription to the controller array. + // Or: + // this.attachSubscription(this._extensionRegistry.extensions, (extensions) => {}); + this._extensionsSubscription = this._extensionRegistry.extensions.subscribe((extensions) => { + this._extensions = [...extensions]; // TODO: Though, this is a shallow clone, wouldn't we either do a deep clone or no clone at all? + }); - this._extensionsSubscription = this._extensionRegistry.extensionsOfType('section').subscribe((sections) => { - // In this callback sections are typed. Example meta.weight... - console.log(sections[0].meta.weight); - }); - }); - } + this._extensionsSubscription = this._extensionRegistry.extensionsOfType('section').subscribe((sections) => { + // In this callback sections are typed. Example meta.weight... + console.log(sections[0].meta.weight); + }); + }); + } - disconnectedCallback(): void { - super.disconnectedCallback(); - this._extensionsSubscription?.unsubscribe(); - } + disconnectedCallback(): void { + super.disconnectedCallback(); + this._extensionsSubscription?.unsubscribe(); + } - render() { - return html` - - - - Type - Name - Alias - + render() { + return html` + + + + Type + Name + Alias + - ${this._extensions.map( - (extension) => html` - - ${extension.type} - ${extension.name} - ${extension.alias} - - ` - )} - - - `; - } + ${this._extensions.map( + (extension) => html` + + ${extension.type} + ${extension.name} + ${extension.alias} + + ` + )} + + + `; + } } 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 02aff8e69d..aa2e94e4a6 100644 --- a/src/Umbraco.Web.UI.Client/src/core/api/fetcher.ts +++ b/src/Umbraco.Web.UI.Client/src/core/api/fetcher.ts @@ -5,7 +5,7 @@ import { paths } from '../../../schemas/generated-schema'; const fetcher = Fetcher.for(); fetcher.configure({ - baseUrl: '/umbraco/backoffice', + baseUrl: '/umbraco/backoffice', }); export const getServerStatus = fetcher.path('/server/status').method('get').create(); 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 8413baa8dd..4162344031 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 @@ -2,8 +2,8 @@ import { HTMLElementConstructor } from '../models'; import { UmbContextConsumer } from './context-consumer'; export declare class UmbContextConsumerInterface { - consumeContext(alias: string, callback?: (_instance: any) => void): void; - whenAvailableOrChanged(contextAliases: string[], callback?: () => void): void; + consumeContext(alias: string, callback?: (_instance: any) => void): void; + whenAvailableOrChanged(contextAliases: string[], callback?: () => void): void; } /** @@ -14,72 +14,72 @@ export declare class UmbContextConsumerInterface { * @mixin */ export const UmbContextConsumerMixin = (superClass: T) => { - class UmbContextConsumerClass extends superClass { - // all context requesters in the element - _consumers: Map = new Map(); - // all successfully resolved context requests - _resolved: Map = new Map(); + class UmbContextConsumerClass extends superClass { + // all context requesters in the element + _consumers: Map = new Map(); + // all successfully resolved context requests + _resolved: Map = new Map(); - _attached = false; + _attached = false; - /** - * Setup a subscription for a request on a given context of this component. - * @param {string} alias - * @param {method} callback optional callback method called when context is received or when context is detached. - */ - consumeContext(alias: string, callback?: (_instance: unknown) => void): void { - if (this._consumers.has(alias)) return; + /** + * Setup a subscription for a request on a given context of this component. + * @param {string} alias + * @param {method} callback optional callback method called when context is received or when context is detached. + */ + consumeContext(alias: string, callback?: (_instance: unknown) => void): void { + if (this._consumers.has(alias)) return; - const consumer = new UmbContextConsumer(this, alias, (_instance: any) => { - // Do we still have this consumer? + const consumer = new UmbContextConsumer(this, alias, (_instance: any) => { + // Do we still have this consumer? - callback?.(_instance); + callback?.(_instance); - // don't to anything if the context is already resolved - if (this._resolved.has(alias) && this._resolved.get(alias) === _instance) return; + // don't to anything if the context is already resolved + if (this._resolved.has(alias) && this._resolved.get(alias) === _instance) return; - this._resolved.set(alias, _instance); - this._consumeContextCallback(alias, _instance); - }); + this._resolved.set(alias, _instance); + this._consumeContextCallback(alias, _instance); + }); - this._consumers.set(alias, consumer); + this._consumers.set(alias, consumer); - if (this._attached) { - consumer.attach(); - } - } + if (this._attached) { + consumer.attach(); + } + } - // TODO: remove requester.. + // TODO: remove requester.. - connectedCallback() { - super.connectedCallback?.(); - this._attached = true; - this._consumers.forEach((requester) => requester.attach()); - } + connectedCallback() { + super.connectedCallback?.(); + this._attached = true; + this._consumers.forEach((requester) => requester.attach()); + } - disconnectedCallback() { - super.disconnectedCallback?.(); - this._attached = false; - this._consumers.forEach((requester) => requester.detach()); - this._resolved.clear(); - } + disconnectedCallback() { + super.disconnectedCallback?.(); + this._attached = false; + this._consumers.forEach((requester) => requester.detach()); + this._resolved.clear(); + } - _consumeContextCallback(_newAlias: string, _newInstance: unknown) { - // TODO: do be done. - } + _consumeContextCallback(_newAlias: string, _newInstance: unknown) { + // TODO: do be done. + } - // might return a object, so you can unsubscribe. - whenAvailableOrChanged(_contextAliases: string[]) { - // TODO: To be done. - } - } + // might return a object, so you can unsubscribe. + whenAvailableOrChanged(_contextAliases: string[]) { + // TODO: To be done. + } + } - return UmbContextConsumerClass as unknown as HTMLElementConstructor & T; + return UmbContextConsumerClass as unknown as HTMLElementConstructor & T; }; declare global { - interface HTMLElement { - connectedCallback(): void; - disconnectedCallback(): void; - } + interface HTMLElement { + connectedCallback(): void; + disconnectedCallback(): void; + } } diff --git a/src/Umbraco.Web.UI.Client/src/core/context/context-consumer.test.ts b/src/Umbraco.Web.UI.Client/src/core/context/context-consumer.test.ts index 83da94fd38..088216c902 100644 --- a/src/Umbraco.Web.UI.Client/src/core/context/context-consumer.test.ts +++ b/src/Umbraco.Web.UI.Client/src/core/context/context-consumer.test.ts @@ -7,51 +7,51 @@ import { UmbContextRequestEventImplementation, umbContextRequestEventType } from const testContextAlias = 'my-test-context'; class MyClass { - prop = 'value from provider'; + prop = 'value from provider'; } describe('UmbContextConsumer', () => { - let consumer: UmbContextConsumer; + let consumer: UmbContextConsumer; - beforeEach(() => { - // eslint-disable-next-line @typescript-eslint/no-empty-function - consumer = new UmbContextConsumer(document.body, testContextAlias, () => {}); - }); + beforeEach(() => { + // eslint-disable-next-line @typescript-eslint/no-empty-function + consumer = new UmbContextConsumer(document.body, testContextAlias, () => {}); + }); - describe('Public API', () => { - describe('methods', () => { - it('has a request method', () => { - expect(consumer).to.have.property('request').that.is.a('function'); - }); - }); + describe('Public API', () => { + describe('methods', () => { + it('has a request method', () => { + expect(consumer).to.have.property('request').that.is.a('function'); + }); + }); - describe('events', () => { - it('dispatches context request event when constructed', async () => { - const listener = oneEvent(window, umbContextRequestEventType); + describe('events', () => { + it('dispatches context request event when constructed', async () => { + const listener = oneEvent(window, umbContextRequestEventType); - consumer.attach(); + consumer.attach(); - const event = (await listener) as unknown as UmbContextRequestEventImplementation; - expect(event).to.exist; - expect(event.type).to.eq(umbContextRequestEventType); - expect(event.contextAlias).to.eq(testContextAlias); - }); - }); - }); + const event = (await listener) as unknown as UmbContextRequestEventImplementation; + expect(event).to.exist; + expect(event.type).to.eq(umbContextRequestEventType); + expect(event.contextAlias).to.eq(testContextAlias); + }); + }); + }); - it('works with UmbContextProvider', (done) => { - const provider = new UmbContextProvider(document.body, testContextAlias, new MyClass()); - provider.attach(); + it('works with UmbContextProvider', (done) => { + const provider = new UmbContextProvider(document.body, testContextAlias, new MyClass()); + provider.attach(); - const element = document.createElement('div'); - document.body.appendChild(element); + const element = document.createElement('div'); + document.body.appendChild(element); - const localConsumer = new UmbContextConsumer(element, testContextAlias, (_instance) => { - expect(_instance.prop).to.eq('value from provider'); - done(); - }); - localConsumer.attach(); + const localConsumer = new UmbContextConsumer(element, testContextAlias, (_instance) => { + expect(_instance.prop).to.eq('value from provider'); + done(); + }); + localConsumer.attach(); - provider.detach(); - }); + provider.detach(); + }); }); diff --git a/src/Umbraco.Web.UI.Client/src/core/context/context-consumer.ts b/src/Umbraco.Web.UI.Client/src/core/context/context-consumer.ts index ce62ced30d..205bd69630 100644 --- a/src/Umbraco.Web.UI.Client/src/core/context/context-consumer.ts +++ b/src/Umbraco.Web.UI.Client/src/core/context/context-consumer.ts @@ -6,37 +6,37 @@ import { isUmbContextProvideEvent, umbContextProvideEventType } from './context- * @class UmbContextConsumer */ export class UmbContextConsumer { - /** - * Creates an instance of UmbContextConsumer. - * @param {EventTarget} target - * @param {string} _contextAlias - * @param {UmbContextCallback} _callback - * @memberof UmbContextConsumer - */ - constructor(protected target: EventTarget, private _contextAlias: string, private _callback: UmbContextCallback) {} + /** + * Creates an instance of UmbContextConsumer. + * @param {EventTarget} target + * @param {string} _contextAlias + * @param {UmbContextCallback} _callback + * @memberof UmbContextConsumer + */ + constructor(protected target: EventTarget, private _contextAlias: string, private _callback: UmbContextCallback) {} - /** - * @memberof UmbContextConsumer - */ - public request() { - const event = new UmbContextRequestEventImplementation(this._contextAlias, this._callback); - this.target.dispatchEvent(event); - } + /** + * @memberof UmbContextConsumer + */ + public request() { + const event = new UmbContextRequestEventImplementation(this._contextAlias, this._callback); + this.target.dispatchEvent(event); + } - public attach() { - window.addEventListener(umbContextProvideEventType, this._handleNewProvider); - this.request(); - } + public attach() { + window.addEventListener(umbContextProvideEventType, this._handleNewProvider); + this.request(); + } - public detach() { - window.removeEventListener(umbContextProvideEventType, this._handleNewProvider); - } + public detach() { + window.removeEventListener(umbContextProvideEventType, this._handleNewProvider); + } - private _handleNewProvider = (event: Event) => { - if (!isUmbContextProvideEvent(event)) return; + private _handleNewProvider = (event: Event) => { + if (!isUmbContextProvideEvent(event)) return; - if (this._contextAlias === event.contextAlias) { - this.request(); - } - }; + if (this._contextAlias === event.contextAlias) { + this.request(); + } + }; } diff --git a/src/Umbraco.Web.UI.Client/src/core/context/context-provide.event.test.ts b/src/Umbraco.Web.UI.Client/src/core/context/context-provide.event.test.ts index 52b5af7a31..0c7c158123 100644 --- a/src/Umbraco.Web.UI.Client/src/core/context/context-provide.event.test.ts +++ b/src/Umbraco.Web.UI.Client/src/core/context/context-provide.event.test.ts @@ -2,21 +2,21 @@ import { expect } from '@open-wc/testing'; import { UmbContextProvideEventImplementation, UmbContextProvideEvent } from './context-provide.event'; describe('UmbContextProvideEvent', () => { - const event: UmbContextProvideEvent = new UmbContextProvideEventImplementation('my-test-context-alias'); + const event: UmbContextProvideEvent = new UmbContextProvideEventImplementation('my-test-context-alias'); - it('has context', () => { - expect(event.contextAlias).to.eq('my-test-context-alias'); - }); + it('has context', () => { + expect(event.contextAlias).to.eq('my-test-context-alias'); + }); - it('bubbles', () => { - expect(event.bubbles).to.be.true; - }); + it('bubbles', () => { + expect(event.bubbles).to.be.true; + }); - it('is composed', () => { - expect(event.composed).to.be.true; - }); + it('is composed', () => { + expect(event.composed).to.be.true; + }); - it('is not cancelable', () => { - expect(event.cancelable).to.be.false; - }); + it('is not cancelable', () => { + expect(event.cancelable).to.be.false; + }); }); diff --git a/src/Umbraco.Web.UI.Client/src/core/context/context-provide.event.ts b/src/Umbraco.Web.UI.Client/src/core/context/context-provide.event.ts index 00d1890c93..7478d4f7d0 100644 --- a/src/Umbraco.Web.UI.Client/src/core/context/context-provide.event.ts +++ b/src/Umbraco.Web.UI.Client/src/core/context/context-provide.event.ts @@ -5,7 +5,7 @@ export const umbContextProvideEventType = 'umb:context-provide'; * @interface UmbContextProvideEvent */ export interface UmbContextProvideEvent extends Event { - readonly contextAlias: string; + readonly contextAlias: string; } /** @@ -15,11 +15,11 @@ export interface UmbContextProvideEvent extends Event { * @implements {UmbContextProvideEvent} */ export class UmbContextProvideEventImplementation extends Event implements UmbContextProvideEvent { - public constructor(public readonly contextAlias: string) { - super(umbContextProvideEventType, { bubbles: true, composed: true }); - } + public constructor(public readonly contextAlias: string) { + super(umbContextProvideEventType, { bubbles: true, composed: true }); + } } export const isUmbContextProvideEvent = (event: Event): event is UmbContextProvideEventImplementation => { - return event.type === umbContextProvideEventType; + return event.type === umbContextProvideEventType; }; diff --git a/src/Umbraco.Web.UI.Client/src/core/context/context-provider.mixin.test.ts b/src/Umbraco.Web.UI.Client/src/core/context/context-provider.mixin.test.ts index 9d283d2b6d..c68277e517 100644 --- a/src/Umbraco.Web.UI.Client/src/core/context/context-provider.mixin.test.ts +++ b/src/Umbraco.Web.UI.Client/src/core/context/context-provider.mixin.test.ts @@ -3,43 +3,43 @@ import { UmbContextProvider } from './context-provider'; import { UmbContextProviderMixin } from './context-provider.mixin'; class MyClass { - prop: string; + prop: string; - constructor(text: string) { - this.prop = text; - } + constructor(text: string) { + this.prop = text; + } } class MyTestProviderElement extends UmbContextProviderMixin(HTMLElement) { - constructor() { - super(); - this.provideContext('my-test-context-1', new MyClass('context value 1')); - this.provideContext('my-test-context-2', new MyClass('context value 2')); - } + constructor() { + super(); + this.provideContext('my-test-context-1', new MyClass('context value 1')); + this.provideContext('my-test-context-2', new MyClass('context value 2')); + } } customElements.define('my-test-provider-element', MyTestProviderElement); describe('UmbContextProviderMixin', async () => { - let element: MyTestProviderElement; - let _providers: Map; + let element: MyTestProviderElement; + let _providers: Map; - beforeEach(async () => { - element = await fixture(html``); - _providers = (element as any)['_providers']; - }); + beforeEach(async () => { + element = await fixture(html``); + _providers = (element as any)['_providers']; + }); - it('sets all providers to element', () => { - expect(_providers.has('my-test-context-1')).to.be.true; - expect(_providers.has('my-test-context-2')).to.be.true; - }); + it('sets all providers to element', () => { + expect(_providers.has('my-test-context-1')).to.be.true; + expect(_providers.has('my-test-context-2')).to.be.true; + }); - it('can not set context with same key as already existing context', () => { - const provider = _providers.get('my-test-context-1'); - expect(provider).to.not.be.undefined; - if (!provider) return; - expect((provider['_instance'] as MyClass).prop).to.eq('context value 1'); - element.provideContext('my-test-context-1', new MyClass('new context value 1')); - expect((provider['_instance'] as MyClass).prop).to.eq('context value 1'); - }); + it('can not set context with same key as already existing context', () => { + const provider = _providers.get('my-test-context-1'); + expect(provider).to.not.be.undefined; + if (!provider) return; + expect((provider['_instance'] as MyClass).prop).to.eq('context value 1'); + element.provideContext('my-test-context-1', new MyClass('new context value 1')); + expect((provider['_instance'] as MyClass).prop).to.eq('context value 1'); + }); }); 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 d793fde40e..26a4c95e66 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 @@ -2,48 +2,48 @@ import { HTMLElementConstructor } from '../models'; import { UmbContextProvider } from './context-provider'; export declare class UmbContextProviderMixinInterface { - provideContext(alias: string, instance: unknown): void; + provideContext(alias: string, instance: unknown): void; } export const UmbContextProviderMixin = (superClass: T) => { - class UmbContextProviderClass extends superClass { - _providers: Map = new Map(); + class UmbContextProviderClass extends superClass { + _providers: Map = new Map(); - _attached = false; + _attached = false; - provideContext(alias: string, instance: unknown) { - // TODO: Consider if key matches wether we should replace and re-publish the context? - if (this._providers.has(alias)) return; + provideContext(alias: string, instance: unknown) { + // TODO: Consider if key matches wether we should replace and re-publish the context? + if (this._providers.has(alias)) return; - const provider = new UmbContextProvider(this, alias, instance); - this._providers.set(alias, provider); - // TODO: if already connected then attach the new one. - if (this._attached) { - provider.attach(); - } - } + const provider = new UmbContextProvider(this, alias, instance); + this._providers.set(alias, provider); + // TODO: if already connected then attach the new one. + if (this._attached) { + provider.attach(); + } + } - // TODO: unprovide method to enforce a detach? + // TODO: unprovide method to enforce a detach? - connectedCallback() { - super.connectedCallback?.(); - this._attached = true; - this._providers.forEach((provider) => provider.attach()); - } + connectedCallback() { + super.connectedCallback?.(); + this._attached = true; + this._providers.forEach((provider) => provider.attach()); + } - disconnectedCallback() { - super.disconnectedCallback?.(); - this._attached = false; - this._providers.forEach((provider) => provider.detach()); - } - } + disconnectedCallback() { + super.disconnectedCallback?.(); + this._attached = false; + this._providers.forEach((provider) => provider.detach()); + } + } - return UmbContextProviderClass as unknown as HTMLElementConstructor & T; + return UmbContextProviderClass as unknown as HTMLElementConstructor & T; }; declare global { - interface HTMLElement { - connectedCallback(): void; - disconnectedCallback(): void; - } + interface HTMLElement { + connectedCallback(): void; + disconnectedCallback(): void; + } } diff --git a/src/Umbraco.Web.UI.Client/src/core/context/context-provider.test.ts b/src/Umbraco.Web.UI.Client/src/core/context/context-provider.test.ts index d2cf5ecc0f..d3126242f5 100644 --- a/src/Umbraco.Web.UI.Client/src/core/context/context-provider.test.ts +++ b/src/Umbraco.Web.UI.Client/src/core/context/context-provider.test.ts @@ -4,57 +4,57 @@ import { UmbContextConsumer } from './context-consumer'; import { UmbContextRequestEventImplementation } from './context-request.event'; class MyClass { - prop = 'value from provider'; + prop = 'value from provider'; } describe('UmbContextProvider', () => { - let provider: UmbContextProvider; + let provider: UmbContextProvider; - beforeEach(() => { - provider = new UmbContextProvider(document.body, 'my-test-context', new MyClass()); - provider.attach(); - }); + beforeEach(() => { + provider = new UmbContextProvider(document.body, 'my-test-context', new MyClass()); + provider.attach(); + }); - afterEach(async () => { - provider.detach(); - }); + afterEach(async () => { + provider.detach(); + }); - describe('Public API', () => { - describe('properties', () => { - it('has a host property', () => { - expect(provider).to.have.property('host'); - }); - }); + describe('Public API', () => { + describe('properties', () => { + it('has a host property', () => { + expect(provider).to.have.property('host'); + }); + }); - describe('methods', () => { - it('has an attach method', () => { - expect(provider).to.have.property('attach').that.is.a('function'); - }); + describe('methods', () => { + it('has an attach method', () => { + expect(provider).to.have.property('attach').that.is.a('function'); + }); - it('has a detach method', () => { - expect(provider).to.have.property('detach').that.is.a('function'); - }); - }); - }); + it('has a detach method', () => { + expect(provider).to.have.property('detach').that.is.a('function'); + }); + }); + }); - it('handles context request events', (done) => { - const event = new UmbContextRequestEventImplementation('my-test-context', (_instance: MyClass) => { - expect(_instance.prop).to.eq('value from provider'); - done(); - }); + it('handles context request events', (done) => { + const event = new UmbContextRequestEventImplementation('my-test-context', (_instance: MyClass) => { + expect(_instance.prop).to.eq('value from provider'); + done(); + }); - document.body.dispatchEvent(event); - }); + document.body.dispatchEvent(event); + }); - it('works with UmbContextConsumer', (done) => { - const element = document.createElement('div'); - document.body.appendChild(element); + it('works with UmbContextConsumer', (done) => { + const element = document.createElement('div'); + document.body.appendChild(element); - const localConsumer = new UmbContextConsumer(element, 'my-test-context', (_instance: MyClass) => { - expect(_instance.prop).to.eq('value from provider'); - done(); - localConsumer.detach(); - }); - localConsumer.attach(); - }); + const localConsumer = new UmbContextConsumer(element, 'my-test-context', (_instance: MyClass) => { + expect(_instance.prop).to.eq('value from provider'); + done(); + localConsumer.detach(); + }); + localConsumer.attach(); + }); }); diff --git a/src/Umbraco.Web.UI.Client/src/core/context/context-provider.ts b/src/Umbraco.Web.UI.Client/src/core/context/context-provider.ts index c0b8815398..5c9c56c447 100644 --- a/src/Umbraco.Web.UI.Client/src/core/context/context-provider.ts +++ b/src/Umbraco.Web.UI.Client/src/core/context/context-provider.ts @@ -6,49 +6,49 @@ import { UmbContextProvideEventImplementation } from './context-provide.event'; * @class UmbContextProvider */ export class UmbContextProvider { - protected host: EventTarget; - private _contextAlias: string; - private _instance: unknown; + protected host: EventTarget; + private _contextAlias: string; + private _instance: unknown; - /** - * Creates an instance of UmbContextProvider. - * @param {EventTarget} host - * @param {string} contextAlias - * @param {*} instance - * @memberof UmbContextProvider - */ - constructor(host: EventTarget, contextAlias: string, instance: unknown) { - this.host = host; - this._contextAlias = contextAlias; - this._instance = instance; - } + /** + * Creates an instance of UmbContextProvider. + * @param {EventTarget} host + * @param {string} contextAlias + * @param {*} instance + * @memberof UmbContextProvider + */ + constructor(host: EventTarget, contextAlias: string, instance: unknown) { + this.host = host; + this._contextAlias = contextAlias; + this._instance = instance; + } - /** - * @memberof UmbContextProvider - */ - public attach() { - this.host.addEventListener(umbContextRequestEventType, this._handleContextRequest); - this.host.dispatchEvent(new UmbContextProvideEventImplementation(this._contextAlias)); - } + /** + * @memberof UmbContextProvider + */ + public attach() { + this.host.addEventListener(umbContextRequestEventType, this._handleContextRequest); + this.host.dispatchEvent(new UmbContextProvideEventImplementation(this._contextAlias)); + } - /** - * @memberof UmbContextProvider - */ - public detach() { - this.host.removeEventListener(umbContextRequestEventType, this._handleContextRequest); - // TODO: fire unprovided event. - } + /** + * @memberof UmbContextProvider + */ + public detach() { + this.host.removeEventListener(umbContextRequestEventType, this._handleContextRequest); + // TODO: fire unprovided event. + } - /** - * @private - * @param {UmbContextRequestEvent} event - * @memberof UmbContextProvider - */ - private _handleContextRequest = (event: Event) => { - if (!isUmbContextRequestEvent(event)) return; - if (event.contextAlias !== this._contextAlias) return; + /** + * @private + * @param {UmbContextRequestEvent} event + * @memberof UmbContextProvider + */ + private _handleContextRequest = (event: Event) => { + if (!isUmbContextRequestEvent(event)) return; + if (event.contextAlias !== this._contextAlias) return; - event.stopPropagation(); - event.callback(this._instance); - }; + event.stopPropagation(); + event.callback(this._instance); + }; } diff --git a/src/Umbraco.Web.UI.Client/src/core/context/context-request.event.test.ts b/src/Umbraco.Web.UI.Client/src/core/context/context-request.event.test.ts index b20f0b5323..33859c6acd 100644 --- a/src/Umbraco.Web.UI.Client/src/core/context/context-request.event.test.ts +++ b/src/Umbraco.Web.UI.Client/src/core/context/context-request.event.test.ts @@ -2,32 +2,32 @@ import { expect } from '@open-wc/testing'; import { UmbContextRequestEventImplementation, UmbContextRequestEvent } from './context-request.event'; describe('UmbContextRequestEvent', () => { - const contextRequestCallback = () => { - console.log('hello from callback'); - }; + const contextRequestCallback = () => { + console.log('hello from callback'); + }; - const event: UmbContextRequestEvent = new UmbContextRequestEventImplementation( - 'my-test-context-alias', - contextRequestCallback - ); + const event: UmbContextRequestEvent = new UmbContextRequestEventImplementation( + 'my-test-context-alias', + contextRequestCallback + ); - it('has context', () => { - expect(event.contextAlias).to.eq('my-test-context-alias'); - }); + it('has context', () => { + expect(event.contextAlias).to.eq('my-test-context-alias'); + }); - it('has a callback', () => { - expect(event.callback).to.eq(contextRequestCallback); - }); + it('has a callback', () => { + expect(event.callback).to.eq(contextRequestCallback); + }); - it('bubbles', () => { - expect(event.bubbles).to.be.true; - }); + it('bubbles', () => { + expect(event.bubbles).to.be.true; + }); - it('is composed', () => { - expect(event.composed).to.be.true; - }); + it('is composed', () => { + expect(event.composed).to.be.true; + }); - it('is cancelable', () => { - expect(event.cancelable).to.be.true; - }); + it('is cancelable', () => { + expect(event.cancelable).to.be.true; + }); }); diff --git a/src/Umbraco.Web.UI.Client/src/core/context/context-request.event.ts b/src/Umbraco.Web.UI.Client/src/core/context/context-request.event.ts index ed3fdae08a..ad1baad5c2 100644 --- a/src/Umbraco.Web.UI.Client/src/core/context/context-request.event.ts +++ b/src/Umbraco.Web.UI.Client/src/core/context/context-request.event.ts @@ -7,8 +7,8 @@ export type UmbContextCallback = (instance: any) => void; * @interface UmbContextRequestEvent */ export interface UmbContextRequestEvent extends Event { - readonly contextAlias: string; - readonly callback: UmbContextCallback; + readonly contextAlias: string; + readonly callback: UmbContextCallback; } /** @@ -18,11 +18,11 @@ export interface UmbContextRequestEvent extends Event { * @implements {UmbContextRequestEvent} */ export class UmbContextRequestEventImplementation extends Event implements UmbContextRequestEvent { - public constructor(public readonly contextAlias: string, public readonly callback: UmbContextCallback) { - super(umbContextRequestEventType, { bubbles: true, composed: true, cancelable: true }); - } + public constructor(public readonly contextAlias: string, public readonly callback: UmbContextCallback) { + super(umbContextRequestEventType, { bubbles: true, composed: true, cancelable: true }); + } } export const isUmbContextRequestEvent = (event: Event): event is UmbContextRequestEventImplementation => { - return event.type === umbContextRequestEventType; + return event.type === umbContextRequestEventType; }; 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 adfb4a4e3a..4b2f261060 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 @@ -4,26 +4,26 @@ import { isExtensionType } from './is-extension.function'; import { loadExtension } from './load-extension.function'; export async function createExtensionElement(manifest: UmbExtensionManifest): Promise { - //TODO: Write tests for these extension options: - const js = await loadExtension(manifest); - if (manifest.elementName) { - // created by manifest method providing HTMLElement - return document.createElement(manifest.elementName); - } - if (js) { - if (js instanceof HTMLElement) { - console.log('-- created by manifest method providing HTMLElement', js); - return js; - } - if (isExtensionType(js)) { - // created by js export elementName - return js.elementName ? document.createElement(js.elementName) : Promise.resolve(undefined); - } - if (hasDefaultExport(js)) { - // created by default class - return new js.default(); - } - } - console.error('-- Extension did not succeed creating an element'); - return Promise.resolve(undefined); + //TODO: Write tests for these extension options: + const js = await loadExtension(manifest); + if (manifest.elementName) { + // created by manifest method providing HTMLElement + return document.createElement(manifest.elementName); + } + if (js) { + if (js instanceof HTMLElement) { + console.log('-- created by manifest method providing HTMLElement', js); + return js; + } + if (isExtensionType(js)) { + // created by js export elementName + return js.elementName ? document.createElement(js.elementName) : Promise.resolve(undefined); + } + if (hasDefaultExport(js)) { + // created by default class + return new js.default(); + } + } + console.error('-- Extension did not succeed creating an element'); + return Promise.resolve(undefined); } 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 afafe61568..1e321c1829 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 @@ -4,76 +4,76 @@ import { BehaviorSubject, map, Observable } from 'rxjs'; export type UmbExtensionType = 'startUp' | 'section' | 'propertyEditorUI' | 'dashboard'; export type UmbExtensionManifestJSModel = { - elementName?: string; + elementName?: string; }; export type UmbExtensionManifestBase = { - //type: string; - alias: string; - name: string; - js?: string | (() => Promise); - elementName?: string; - //meta: undefined; + //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; + pathname: string; // TODO: how to we want to support pretty urls? + weight: number; }; export type UmbExtensionManifestSection = { - type: 'section'; - meta: UmbManifestSectionMeta; + 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 + 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 UmbExtensionManifestPropertyEditor = { - type: 'propertyEditorUI'; - meta: UmbManifestPropertyEditorMeta; + type: 'propertyEditorUI'; + meta: UmbManifestPropertyEditorMeta; } & UmbExtensionManifestBase; // Dashboard: export type UmbManifestDashboardMeta = { - sections: Array; - pathname: string; // TODO: how to we want to support pretty urls? - weight: number; + sections: Array; + pathname: string; // TODO: how to we want to support pretty urls? + weight: number; }; export type UmbExtensionManifestDashboard = { - type: 'dashboard'; - meta: UmbManifestDashboardMeta; + type: 'dashboard'; + meta: UmbManifestDashboardMeta; } & UmbExtensionManifestBase; // Editor View: export type UmbManifestEditorViewMeta = { - pathname: string; // TODO: how to we want to support pretty urls? - icon: string; - weight: number; + pathname: string; // TODO: how to we want to support pretty urls? + icon: string; + weight: number; }; export type UmbExtensionManifestEditorView = { - type: 'editorView'; - meta: UmbManifestEditorViewMeta; + type: 'editorView'; + meta: UmbManifestEditorViewMeta; } & UmbExtensionManifestBase; export type UmbExtensionManifestCore = - | UmbExtensionManifestSection - | UmbExtensionManifestDashboard - | UmbExtensionManifestPropertyEditor - | UmbExtensionManifestEditorView; + | UmbExtensionManifestSection + | UmbExtensionManifestDashboard + | UmbExtensionManifestPropertyEditor + | UmbExtensionManifestEditorView; // the 'Other' manifest type: type UmbExtensionManifestOther = { - type: string; - meta: unknown; + type: string; + meta: unknown; } & UmbExtensionManifestBase; export type UmbExtensionManifest = UmbExtensionManifestCore | UmbExtensionManifestOther; @@ -81,36 +81,36 @@ export type UmbExtensionManifest = UmbExtensionManifestCore | UmbExtensionManife type UmbExtensionManifestCoreTypes = Pick['type']; export class UmbExtensionRegistry { - private _extensions = new BehaviorSubject>([]); - public readonly extensions = this._extensions.asObservable(); + private _extensions = new BehaviorSubject>([]); + public readonly extensions = this._extensions.asObservable(); - register(manifest: T): void { - const extensionsValues = this._extensions.getValue(); - const extension = extensionsValues.find((extension) => extension.alias === manifest.alias); + register(manifest: T): void { + const extensionsValues = this._extensions.getValue(); + const extension = extensionsValues.find((extension) => extension.alias === manifest.alias); - if (extension) { - console.error(`Extension with alias ${manifest.alias} is already registered`); - return; - } + if (extension) { + console.error(`Extension with alias ${manifest.alias} is already registered`); + return; + } - this._extensions.next([...extensionsValues, manifest]); - } + this._extensions.next([...extensionsValues, manifest]); + } - getByAlias(alias: string): Observable { - // TODO: make pipes prettier/simpler/reuseable - return this.extensions.pipe(map((dataTypes) => dataTypes.find((extension) => extension.alias === alias) || null)); - } + getByAlias(alias: string): Observable { + // TODO: make pipes prettier/simpler/reuseable + return this.extensions.pipe(map((dataTypes) => dataTypes.find((extension) => extension.alias === alias) || null)); + } - // TODO: implement unregister of extension + // 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: 'propertyEditor'): Observable>; - extensionsOfType(type: UmbExtensionManifestCoreTypes): Observable>; - extensionsOfType(type: string): Observable>; - extensionsOfType(type: string): Observable>; - extensionsOfType(type: string) { - return this.extensions.pipe(map((exts) => exts.filter((ext) => ext.type === type))); - } + // 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: 'propertyEditor'): Observable>; + extensionsOfType(type: UmbExtensionManifestCoreTypes): 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/has-default-export.function.ts b/src/Umbraco.Web.UI.Client/src/core/extension/has-default-export.function.ts index 8a7931479f..d8b965ced5 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,5 +1,5 @@ import { HTMLElementConstructor } from '../models'; export function hasDefaultExport(object: unknown): object is { default: HTMLElementConstructor } { - return typeof object === 'object' && object !== null && 'default' in object; + return typeof object === 'object' && object !== null && 'default' in object; } 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 ab06750c87..93cdabdfee 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,9 @@ import { UmbExtensionManifestBase } from './extension.registry'; export function isExtensionType(manifest: unknown): manifest is UmbExtensionManifestBase { - return ( - typeof manifest === 'object' && - manifest !== null && - (manifest as UmbExtensionManifestBase).elementName !== undefined - ); + return ( + typeof manifest === 'object' && + manifest !== null && + (manifest as UmbExtensionManifestBase).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 3dbcfde874..73202c1a65 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,31 @@ import { UmbExtensionManifest } from './extension.registry'; export function loadExtension(manifest: UmbExtensionManifest): Promise | Promise { - if (typeof manifest.js === 'function') { - return manifest.js() as Promise; - } + if (typeof manifest.js === 'function') { + return manifest.js() as Promise; + } - // 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; - } + // 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; + } - console.log('-- Extension does not have any referenced JS'); - return Promise.resolve(null); + console.log('-- Extension does not have any referenced JS'); + return Promise.resolve(null); } diff --git a/src/Umbraco.Web.UI.Client/src/core/services/notification.service.ts b/src/Umbraco.Web.UI.Client/src/core/services/notification.service.ts index 8e0f3929bf..ee4373500f 100644 --- a/src/Umbraco.Web.UI.Client/src/core/services/notification.service.ts +++ b/src/Umbraco.Web.UI.Client/src/core/services/notification.service.ts @@ -1,18 +1,18 @@ import { BehaviorSubject, Observable } from 'rxjs'; type TempNotificationObject = { - headline: string; - key: string; + headline: string; + key: string; }; export class UmbNotificationService { - private _notifications: BehaviorSubject> = new BehaviorSubject( - >[] - ); - public readonly notifications: Observable> = this._notifications.asObservable(); + private _notifications: BehaviorSubject> = new BehaviorSubject( + >[] + ); + public readonly notifications: Observable> = this._notifications.asObservable(); - // TODO: this is just a quick solution to get notifications in POC. (suppose to get much more complex data set for this, enabling description, actions and event custom elements). - peek(headline: string) { - this._notifications.next([...this._notifications.getValue(), { headline: headline, key: Date.now().toString() }]); - } + // TODO: this is just a quick solution to get notifications in POC. (suppose to get much more complex data set for this, enabling description, actions and event custom elements). + peek(headline: string) { + this._notifications.next([...this._notifications.getValue(), { headline: headline, key: Date.now().toString() }]); + } } diff --git a/src/Umbraco.Web.UI.Client/src/core/stores/data-type.store.ts b/src/Umbraco.Web.UI.Client/src/core/stores/data-type.store.ts index 23629f0efa..78ba0fbb04 100644 --- a/src/Umbraco.Web.UI.Client/src/core/stores/data-type.store.ts +++ b/src/Umbraco.Web.UI.Client/src/core/stores/data-type.store.ts @@ -2,53 +2,53 @@ import { BehaviorSubject, map, Observable } from 'rxjs'; import { DataTypeEntity } from '../../mocks/data/content.data'; export class UmbDataTypeStore { - private _dataTypes: BehaviorSubject> = new BehaviorSubject(>[]); - public readonly dataTypes: Observable> = this._dataTypes.asObservable(); + private _dataTypes: BehaviorSubject> = new BehaviorSubject(>[]); + public readonly dataTypes: Observable> = this._dataTypes.asObservable(); - constructor() { - this._dataTypes.next([ - { - id: 1245, - key: 'dt-1', - name: 'TextString (DataType)', - propertyEditorUIAlias: 'Umb.PropertyEditorUI.Text', - }, - { - id: 1244, - key: 'dt-2', - name: 'Textarea (DataType)', - propertyEditorUIAlias: 'Umb.PropertyEditorUI.Textarea', - }, - { - id: 1246, - key: 'dt-3', - name: 'My JS Property Editor (DataType)', - propertyEditorUIAlias: 'My.PropertyEditorUI.Custom', - }, - { - id: 1247, - key: 'dt-4', - name: 'Context Example (DataType)', - propertyEditorUIAlias: 'Umb.PropertyEditorUI.ContextExample', - }, - ]); - } + constructor() { + this._dataTypes.next([ + { + id: 1245, + key: 'dt-1', + name: 'TextString (DataType)', + propertyEditorUIAlias: 'Umb.PropertyEditorUI.Text', + }, + { + id: 1244, + key: 'dt-2', + name: 'Textarea (DataType)', + propertyEditorUIAlias: 'Umb.PropertyEditorUI.Textarea', + }, + { + id: 1246, + key: 'dt-3', + name: 'My JS Property Editor (DataType)', + propertyEditorUIAlias: 'My.PropertyEditorUI.Custom', + }, + { + id: 1247, + key: 'dt-4', + name: 'Context Example (DataType)', + propertyEditorUIAlias: 'Umb.PropertyEditorUI.ContextExample', + }, + ]); + } - getById(id: number): Observable { - // no fetch.. + getById(id: number): Observable { + // no fetch.. - // TODO: make pipes prettier/simpler/reuseable - return this.dataTypes.pipe( - map((dataTypes: Array) => dataTypes.find((node: DataTypeEntity) => node.id === id) || null) - ); - } + // TODO: make pipes prettier/simpler/reuseable + return this.dataTypes.pipe( + map((dataTypes: Array) => dataTypes.find((node: DataTypeEntity) => node.id === id) || null) + ); + } - getByKey(key: string): Observable { - // no fetch.. + getByKey(key: string): Observable { + // no fetch.. - // TODO: make pipes prettier/simpler/reuseable - return this.dataTypes.pipe( - map((dataTypes: Array) => dataTypes.find((node: DataTypeEntity) => node.key === key) || null) - ); - } + // TODO: make pipes prettier/simpler/reuseable + return this.dataTypes.pipe( + map((dataTypes: Array) => dataTypes.find((node: DataTypeEntity) => node.key === key) || null) + ); + } } diff --git a/src/Umbraco.Web.UI.Client/src/core/stores/node.store.ts b/src/Umbraco.Web.UI.Client/src/core/stores/node.store.ts index 59659c21e1..bd7a0cf961 100644 --- a/src/Umbraco.Web.UI.Client/src/core/stores/node.store.ts +++ b/src/Umbraco.Web.UI.Client/src/core/stores/node.store.ts @@ -2,66 +2,66 @@ import { BehaviorSubject, map, Observable } from 'rxjs'; import { DocumentNode } from '../../mocks/data/content.data'; export class UmbNodeStore { - private _nodes: BehaviorSubject> = new BehaviorSubject(>[]); - public readonly nodes: Observable> = this._nodes.asObservable(); + private _nodes: BehaviorSubject> = new BehaviorSubject(>[]); + public readonly nodes: Observable> = this._nodes.asObservable(); - getById(id: number): Observable { - // fetch from server and update store - fetch(`/umbraco/backoffice/content/${id}`) - .then((res) => res.json()) - .then((data) => { - this._updateStore(data); - }); + getById(id: number): Observable { + // fetch from server and update store + fetch(`/umbraco/backoffice/content/${id}`) + .then((res) => res.json()) + .then((data) => { + this._updateStore(data); + }); - return this.nodes.pipe( - map((nodes: Array) => nodes.find((node: DocumentNode) => node.id === id) || null) - ); - } + return this.nodes.pipe( + map((nodes: Array) => nodes.find((node: DocumentNode) => node.id === id) || null) + ); + } - // TODO: Use Node type, to not be specific about Document. - // TODO: make sure UI somehow can follow the status of this action. - save(data: DocumentNode[]): Promise { - // fetch from server and update store - // TODO: use Fetcher API. - let body: string; + // TODO: Use Node type, to not be specific about Document. + // TODO: make sure UI somehow can follow the status of this action. + save(data: DocumentNode[]): Promise { + // fetch from server and update store + // TODO: use Fetcher API. + let body: string; - try { - body = JSON.stringify(data); - } catch (error) { - console.error(error); - return Promise.reject(); - } + try { + body = JSON.stringify(data); + } catch (error) { + console.error(error); + return Promise.reject(); + } - // TODO: Use node type to hit the right API, or have a general Node API? - return fetch('/umbraco/backoffice/content/save', { - method: 'POST', - body: body, - headers: { - 'Content-Type': 'application/json', - }, - }) - .then((res) => res.json()) - .then((data) => { - this._updateStore(data); - }); - } + // TODO: Use node type to hit the right API, or have a general Node API? + return fetch('/umbraco/backoffice/content/save', { + method: 'POST', + body: body, + headers: { + 'Content-Type': 'application/json', + }, + }) + .then((res) => res.json()) + .then((data) => { + this._updateStore(data); + }); + } - private _updateStore(fetchedNodes: Array) { - const storedNodes = this._nodes.getValue(); - const updated: DocumentNode[] = [...storedNodes]; + private _updateStore(fetchedNodes: Array) { + const storedNodes = this._nodes.getValue(); + const updated: DocumentNode[] = [...storedNodes]; - fetchedNodes.forEach((fetchedNode) => { - const index = storedNodes.map((storedNode) => storedNode.id).indexOf(fetchedNode.id); + fetchedNodes.forEach((fetchedNode) => { + const index = storedNodes.map((storedNode) => storedNode.id).indexOf(fetchedNode.id); - if (index !== -1) { - // If the node is already in the store, update it - updated[index] = fetchedNode; - } else { - // If the node is not in the store, add it - updated.push(fetchedNode); - } - }); + if (index !== -1) { + // If the node is already in the store, update it + updated[index] = fetchedNode; + } else { + // If the node is not in the store, add it + updated.push(fetchedNode); + } + }); - this._nodes.next([...updated]); - } + this._nodes.next([...updated]); + } } 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 9acf36eaf1..57c1418077 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 @@ -8,136 +8,136 @@ import { UmbInstallerContext } from './installer-context'; @customElement('umb-installer-consent') export class UmbInstallerConsent extends UmbContextConsumerMixin(LitElement) { - static styles: CSSResultGroup = [ - css` - :host, - #container { - display: flex; - flex-direction: column; - height: 100%; - } + static styles: CSSResultGroup = [ + css` + :host, + #container { + display: flex; + flex-direction: column; + height: 100%; + } - uui-form { - height: 100%; - } + uui-form { + height: 100%; + } - form { - height: 100%; - display: flex; - flex-direction: column; - } + form { + height: 100%; + display: flex; + flex-direction: column; + } - h1 { - text-align: center; - margin-bottom: var(--uui-size-layout-3); - } + h1 { + text-align: center; + margin-bottom: var(--uui-size-layout-3); + } - #buttons { - display: flex; - margin-top: auto; - } + #buttons { + display: flex; + margin-top: auto; + } - #button-install { - margin-left: auto; - min-width: 120px; - } - `, - ]; + #button-install { + margin-left: auto; + min-width: 120px; + } + `, + ]; - @state() - private _telemetryLevels: TelemetryModel[] = []; + @state() + private _telemetryLevels: TelemetryModel[] = []; - @state() - private _telemetryFormData!: TelemetryModel['level']; + @state() + private _telemetryFormData!: TelemetryModel['level']; - @state() - private _installerStore!: UmbInstallerContext; + @state() + private _installerStore!: UmbInstallerContext; - private storeDataSubscription?: Subscription; - private storeSettingsSubscription?: Subscription; + private storeDataSubscription?: Subscription; + private storeSettingsSubscription?: Subscription; - constructor() { - super(); + constructor() { + super(); - this.consumeContext('umbInstallerContext', (installerStore: UmbInstallerContext) => { - this._installerStore = installerStore; + this.consumeContext('umbInstallerContext', (installerStore: UmbInstallerContext) => { + this._installerStore = installerStore; - this.storeSettingsSubscription?.unsubscribe(); - this.storeSettingsSubscription = installerStore.settings.subscribe((settings) => { - this._telemetryLevels = settings.user.consentLevels; - }); + this.storeSettingsSubscription?.unsubscribe(); + this.storeSettingsSubscription = installerStore.settings.subscribe((settings) => { + this._telemetryLevels = settings.user.consentLevels; + }); - this.storeDataSubscription?.unsubscribe(); - this.storeDataSubscription = installerStore.data.subscribe((data) => { - this._telemetryFormData = data.telemetryLevel; - }); - }); - } + this.storeDataSubscription?.unsubscribe(); + this.storeDataSubscription = installerStore.data.subscribe((data) => { + this._telemetryFormData = data.telemetryLevel; + }); + }); + } - disconnectedCallback(): void { - super.disconnectedCallback(); - this.storeSettingsSubscription?.unsubscribe(); - this.storeDataSubscription?.unsubscribe(); - } + disconnectedCallback(): void { + super.disconnectedCallback(); + this.storeSettingsSubscription?.unsubscribe(); + this.storeDataSubscription?.unsubscribe(); + } - private _handleChange(e: InputEvent) { - const target = e.target as HTMLInputElement; + private _handleChange(e: InputEvent) { + const target = e.target as HTMLInputElement; - const value: { [key: string]: string } = {}; - value[target.name] = this._telemetryLevels[parseInt(target.value) - 1].level; - this._installerStore.appendData(value); - } + const value: { [key: string]: string } = {}; + value[target.name] = this._telemetryLevels[parseInt(target.value) - 1].level; + this._installerStore.appendData(value); + } - private _onNext() { - this.dispatchEvent(new CustomEvent('next', { bubbles: true, composed: true })); - } + private _onNext() { + this.dispatchEvent(new CustomEvent('next', { bubbles: true, composed: true })); + } - private _onBack() { - this.dispatchEvent(new CustomEvent('previous', { bubbles: true, composed: true })); - } + private _onBack() { + this.dispatchEvent(new CustomEvent('previous', { bubbles: true, composed: true })); + } - private get _selectedTelemetryIndex() { - return this._telemetryLevels?.findIndex((x) => x.level === this._telemetryFormData) ?? 0; - } + private get _selectedTelemetryIndex() { + return this._telemetryLevels?.findIndex((x) => x.level === this._telemetryFormData) ?? 0; + } - private get _selectedTelemetry() { - return this._telemetryLevels?.find((x) => x.level === this._telemetryFormData) ?? this._telemetryLevels[0]; - } + private get _selectedTelemetry() { + return this._telemetryLevels?.find((x) => x.level === this._telemetryFormData) ?? this._telemetryLevels[0]; + } - private _renderSlider() { - if (!this._telemetryLevels) return; + private _renderSlider() { + if (!this._telemetryLevels) return; - return html` - -

${this._selectedTelemetry.level}

- -

${unsafeHTML(this._selectedTelemetry.description)}

- `; - } + return html` + +

${this._selectedTelemetry.level}

+ +

${unsafeHTML(this._selectedTelemetry.description)}

+ `; + } - render() { - return html` -
-

Consent Level

- ${this._renderSlider()} -
- - -
-
- `; - } + render() { + return html` +
+

Consent Level

+ ${this._renderSlider()} +
+ + +
+
+ `; + } } declare global { - interface HTMLElementTagNameMap { - 'umb-installer-consent': UmbInstallerConsent; - } + interface HTMLElementTagNameMap { + 'umb-installer-consent': UmbInstallerConsent; + } } 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 f54b0cef5a..2d8fb4db4e 100644 --- a/src/Umbraco.Web.UI.Client/src/installer/installer-context.ts +++ b/src/Umbraco.Web.UI.Client/src/installer/installer-context.ts @@ -4,35 +4,35 @@ import { getInstallSettings, postInstallSetup } from '../core/api/fetcher'; import { PostInstallRequest, UmbracoInstaller } from '../core/models'; export class UmbInstallerContext { - private _data = new BehaviorSubject({ - user: { name: '', email: '', password: '', subscribeToNewsletter: false }, - telemetryLevel: 'Basic', - }); - public readonly data = this._data.asObservable(); + private _data = new BehaviorSubject({ + user: { name: '', email: '', password: '', subscribeToNewsletter: false }, + telemetryLevel: 'Basic', + }); + public readonly data = this._data.asObservable(); - private _settings = new ReplaySubject(); - public readonly settings = this._settings.asObservable(); + private _settings = new ReplaySubject(); + public readonly settings = this._settings.asObservable(); - constructor() { - this.loadIntallerSettings(); - } + constructor() { + this.loadIntallerSettings(); + } - public appendData(data: any) { - this._data.next({ ...this.getData(), ...data }); - } + public appendData(data: any) { + this._data.next({ ...this.getData(), ...data }); + } - public getData() { - return this._data.getValue(); - } + public getData() { + return this._data.getValue(); + } - public requestInstall() { - // TODO: The post install will probably return a user in the future, so we have to set that context somewhere to let the client know that it is authenticated - return postInstallSetup(this.getData()); - } + public requestInstall() { + // TODO: The post install will probably return a user in the future, so we have to set that context somewhere to let the client know that it is authenticated + return postInstallSetup(this.getData()); + } - private loadIntallerSettings() { - getInstallSettings({}).then(({ data }) => { - this._settings.next(data); - }); - } + private loadIntallerSettings() { + getInstallSettings({}).then(({ data }) => { + this._settings.next(data); + }); + } } 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 9cdf11d967..39d4c9e41a 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,356 +5,356 @@ import { Subscription } from 'rxjs'; import { UmbContextConsumerMixin } from '../core/context'; import { - ProblemDetails, - UmbracoInstallerDatabaseModel, - UmbracoPerformInstallDatabaseConfiguration, + ProblemDetails, + UmbracoInstallerDatabaseModel, + UmbracoPerformInstallDatabaseConfiguration, } from '../core/models'; import { UmbInstallerContext } from './installer-context'; @customElement('umb-installer-database') export class UmbInstallerDatabase extends UmbContextConsumerMixin(LitElement) { - static styles: CSSResultGroup = [ - css` - :host, - #container { - display: flex; - flex-direction: column; - height: 100%; - } + static styles: CSSResultGroup = [ + css` + :host, + #container { + display: flex; + flex-direction: column; + height: 100%; + } - uui-form { - height: 100%; - } + uui-form { + height: 100%; + } - form { - height: 100%; - display: flex; - flex-direction: column; - } + form { + height: 100%; + display: flex; + flex-direction: column; + } - form > uui-form-layout-item { - /* margin-bottom: var(--uui-size-layout-2); */ - } + form > uui-form-layout-item { + /* margin-bottom: var(--uui-size-layout-2); */ + } - uui-form-layout-item { - margin-top: 0; - margin-bottom: var(--uui-size-space-6); - } + uui-form-layout-item { + margin-top: 0; + margin-bottom: var(--uui-size-space-6); + } - uui-input, - uui-input-password, - uui-combobox { - width: 100%; - } + uui-input, + uui-input-password, + uui-combobox { + width: 100%; + } - hr { - width: 100%; - margin-top: var(--uui-size-space-2); - margin-bottom: var(--uui-size-space-6); - border: none; - border-bottom: 1px solid var(--uui-color-border); - } + hr { + width: 100%; + margin-top: var(--uui-size-space-2); + margin-bottom: var(--uui-size-space-6); + border: none; + border-bottom: 1px solid var(--uui-color-border); + } - h1 { - text-align: center; - margin-bottom: var(--uui-size-layout-3); - } + h1 { + text-align: center; + margin-bottom: var(--uui-size-layout-3); + } - h4 { - margin: 0; - } + h4 { + margin: 0; + } - #buttons { - display: flex; - margin-top: auto; - } + #buttons { + display: flex; + margin-top: auto; + } - #button-install { - margin-left: auto; - min-width: 120px; - } + #button-install { + margin-left: auto; + min-width: 120px; + } - #error-message { - color: var(--uui-color-error, red); - } - `, - ]; + #error-message { + color: var(--uui-color-error, red); + } + `, + ]; - @query('#button-install') - private _installButton!: UUIButtonElement; + @query('#button-install') + private _installButton!: UUIButtonElement; - @query('#error-message') - private _errorMessage!: HTMLElement; + @query('#error-message') + private _errorMessage!: HTMLElement; - @property({ attribute: false }) - public databaseFormData!: UmbracoPerformInstallDatabaseConfiguration; + @property({ attribute: false }) + public databaseFormData!: UmbracoPerformInstallDatabaseConfiguration; - @state() - private _options: { name: string; value: string; selected?: boolean }[] = []; + @state() + private _options: { name: string; value: string; selected?: boolean }[] = []; - @state() - private _databases: UmbracoInstallerDatabaseModel[] = []; + @state() + private _databases: UmbracoInstallerDatabaseModel[] = []; - @state() - private _preConfiguredDatabase?: UmbracoInstallerDatabaseModel; + @state() + private _preConfiguredDatabase?: UmbracoInstallerDatabaseModel; - @state() - private _installerStore!: UmbInstallerContext; + @state() + private _installerStore!: UmbInstallerContext; - private storeDataSubscription?: Subscription; - private storeSettingsSubscription?: Subscription; + private storeDataSubscription?: Subscription; + private storeSettingsSubscription?: Subscription; - constructor() { - super(); + constructor() { + super(); - this.consumeContext('umbInstallerContext', (installerStore: UmbInstallerContext) => { - this._installerStore = installerStore; + this.consumeContext('umbInstallerContext', (installerStore: UmbInstallerContext) => { + this._installerStore = installerStore; - this.storeSettingsSubscription?.unsubscribe(); - this.storeSettingsSubscription = installerStore.settings.subscribe((settings) => { - this._databases = settings.databases; + this.storeSettingsSubscription?.unsubscribe(); + this.storeSettingsSubscription = installerStore.settings.subscribe((settings) => { + this._databases = settings.databases; - // If there is an isConfigured database in the databases array then we can skip the database selection step - // and just use that. - this._preConfiguredDatabase = this._databases.find((x) => x.isConfigured); - if (!this._preConfiguredDatabase) { - this._options = settings.databases.map((x, i) => ({ name: x.displayName, value: x.id, selected: i === 0 })); - } - }); + // If there is an isConfigured database in the databases array then we can skip the database selection step + // and just use that. + this._preConfiguredDatabase = this._databases.find((x) => x.isConfigured); + if (!this._preConfiguredDatabase) { + this._options = settings.databases.map((x, i) => ({ name: x.displayName, value: x.id, selected: i === 0 })); + } + }); - this.storeDataSubscription?.unsubscribe(); - this.storeDataSubscription = installerStore.data.subscribe((data) => { - this.databaseFormData = data.database ?? {}; - this._options.forEach((x, i) => (x.selected = data.database?.id === x.value || i === 0)); - }); - }); - } + this.storeDataSubscription?.unsubscribe(); + this.storeDataSubscription = installerStore.data.subscribe((data) => { + this.databaseFormData = data.database ?? {}; + this._options.forEach((x, i) => (x.selected = data.database?.id === x.value || i === 0)); + }); + }); + } - disconnectedCallback(): void { - super.disconnectedCallback(); - this.storeSettingsSubscription?.unsubscribe(); - this.storeDataSubscription?.unsubscribe(); - } + disconnectedCallback(): void { + super.disconnectedCallback(); + this.storeSettingsSubscription?.unsubscribe(); + this.storeDataSubscription?.unsubscribe(); + } - private _handleChange(e: InputEvent) { - const target = e.target as HTMLInputElement; + private _handleChange(e: InputEvent) { + const target = e.target as HTMLInputElement; - const value: { [key: string]: string | boolean } = {}; - value[target.name] = target.checked ?? target.value; // handle boolean and text inputs + const value: { [key: string]: string | boolean } = {}; + value[target.name] = target.checked ?? target.value; // handle boolean and text inputs - const database = { ...this._installerStore.getData().database, ...value }; + const database = { ...this._installerStore.getData().database, ...value }; - this._installerStore.appendData({ database }); - } + this._installerStore.appendData({ database }); + } - private _handleSubmit = (e: SubmitEvent) => { - e.preventDefault(); + private _handleSubmit = (e: SubmitEvent) => { + e.preventDefault(); - const form = e.target as HTMLFormElement; - if (!form) return; + const form = e.target as HTMLFormElement; + if (!form) return; - const isValid = form.checkValidity(); - if (!isValid) return; + const isValid = form.checkValidity(); + if (!isValid) return; - // Only append the database if it's not pre-configured - if (!this._preConfiguredDatabase) { - const formData = new FormData(form); - const id = formData.get('id') as string; - const username = formData.get('username') as string; - const password = formData.get('password') as string; - const server = formData.get('server') as string; - const name = formData.get('name') as string; - const useIntegratedAuthentication = formData.has('useIntegratedAuthentication'); + // Only append the database if it's not pre-configured + if (!this._preConfiguredDatabase) { + const formData = new FormData(form); + const id = formData.get('id') as string; + const username = formData.get('username') as string; + const password = formData.get('password') as string; + const server = formData.get('server') as string; + const name = formData.get('name') as string; + const useIntegratedAuthentication = formData.has('useIntegratedAuthentication'); - const database = { - ...this._installerStore.getData().database, - id, - username, - password, - server, - name, - useIntegratedAuthentication, - } as UmbracoPerformInstallDatabaseConfiguration; + const database = { + ...this._installerStore.getData().database, + id, + username, + password, + server, + name, + useIntegratedAuthentication, + } as UmbracoPerformInstallDatabaseConfiguration; - this._installerStore.appendData({ database }); - } + this._installerStore.appendData({ database }); + } - this._installerStore.requestInstall().then(this._handleFulfilled.bind(this), this._handleRejected.bind(this)); - this._installButton.state = 'waiting'; - }; - private _handleFulfilled() { - this.dispatchEvent(new CustomEvent('next', { bubbles: true, composed: true })); - } - private _handleRejected(error: ProblemDetails) { - this._installButton.state = 'failed'; - this._errorMessage.innerText = error.type; - } + this._installerStore.requestInstall().then(this._handleFulfilled.bind(this), this._handleRejected.bind(this)); + this._installButton.state = 'waiting'; + }; + private _handleFulfilled() { + this.dispatchEvent(new CustomEvent('next', { bubbles: true, composed: true })); + } + private _handleRejected(error: ProblemDetails) { + this._installButton.state = 'failed'; + this._errorMessage.innerText = error.type; + } - private _onBack() { - this.dispatchEvent(new CustomEvent('previous', { bubbles: true, composed: true })); - } + private _onBack() { + this.dispatchEvent(new CustomEvent('previous', { bubbles: true, composed: true })); + } - private get selectedDatabase() { - const id = this._installerStore.getData().database?.id; - console.log('selected id', id, this._databases); - return this._databases.find((x) => x.id === id) ?? this._databases[0]; - } + private get selectedDatabase() { + const id = this._installerStore.getData().database?.id; + console.log('selected id', id, this._databases); + return this._databases.find((x) => x.id === id) ?? this._databases[0]; + } - private _renderSettings() { - if (!this.selectedDatabase) return; + private _renderSettings() { + if (!this.selectedDatabase) return; - if (this.selectedDatabase.displayName.toLowerCase() === 'custom') { - return this._renderCustom(); - } + if (this.selectedDatabase.displayName.toLowerCase() === 'custom') { + return this._renderCustom(); + } - const result = []; + const result = []; - if (this.selectedDatabase.requiresServer) { - result.push(this._renderServer()); - } + if (this.selectedDatabase.requiresServer) { + result.push(this._renderServer()); + } - result.push(this._renderDatabaseName()); + result.push(this._renderDatabaseName()); - if (this.selectedDatabase.requiresCredentials) { - result.push(this._renderCredentials()); - } + if (this.selectedDatabase.requiresCredentials) { + result.push(this._renderCredentials()); + } - return result; - } + return result; + } - private _renderServer = () => html` -

Connection

-
- - Server - - - `; + private _renderServer = () => html` +

Connection

+
+ + Server + + + `; - private _renderDatabaseName = () => html` - Database Name - - `; + private _renderDatabaseName = () => html` + Database Name + + `; - private _renderCredentials = () => html` -

Credentials

-
- - Use integrated authentication - + private _renderCredentials = () => html` +

Credentials

+
+ + Use integrated authentication + - ${!this.databaseFormData.useIntegratedAuthentication - ? html` - Username - - + ${!this.databaseFormData.useIntegratedAuthentication + ? html` + Username + + - - Password - - ` - : ''} - `; + + Password + + ` + : ''} + `; - private _renderCustom = () => html` - - Connection string - - - `; + private _renderCustom = () => html` + + Connection string + + + `; - private _renderDatabaseSelection = () => html` - - Database type - - + private _renderDatabaseSelection = () => html` + + Database type + + - ${this._renderSettings()} - `; + ${this._renderSettings()} + `; - private _renderPreConfiguredDatabase = (database: UmbracoInstallerDatabaseModel) => html` -

A database has already been pre-configured on the server and will be used:

-

- Type: ${database.displayName} -
- Provider: ${database.providerName} -

- `; + private _renderPreConfiguredDatabase = (database: UmbracoInstallerDatabaseModel) => html` +

A database has already been pre-configured on the server and will be used:

+

+ Type: ${database.displayName} +
+ Provider: ${database.providerName} +

+ `; - render() { - return html`
-

Database Configuration

- -
- ${this._preConfiguredDatabase - ? this._renderPreConfiguredDatabase(this._preConfiguredDatabase) - : this._renderDatabaseSelection()} + render() { + return html`
+

Database Configuration

+ + + ${this._preConfiguredDatabase + ? this._renderPreConfiguredDatabase(this._preConfiguredDatabase) + : this._renderDatabaseSelection()} - -

+ +

-
- - -
- -
-
`; - } +
+ + +
+ +
+
`; + } } declare global { - interface HTMLElementTagNameMap { - 'umb-installer-database': UmbInstallerDatabase; - } + interface HTMLElementTagNameMap { + 'umb-installer-database': UmbInstallerDatabase; + } } diff --git a/src/Umbraco.Web.UI.Client/src/installer/installer-installing.element.ts b/src/Umbraco.Web.UI.Client/src/installer/installer-installing.element.ts index 37ebf2509c..33117bdc83 100644 --- a/src/Umbraco.Web.UI.Client/src/installer/installer-installing.element.ts +++ b/src/Umbraco.Web.UI.Client/src/installer/installer-installing.element.ts @@ -2,46 +2,46 @@ import { css, CSSResultGroup, html, LitElement, PropertyValueMap } from 'lit'; import { customElement, state } from 'lit/decorators.js'; @customElement('umb-installer-installing') export class UmbInstallerInstalling extends LitElement { - static styles: CSSResultGroup = [ - css` - h1 { - text-align: center; - } - `, - ]; + static styles: CSSResultGroup = [ + css` + h1 { + text-align: center; + } + `, + ]; - @state() - private _installProgress = 0; + @state() + private _installProgress = 0; - protected firstUpdated(_changedProperties: PropertyValueMap | Map): void { - super.firstUpdated(_changedProperties); + protected firstUpdated(_changedProperties: PropertyValueMap | Map): void { + super.firstUpdated(_changedProperties); - this._updateProgress(); - } + this._updateProgress(); + } - private async _updateProgress() { - this._installProgress = Math.min(this._installProgress + (Math.random() + 1) * 10, 100); - await new Promise((resolve) => setTimeout(resolve, (Math.random() + 1) * 1000)); + private async _updateProgress() { + this._installProgress = Math.min(this._installProgress + (Math.random() + 1) * 10, 100); + await new Promise((resolve) => setTimeout(resolve, (Math.random() + 1) * 1000)); - if (this._installProgress >= 100) { - // Redirect to backoffice - history.replaceState(null, '', '/'); - return; - } + if (this._installProgress >= 100) { + // Redirect to backoffice + history.replaceState(null, '', '/'); + return; + } - this._updateProgress(); - } + this._updateProgress(); + } - render() { - return html`
-

Installing Umbraco

- -
`; - } + render() { + return html`
+

Installing Umbraco

+ +
`; + } } declare global { - interface HTMLElementTagNameMap { - 'umb-installer-installing': UmbInstallerInstalling; - } + interface HTMLElementTagNameMap { + 'umb-installer-installing': UmbInstallerInstalling; + } } diff --git a/src/Umbraco.Web.UI.Client/src/installer/installer-layout.element.ts b/src/Umbraco.Web.UI.Client/src/installer/installer-layout.element.ts index 2f1f1b6ab1..966e9cd6cf 100644 --- a/src/Umbraco.Web.UI.Client/src/installer/installer-layout.element.ts +++ b/src/Umbraco.Web.UI.Client/src/installer/installer-layout.element.ts @@ -3,70 +3,70 @@ import { customElement } from 'lit/decorators.js'; @customElement('umb-installer-layout') export class UmbInstallerLayout extends LitElement { - static styles: CSSResultGroup = [ - css` - #background { - position: fixed; - overflow: hidden; - background-position: 50%; - background-repeat: no-repeat; - background-size: cover; - background-image: url('/installer.jpg'); - width: 100vw; - height: 100vh; - } + static styles: CSSResultGroup = [ + css` + #background { + position: fixed; + overflow: hidden; + background-position: 50%; + background-repeat: no-repeat; + background-size: cover; + background-image: url('/installer.jpg'); + width: 100vw; + height: 100vh; + } - #logo { - position: fixed; - top: var(--uui-size-space-5); - left: var(--uui-size-space-5); - height: 30px; - } + #logo { + position: fixed; + top: var(--uui-size-space-5); + left: var(--uui-size-space-5); + height: 30px; + } - #logo img { - height: 100%; - } + #logo img { + height: 100%; + } - #container { - position: relative; - display: flex; - justify-content: flex-end; - width: 100%; - min-height: 100vh; - } + #container { + position: relative; + display: flex; + justify-content: flex-end; + width: 100%; + min-height: 100vh; + } - #box { - max-width: 500px; - width: 100%; - box-sizing: border-box; - border-radius: 30px 0 0 30px; - background-color: var(--uui-color-surface); - display: flex; - flex-direction: column; - padding: var(--uui-size-layout-4) var(--uui-size-layout-4) var(--uui-size-layout-2) var(--uui-size-layout-4); - } - `, - ]; + #box { + max-width: 500px; + width: 100%; + box-sizing: border-box; + border-radius: 30px 0 0 30px; + background-color: var(--uui-color-surface); + display: flex; + flex-direction: column; + padding: var(--uui-size-layout-4) var(--uui-size-layout-4) var(--uui-size-layout-2) var(--uui-size-layout-4); + } + `, + ]; - render() { - return html`
-
+ render() { + return html`
+
- + -
-
- -
-
-
`; - } +
+
+ +
+
+
`; + } } declare global { - interface HTMLElementTagNameMap { - 'umb-installer-layout': UmbInstallerLayout; - } + interface HTMLElementTagNameMap { + 'umb-installer-layout': UmbInstallerLayout; + } } diff --git a/src/Umbraco.Web.UI.Client/src/installer/installer-user.element.ts b/src/Umbraco.Web.UI.Client/src/installer/installer-user.element.ts index e53bd64683..6686843774 100644 --- a/src/Umbraco.Web.UI.Client/src/installer/installer-user.element.ts +++ b/src/Umbraco.Web.UI.Client/src/installer/installer-user.element.ts @@ -6,162 +6,162 @@ import { UmbInstallerContext } from './installer-context'; @customElement('umb-installer-user') export class UmbInstallerUser extends UmbContextConsumerMixin(LitElement) { - static styles: CSSResultGroup = [ - css` - :host, - #container { - display: flex; - flex-direction: column; - height: 100%; - } + static styles: CSSResultGroup = [ + css` + :host, + #container { + display: flex; + flex-direction: column; + height: 100%; + } - uui-form-layout-item { - margin-top: 0; - margin-bottom: var(--uui-size-space-6); - } + uui-form-layout-item { + margin-top: 0; + margin-bottom: var(--uui-size-space-6); + } - uui-form { - height: 100%; - } + uui-form { + height: 100%; + } - form { - height: 100%; - display: flex; - flex-direction: column; - } + form { + height: 100%; + display: flex; + flex-direction: column; + } - uui-input, - uui-input-password { - width: 100%; - } + uui-input, + uui-input-password { + width: 100%; + } - h1 { - text-align: center; - margin-bottom: var(--uui-size-layout-3); - } + h1 { + text-align: center; + margin-bottom: var(--uui-size-layout-3); + } - #news-checkbox { - margin-top: var(--uui-size-space-4); - } + #news-checkbox { + margin-top: var(--uui-size-space-4); + } - #buttons { - display: flex; - margin-top: auto; - } + #buttons { + display: flex; + margin-top: auto; + } - #button-install { - margin-left: auto; - min-width: 120px; - } - `, - ]; + #button-install { + margin-left: auto; + min-width: 120px; + } + `, + ]; - @state() - private _userFormData!: { name: string; password: string; email: string; subscribeToNewsletter: boolean }; + @state() + private _userFormData!: { name: string; password: string; email: string; subscribeToNewsletter: boolean }; - @state() - private _installerStore!: UmbInstallerContext; + @state() + private _installerStore!: UmbInstallerContext; - private installerStoreSubscription?: Subscription; + private installerStoreSubscription?: Subscription; - constructor() { - super(); + constructor() { + super(); - this.consumeContext('umbInstallerContext', (installerStore: UmbInstallerContext) => { - this._installerStore = installerStore; - this.installerStoreSubscription?.unsubscribe(); - this.installerStoreSubscription = installerStore.data.subscribe(({ user }) => { - this._userFormData = { - name: user.name, - password: user.password, - email: user.email, - subscribeToNewsletter: user.subscribeToNewsletter, - }; - }); - }); - } + this.consumeContext('umbInstallerContext', (installerStore: UmbInstallerContext) => { + this._installerStore = installerStore; + this.installerStoreSubscription?.unsubscribe(); + this.installerStoreSubscription = installerStore.data.subscribe(({ user }) => { + this._userFormData = { + name: user.name, + password: user.password, + email: user.email, + subscribeToNewsletter: user.subscribeToNewsletter, + }; + }); + }); + } - disconnectedCallback(): void { - super.disconnectedCallback(); - this.installerStoreSubscription?.unsubscribe(); - } + disconnectedCallback(): void { + super.disconnectedCallback(); + this.installerStoreSubscription?.unsubscribe(); + } - private _handleSubmit = (e: SubmitEvent) => { - e.preventDefault(); + private _handleSubmit = (e: SubmitEvent) => { + e.preventDefault(); - const form = e.target as HTMLFormElement; - if (!form) return; + const form = e.target as HTMLFormElement; + if (!form) return; - const isValid = form.checkValidity(); - if (!isValid) return; + const isValid = form.checkValidity(); + if (!isValid) return; - const formData = new FormData(form); - const name = formData.get('name'); - const password = formData.get('password'); - const email = formData.get('email'); - const subscribeToNewsletter = formData.has('subscribeToNewsletter'); + const formData = new FormData(form); + const name = formData.get('name'); + const password = formData.get('password'); + const email = formData.get('email'); + const subscribeToNewsletter = formData.has('subscribeToNewsletter'); - this._installerStore.appendData({ user: { name, password, email, subscribeToNewsletter } }); - this.dispatchEvent(new CustomEvent('next', { bubbles: true, composed: true })); - }; + this._installerStore.appendData({ user: { name, password, email, subscribeToNewsletter } }); + this.dispatchEvent(new CustomEvent('next', { bubbles: true, composed: true })); + }; - render() { - return html`
-

Install Umbraco

- -
- - Name - - + render() { + return html`
+

Install Umbraco

+ + + + Name + + - - Email - - + + Email + + - - Password - - + + Password + + - - - Keep me updated on Umbraco Versions, Security Bulletins and Community News - - + + + Keep me updated on Umbraco Versions, Security Bulletins and Community News + + -
- -
- -
-
`; - } +
+ +
+ +
+
`; + } } declare global { - interface HTMLElementTagNameMap { - 'umb-installer-user': UmbInstallerUser; - } + interface HTMLElementTagNameMap { + 'umb-installer-user': UmbInstallerUser; + } } 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 52af7bd4bc..4097645b34 100644 --- a/src/Umbraco.Web.UI.Client/src/installer/installer.element.ts +++ b/src/Umbraco.Web.UI.Client/src/installer/installer.element.ts @@ -12,53 +12,53 @@ import { UmbContextProviderMixin } from '../core/context'; @customElement('umb-installer') export class UmbInstaller extends UmbContextProviderMixin(LitElement) { - static styles: CSSResultGroup = [css``]; + static styles: CSSResultGroup = [css``]; - @state() - step = 1; + @state() + step = 1; - constructor() { - super(); - this.provideContext('umbInstallerContext', new UmbInstallerContext()); - } + constructor() { + super(); + this.provideContext('umbInstallerContext', new UmbInstallerContext()); + } - connectedCallback(): void { - super.connectedCallback(); - this.addEventListener('next', () => this._handleNext()); - this.addEventListener('previous', () => this._goToPreviousStep()); - } + connectedCallback(): void { + super.connectedCallback(); + this.addEventListener('next', () => this._handleNext()); + this.addEventListener('previous', () => this._goToPreviousStep()); + } - private _handleNext() { - this.step++; - } + private _handleNext() { + this.step++; + } - private _goToPreviousStep() { - this.step--; - } + private _goToPreviousStep() { + this.step--; + } - private _renderSection() { - switch (this.step) { - case 2: - return html``; - case 3: - return html``; - case 4: - return html``; + private _renderSection() { + switch (this.step) { + case 2: + return html``; + case 3: + return html``; + case 4: + return html``; - default: - return html``; - } - } + default: + return html``; + } + } - render() { - return html`${this._renderSection()} `; - } + render() { + return html`${this._renderSection()} `; + } } export default UmbInstaller; declare global { - interface HTMLElementTagNameMap { - 'umb-installer': UmbInstaller; - } + interface HTMLElementTagNameMap { + 'umb-installer': UmbInstaller; + } } diff --git a/src/Umbraco.Web.UI.Client/src/mocks/browser.ts b/src/Umbraco.Web.UI.Client/src/mocks/browser.ts index 504e29faf4..e296cc5fd0 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/browser.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/browser.ts @@ -4,12 +4,12 @@ import { handlers } from './handlers'; const worker = setupWorker(...handlers); export const startMockServiceWorker = () => - worker.start({ - onUnhandledRequest: (req) => { - if (req.url.pathname.startsWith('/node_modules/')) return; - if (req.url.pathname.startsWith('/src/')) return; - if (req.destination === 'image') return; + worker.start({ + onUnhandledRequest: (req) => { + if (req.url.pathname.startsWith('/node_modules/')) return; + if (req.url.pathname.startsWith('/src/')) return; + if (req.destination === 'image') return; - console.warn('Found an unhandled %s request to %s', req.method, req.url.href); - }, - }); + console.warn('Found an unhandled %s request to %s', req.method, req.url.href); + }, + }); diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/content.data.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/content.data.ts index 823276b746..d7800c33fe 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/data/content.data.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/data/content.data.ts @@ -1,29 +1,29 @@ export interface DocumentNode { - id: number; - key: string; - name: string; - alias: string; - icon: string; // TODO: should come from the doc type? - properties: NodeProperty[]; - //data: any; // TODO: define data type - //layout?: any; // TODO: define layout type - make it non-optional + id: number; + key: string; + name: string; + alias: string; + icon: string; // TODO: should come from the doc type? + properties: NodeProperty[]; + //data: any; // TODO: define data type + //layout?: any; // TODO: define layout type - make it non-optional } export interface DataTypeEntity { - id: number; - key: string; - name: string; - //icon: string; // TODO: should come from the doc type? - //configUI: any; // this is the prevalues... - propertyEditorUIAlias: string; + id: number; + key: string; + name: string; + //icon: string; // TODO: should come from the doc type? + //configUI: any; // this is the prevalues... + propertyEditorUIAlias: string; } export interface NodeProperty { - alias: string; - label: string; - description: string; - dataTypeKey: string; - tempValue: string; // TODO: remove this - only used for testing + alias: string; + label: string; + description: string; + dataTypeKey: string; + tempValue: string; // TODO: remove this - only used for testing } /* TODO: @@ -34,29 +34,29 @@ We would like the tree items to stay up to date, without requesting the server a If we split entityData into its own object, then that could go in the entityStore and be merged with the nodeStore (we would have a subscription on both). */ export const data: Array = [ - { - id: 1, - key: '74e4008a-ea4f-4793-b924-15e02fd380d1', - name: 'Document 1', - alias: 'document1', - icon: 'document', - properties: [ - { - alias: 'myHeadline', - label: 'Headline', - description: 'Text string property', - dataTypeKey: 'dt-1', - tempValue: 'The daily life at Umbraco HQ', - }, - { - alias: 'myDescription', - label: 'Description', - description: 'Textarea property', - dataTypeKey: 'dt-2', - tempValue: 'Every day, a rabbit in a military costume greets me at the front door', - }, - ], - /* + { + id: 1, + key: '74e4008a-ea4f-4793-b924-15e02fd380d1', + name: 'Document 1', + alias: 'document1', + icon: 'document', + properties: [ + { + alias: 'myHeadline', + label: 'Headline', + description: 'Text string property', + dataTypeKey: 'dt-1', + tempValue: 'The daily life at Umbraco HQ', + }, + { + alias: 'myDescription', + label: 'Description', + description: 'Textarea property', + dataTypeKey: 'dt-2', + tempValue: 'Every day, a rabbit in a military costume greets me at the front door', + }, + ], + /* // Concept for stored values, better approach for variants, separating data from structure/configuration, still needs structure for variants. (We could actually split it up so we have each variants data through a separate end-point?) data: [ { @@ -69,7 +69,7 @@ export const data: Array = [ }, ], */ - /* + /* // Concept for node layout, separation of design from config and data. layout: [ { @@ -87,73 +87,73 @@ export const data: Array = [ } ], */ - }, - { - id: 2, - key: '74e4008a-ea4f-4793-b924-15e02fd380d2', - name: 'Document 2', - alias: 'document2', - icon: 'favorite', - properties: [ - { - alias: 'myHeadline', - label: 'Text string label', - description: 'this is a text string property', - dataTypeKey: 'dt-1', - tempValue: 'Is it all just fun and curling and scary rabbits?', - }, - { - alias: 'myDescription', - label: 'Textarea label', - description: 'This is the a textarea property', - dataTypeKey: 'dt-2', - tempValue: - 'So no, there\'s not confetti every day. And no, there\'s not champagne every week or a crazy rabbit running around 🐰', - }, - { - alias: 'myExternalEditor', - label: 'My JS Property Editor', - description: 'This is the a external property', - dataTypeKey: 'dt-3', - tempValue: 'Tex lkasdfkljdfsa 1', - }, - { - alias: 'myContextExampleEditor', - label: 'Context example label', - description: 'This is the a example property', - dataTypeKey: 'dt-4', - tempValue: '', - }, - ], - }, + }, + { + id: 2, + key: '74e4008a-ea4f-4793-b924-15e02fd380d2', + name: 'Document 2', + alias: 'document2', + icon: 'favorite', + properties: [ + { + alias: 'myHeadline', + label: 'Text string label', + description: 'this is a text string property', + dataTypeKey: 'dt-1', + tempValue: 'Is it all just fun and curling and scary rabbits?', + }, + { + alias: 'myDescription', + label: 'Textarea label', + description: 'This is the a textarea property', + dataTypeKey: 'dt-2', + tempValue: + "So no, there's not confetti every day. And no, there's not champagne every week or a crazy rabbit running around 🐰", + }, + { + alias: 'myExternalEditor', + label: 'My JS Property Editor', + description: 'This is the a external property', + dataTypeKey: 'dt-3', + tempValue: 'Tex lkasdfkljdfsa 1', + }, + { + alias: 'myContextExampleEditor', + label: 'Context example label', + description: 'This is the a example property', + dataTypeKey: 'dt-4', + tempValue: '', + }, + ], + }, ]; // Temp mocked database class UmbContentData { - private _data: Array = []; + private _data: Array = []; - constructor() { - this._data = data; - } + constructor() { + this._data = data; + } - getById(id: number) { - return this._data.find((item) => item.id === id); - } + getById(id: number) { + return this._data.find((item) => item.id === id); + } - save(nodes: DocumentNode[]) { - nodes.forEach((node) => { - const foundIndex = this._data.findIndex((item) => item.id === node.id); - if (foundIndex !== -1) { - // replace - this._data[foundIndex] = node; - } else { - // new - this._data.push(node); - } - }); - //console.log('save:', nodes); - return nodes; - } + save(nodes: DocumentNode[]) { + nodes.forEach((node) => { + const foundIndex = this._data.findIndex((item) => item.id === node.id); + if (foundIndex !== -1) { + // replace + this._data[foundIndex] = node; + } else { + // new + this._data.push(node); + } + }); + //console.log('save:', nodes); + return nodes; + } } export const umbContentData = new UmbContentData(); diff --git a/src/Umbraco.Web.UI.Client/src/mocks/domains/content.handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/domains/content.handlers.ts index d390921da5..7159c0056f 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/domains/content.handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/domains/content.handlers.ts @@ -4,22 +4,22 @@ import { DocumentNode, umbContentData } from '../data/content.data'; // TODO: add schema export const handlers = [ - rest.get('/umbraco/backoffice/content/:id', (req, res, ctx) => { - const id = req.params.id as string; - if (!id) return; + rest.get('/umbraco/backoffice/content/:id', (req, res, ctx) => { + const id = req.params.id as string; + if (!id) return; - const int = parseInt(id); - const document = umbContentData.getById(int); + const int = parseInt(id); + const document = umbContentData.getById(int); - return res(ctx.status(200), ctx.json([document])); - }), + return res(ctx.status(200), ctx.json([document])); + }), - rest.post('/umbraco/backoffice/content/save', (req, res, ctx) => { - const data = req.body; - if (!data) return; + rest.post('/umbraco/backoffice/content/save', (req, res, ctx) => { + const data = req.body; + if (!data) return; - umbContentData.save(data); + umbContentData.save(data); - return res(ctx.status(200), ctx.json(data)); - }), + return res(ctx.status(200), ctx.json(data)); + }), ]; 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 558fe436e8..af8c1fe18e 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 @@ -3,94 +3,94 @@ import { rest } from 'msw'; import { PostInstallRequest, ProblemDetails, UmbracoInstaller } from '../../core/models'; export const handlers = [ - rest.get('/umbraco/backoffice/install/settings', (_req, res, ctx) => { - return res( - // Respond with a 200 status code - ctx.status(200), - ctx.json({ - user: { - minCharLength: 2, - minNonAlphaNumericLength: 0, - consentLevels: [ - { - level: 'Minimal', - description: 'We will only send an anonymized site ID to let us know that the site exists.', - }, - { - level: 'Basic', - description: 'We will send an anonymized site ID, umbraco version, and packages installed', - }, - { - level: 'Detailed', - description: - 'We will send:\n
- Anonymized site ID, umbraco version, and packages installed.\n
- Number of: Root nodes, Content nodes, Macros, Media, Document Types, Templates, Languages, Domains, User Group, Users, Members, and Property Editors in use.\n
- System information: Webserver, server OS, server framework, server OS language, and database provider.\n
- Configuration settings: Modelsbuilder mode, if custom Umbraco path exists, ASP environment, and if you are in debug mode.\n
\n
We might change what we send on the Detailed level in the future. If so, it will be listed above.\n
By choosing "Detailed" you agree to current and future anonymized information being collected.
', - }, - ], - }, - databases: [ - { - id: '1', - sortOrder: -1, - displayName: 'SQLite', - defaultDatabaseName: 'Umbraco', - providerName: 'Microsoft.Data.SQLite', - isConfigured: import.meta.env.VITE_UMBRACO_INSTALL_PRECONFIGURED === 'true', - requiresServer: false, - serverPlaceholder: null, - requiresCredentials: false, - supportsIntegratedAuthentication: false, - requiresConnectionTest: false, - }, - { - id: '2', - sortOrder: 2, - displayName: 'SQL Server', - defaultDatabaseName: '', - providerName: 'Microsoft.Data.SqlClient', - isConfigured: false, - requiresServer: true, - serverPlaceholder: '(local)\\SQLEXPRESS', - requiresCredentials: true, - supportsIntegratedAuthentication: true, - requiresConnectionTest: true, - }, - { - id: '42c0eafd-1650-4bdb-8cf6-d226e8941698', - sortOrder: 2147483647, - displayName: 'Custom', - defaultDatabaseName: '', - providerName: null, - isConfigured: false, - requiresServer: false, - serverPlaceholder: null, - requiresCredentials: false, - supportsIntegratedAuthentication: false, - requiresConnectionTest: true, - }, - ], - }) - ); - }), + rest.get('/umbraco/backoffice/install/settings', (_req, res, ctx) => { + return res( + // Respond with a 200 status code + ctx.status(200), + ctx.json({ + user: { + minCharLength: 2, + minNonAlphaNumericLength: 0, + consentLevels: [ + { + level: 'Minimal', + description: 'We will only send an anonymized site ID to let us know that the site exists.', + }, + { + level: 'Basic', + description: 'We will send an anonymized site ID, umbraco version, and packages installed', + }, + { + level: 'Detailed', + description: + 'We will send:\n
- Anonymized site ID, umbraco version, and packages installed.\n
- Number of: Root nodes, Content nodes, Macros, Media, Document Types, Templates, Languages, Domains, User Group, Users, Members, and Property Editors in use.\n
- System information: Webserver, server OS, server framework, server OS language, and database provider.\n
- Configuration settings: Modelsbuilder mode, if custom Umbraco path exists, ASP environment, and if you are in debug mode.\n
\n
We might change what we send on the Detailed level in the future. If so, it will be listed above.\n
By choosing "Detailed" you agree to current and future anonymized information being collected.
', + }, + ], + }, + databases: [ + { + id: '1', + sortOrder: -1, + displayName: 'SQLite', + defaultDatabaseName: 'Umbraco', + providerName: 'Microsoft.Data.SQLite', + isConfigured: import.meta.env.VITE_UMBRACO_INSTALL_PRECONFIGURED === 'true', + requiresServer: false, + serverPlaceholder: null, + requiresCredentials: false, + supportsIntegratedAuthentication: false, + requiresConnectionTest: false, + }, + { + id: '2', + sortOrder: 2, + displayName: 'SQL Server', + defaultDatabaseName: '', + providerName: 'Microsoft.Data.SqlClient', + isConfigured: false, + requiresServer: true, + serverPlaceholder: '(local)\\SQLEXPRESS', + requiresCredentials: true, + supportsIntegratedAuthentication: true, + requiresConnectionTest: true, + }, + { + id: '42c0eafd-1650-4bdb-8cf6-d226e8941698', + sortOrder: 2147483647, + displayName: 'Custom', + defaultDatabaseName: '', + providerName: null, + isConfigured: false, + requiresServer: false, + serverPlaceholder: null, + requiresCredentials: false, + supportsIntegratedAuthentication: false, + requiresConnectionTest: true, + }, + ], + }) + ); + }), - rest.post('/umbraco/backoffice/install/setup', async (req, res, ctx) => { - await new Promise((resolve) => setTimeout(resolve, (Math.random() + 1) * 1000)); // simulate a delay of 1-2 seconds + rest.post('/umbraco/backoffice/install/setup', async (req, res, ctx) => { + await new Promise((resolve) => setTimeout(resolve, (Math.random() + 1) * 1000)); // simulate a delay of 1-2 seconds - if (req.body.database?.name === 'fail') { - return res( - // Respond with a 200 status code - ctx.status(400), - ctx.json({ - type: 'validation', - status: 400, - errors: { - name: ['Database name is invalid'], - }, - }) - ); - } - return res( - // Respond with a 200 status code - ctx.status(201) - ); - }), + if (req.body.database?.name === 'fail') { + return res( + // Respond with a 200 status code + ctx.status(400), + ctx.json({ + type: 'validation', + status: 400, + errors: { + name: ['Database name is invalid'], + }, + }) + ); + } + return res( + // Respond with a 200 status code + ctx.status(201) + ); + }), ]; 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 de2f6b395b..e219af59c5 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 @@ -2,36 +2,36 @@ import { rest } from 'msw'; // TODO: set up schema export const handlers = [ - rest.get('/umbraco/backoffice/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, - }, - }, - { - 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', - }, - }, - ], - }) - ); - }), + rest.get('/umbraco/backoffice/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, + }, + }, + { + 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', + }, + }, + ], + }) + ); + }), ]; 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 d8815ef2bb..9a49745dd4 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 @@ -3,22 +3,22 @@ import { rest } from 'msw'; import { StatusResponse, VersionResponse } from '../../core/models'; export const handlers = [ - rest.get('/umbraco/backoffice/server/status', (_req, res, ctx) => { - return res( - // Respond with a 200 status code - ctx.status(200), - ctx.json({ - serverStatus: import.meta.env.VITE_UMBRACO_INSTALL_STATUS !== 'false' ? 'running' : 'must-install', - }) - ); - }), - rest.get('/umbraco/backoffice/server/version', (_req, res, ctx) => { - return res( - // Respond with a 200 status code - ctx.status(200), - ctx.json({ - version: '13.0.0', - }) - ); - }), + rest.get('/umbraco/backoffice/server/status', (_req, res, ctx) => { + return res( + // Respond with a 200 status code + ctx.status(200), + ctx.json({ + serverStatus: import.meta.env.VITE_UMBRACO_INSTALL_STATUS !== 'false' ? 'running' : 'must-install', + }) + ); + }), + rest.get('/umbraco/backoffice/server/version', (_req, res, ctx) => { + return res( + // Respond with a 200 status code + ctx.status(200), + ctx.json({ + version: '13.0.0', + }) + ); + }), ]; 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 c870781a0f..bf9e07a6ee 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 @@ -2,52 +2,52 @@ import { rest } from 'msw'; import { AllowedSectionsResponse, UserResponse } from '../../core/models'; export const handlers = [ - rest.post('/umbraco/backoffice/user/login', (_req, res, ctx) => { - // Persist user's authentication in the session - sessionStorage.setItem('is-authenticated', 'true'); - return res( - // Respond with a 200 status code - ctx.status(201) - ); - }), + rest.post('/umbraco/backoffice/user/login', (_req, res, ctx) => { + // Persist user's authentication in the session + sessionStorage.setItem('is-authenticated', 'true'); + return res( + // Respond with a 200 status code + ctx.status(201) + ); + }), - rest.post('/umbraco/backoffice/user/logout', (_req, res, ctx) => { - // Persist user's authentication in the session - sessionStorage.removeItem('is-authenticated'); - return res( - // Respond with a 200 status code - ctx.status(201) - ); - }), + rest.post('/umbraco/backoffice/user/logout', (_req, res, ctx) => { + // Persist user's authentication in the session + sessionStorage.removeItem('is-authenticated'); + return res( + // Respond with a 200 status code + ctx.status(201) + ); + }), - rest.get('/umbraco/backoffice/user', (_req, res, ctx) => { - // Check if the user is authenticated in this session - const isAuthenticated = sessionStorage.getItem('is-authenticated'); - if (!isAuthenticated) { - // If not authenticated, respond with a 403 error - return res( - ctx.status(403), - ctx.json({ - errorMessage: 'Not authorized', - }) - ); - } - // If authenticated, return a mocked user details - return res( - ctx.status(200), - ctx.json({ - username: 'admin', - role: 'administrator', - }) - ); - }), + rest.get('/umbraco/backoffice/user', (_req, res, ctx) => { + // Check if the user is authenticated in this session + const isAuthenticated = sessionStorage.getItem('is-authenticated'); + if (!isAuthenticated) { + // If not authenticated, respond with a 403 error + return res( + ctx.status(403), + ctx.json({ + errorMessage: 'Not authorized', + }) + ); + } + // If authenticated, return a mocked user details + return res( + ctx.status(200), + ctx.json({ + username: 'admin', + role: 'administrator', + }) + ); + }), - rest.get('/umbraco/backoffice/user/sections', (_req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - sections: ['Umb.Section.Content', 'Umb.Section.Settings', 'My.Section.Custom'], - }) - ); - }), + rest.get('/umbraco/backoffice/user/sections', (_req, res, ctx) => { + return res( + ctx.status(200), + ctx.json({ + sections: ['Umb.Section.Content', 'Umb.Section.Settings', 'My.Section.Custom'], + }) + ); + }), ]; diff --git a/src/Umbraco.Web.UI.Client/src/mocks/handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/handlers.ts index 1ca585578f..171418201b 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/handlers.ts @@ -5,9 +5,9 @@ import { handlers as serverHandlers } from './domains/server.handlers'; import { handlers as userHandlers } from './domains/user.handlers'; export const handlers = [ - ...serverHandlers, - ...contentHandlers, - ...installHandlers, - ...manifestsHandlers, - ...userHandlers, + ...serverHandlers, + ...contentHandlers, + ...installHandlers, + ...manifestsHandlers, + ...userHandlers, ]; 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 3c115d219d..4eed878f05 100644 --- a/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/temp-internal-manifests.ts @@ -1,115 +1,115 @@ import { UmbExtensionManifestCore } from './core/extension'; export const internalManifests: Array = [ - { - type: 'section', - alias: 'Umb.Section.Content', - name: 'Content', - elementName: 'umb-content-section', - js: () => import('./backoffice/sections/content/content-section.element'), - meta: { - pathname: 'content', // 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.Settings', - name: 'Settings', - elementName: 'umb-settings-section', - js: () => import('./backoffice/sections/settings/settings-section.element'), - meta: { - pathname: 'settings', // TODO: how to we want to support pretty urls? - weight: 20, - }, - }, - { - type: 'dashboard', - alias: 'Umb.Dashboard.Welcome', - name: 'Welcome', - elementName: 'umb-dashboard-welcome', - js: () => import('./backoffice/dashboards/dashboard-welcome.element'), - meta: { - sections: ['Umb.Section.Content'], - pathname: 'welcome', // TODO: how to we want to support pretty urls? - weight: 20, - }, - }, - { - type: 'dashboard', - alias: 'Umb.Dashboard.RedirectManagement', - name: 'Redirect Management', - elementName: 'umb-dashboard-redirect-management', - js: () => import('./backoffice/dashboards/dashboard-redirect-management.element'), - meta: { - sections: ['Umb.Section.Content'], - pathname: 'redirect-management', // TODO: how to we want to support pretty urls? - weight: 10, - }, - }, - { - type: 'propertyEditorUI', - alias: 'Umb.PropertyEditorUI.Text', - name: 'Text', - js: () => import('./backoffice/property-editors/property-editor-text.element'), - meta: { - icon: 'document', - group: 'common', - }, - }, - { - type: 'propertyEditorUI', - alias: 'Umb.PropertyEditorUI.Textarea', - name: 'Textarea', - elementName: 'umb-property-editor-textarea', - js: () => import('./backoffice/property-editors/property-editor-textarea.element'), - meta: { - icon: 'document', - group: 'common', - }, - }, - { - type: 'propertyEditorUI', - alias: 'Umb.PropertyEditorUI.ContextExample', - name: 'Context Example', - js: () => import('./backoffice/property-editors/property-editor-context-example.element'), - meta: { - icon: 'document', - group: 'common', - }, - }, - { - type: 'editorView', - alias: 'Umb.EditorView.ContentEdit', - name: 'Content', - elementName: 'umb-editor-view-node-edit', - js: () => import('./backoffice/editor-views/editor-view-node-edit.element'), - meta: { - pathname: 'content', - weight: 100, - icon: 'document', - }, - }, - { - type: 'editorView', - alias: 'Umb.EditorView.ContentInfo', - name: 'Info', - elementName: 'umb-editor-view-node-info', - js: () => import('./backoffice/editor-views/editor-view-node-info.element'), - meta: { - pathname: 'info', - weight: 90, - icon: 'info', - }, - }, + { + type: 'section', + alias: 'Umb.Section.Content', + name: 'Content', + elementName: 'umb-content-section', + js: () => import('./backoffice/sections/content/content-section.element'), + meta: { + pathname: 'content', // 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.Settings', + name: 'Settings', + elementName: 'umb-settings-section', + js: () => import('./backoffice/sections/settings/settings-section.element'), + meta: { + pathname: 'settings', // TODO: how to we want to support pretty urls? + weight: 20, + }, + }, + { + type: 'dashboard', + alias: 'Umb.Dashboard.Welcome', + name: 'Welcome', + elementName: 'umb-dashboard-welcome', + js: () => import('./backoffice/dashboards/dashboard-welcome.element'), + meta: { + sections: ['Umb.Section.Content'], + pathname: 'welcome', // TODO: how to we want to support pretty urls? + weight: 20, + }, + }, + { + type: 'dashboard', + alias: 'Umb.Dashboard.RedirectManagement', + name: 'Redirect Management', + elementName: 'umb-dashboard-redirect-management', + js: () => import('./backoffice/dashboards/dashboard-redirect-management.element'), + meta: { + sections: ['Umb.Section.Content'], + pathname: 'redirect-management', // TODO: how to we want to support pretty urls? + weight: 10, + }, + }, + { + type: 'propertyEditorUI', + alias: 'Umb.PropertyEditorUI.Text', + name: 'Text', + js: () => import('./backoffice/property-editors/property-editor-text.element'), + meta: { + icon: 'document', + group: 'common', + }, + }, + { + type: 'propertyEditorUI', + alias: 'Umb.PropertyEditorUI.Textarea', + name: 'Textarea', + elementName: 'umb-property-editor-textarea', + js: () => import('./backoffice/property-editors/property-editor-textarea.element'), + meta: { + icon: 'document', + group: 'common', + }, + }, + { + type: 'propertyEditorUI', + alias: 'Umb.PropertyEditorUI.ContextExample', + name: 'Context Example', + js: () => import('./backoffice/property-editors/property-editor-context-example.element'), + meta: { + icon: 'document', + group: 'common', + }, + }, + { + type: 'editorView', + alias: 'Umb.EditorView.ContentEdit', + name: 'Content', + elementName: 'umb-editor-view-node-edit', + js: () => import('./backoffice/editor-views/editor-view-node-edit.element'), + meta: { + pathname: 'content', + weight: 100, + icon: 'document', + }, + }, + { + type: 'editorView', + alias: 'Umb.EditorView.ContentInfo', + name: 'Info', + elementName: 'umb-editor-view-node-info', + js: () => import('./backoffice/editor-views/editor-view-node-info.element'), + meta: { + pathname: 'info', + weight: 90, + icon: 'info', + }, + }, ]; diff --git a/src/Umbraco.Web.UI.Client/src/upgrader/upgrader.element.ts b/src/Umbraco.Web.UI.Client/src/upgrader/upgrader.element.ts index 73ce15b7e5..c2acb61623 100644 --- a/src/Umbraco.Web.UI.Client/src/upgrader/upgrader.element.ts +++ b/src/Umbraco.Web.UI.Client/src/upgrader/upgrader.element.ts @@ -5,34 +5,34 @@ import { UmbContextProviderMixin } from '../core/context'; @customElement('umb-upgrader') export class UmbUpgrader extends UmbContextProviderMixin(LitElement) { - static styles: CSSResultGroup = [css``]; + static styles: CSSResultGroup = [css``]; - @state() - step = 1; + @state() + step = 1; - connectedCallback(): void { - super.connectedCallback(); - this.addEventListener('next', () => this._handleNext()); - this.addEventListener('previous', () => this._goToPreviousStep()); - } + connectedCallback(): void { + super.connectedCallback(); + this.addEventListener('next', () => this._handleNext()); + this.addEventListener('previous', () => this._goToPreviousStep()); + } - private _handleNext() { - this.step++; - } + private _handleNext() { + this.step++; + } - private _goToPreviousStep() { - this.step--; - } + private _goToPreviousStep() { + this.step--; + } - render() { - return html`

Please implement me

`; - } + render() { + return html`

Please implement me

`; + } } export default UmbUpgrader; declare global { - interface HTMLElementTagNameMap { - 'umb-upgrader': UmbUpgrader; - } + interface HTMLElementTagNameMap { + 'umb-upgrader': UmbUpgrader; + } } diff --git a/src/Umbraco.Web.UI.Client/src/vite-env.d.ts b/src/Umbraco.Web.UI.Client/src/vite-env.d.ts index 8d05a22c69..78d9eb2522 100644 --- a/src/Umbraco.Web.UI.Client/src/vite-env.d.ts +++ b/src/Umbraco.Web.UI.Client/src/vite-env.d.ts @@ -1,5 +1,5 @@ /// interface ImportMetaEnv { - VITE_UMBRACO_INSTALL_STATUS: string; - VITE_UMBRACO_INSTALL_PRECONFIGURED: string; + VITE_UMBRACO_INSTALL_STATUS: string; + VITE_UMBRACO_INSTALL_PRECONFIGURED: string; }