diff --git a/src/Umbraco.Web.UI.Client/src/packages/packages/package-section/views/installed/installed-packages-section-view-item.element.ts b/src/Umbraco.Web.UI.Client/src/packages/packages/package-section/views/installed/installed-packages-section-view-item.element.ts index 9be9a1ab10..324658656f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/packages/package-section/views/installed/installed-packages-section-view-item.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/packages/package-section/views/installed/installed-packages-section-view-item.element.ts @@ -1,22 +1,18 @@ import { html, css, nothing, ifDefined, customElement, property, state } from '@umbraco-cms/backoffice/external/lit'; -import type { UUIButtonState } from '@umbraco-cms/backoffice/external/uui'; -import { map } from '@umbraco-cms/backoffice/external/rxjs'; -import { umbConfirmModal } from '@umbraco-cms/backoffice/modal'; import { createExtensionElement } from '@umbraco-cms/backoffice/extension-api'; -import type { ManifestPackageView } from '@umbraco-cms/backoffice/extension-registry'; +import { PackageResource } from '@umbraco-cms/backoffice/external/backend-api'; +import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; +import { umbConfirmModal } from '@umbraco-cms/backoffice/modal'; import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; -import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; -import { PackageResource } from '@umbraco-cms/backoffice/external/backend-api'; -import type { UmbNotificationContext } from '@umbraco-cms/backoffice/notification'; import { UMB_NOTIFICATION_CONTEXT } from '@umbraco-cms/backoffice/notification'; +import type { ManifestPackageView } from '@umbraco-cms/backoffice/extension-registry'; +import type { UmbNotificationContext } from '@umbraco-cms/backoffice/notification'; +import type { UUIButtonState } from '@umbraco-cms/backoffice/external/uui'; @customElement('umb-installed-packages-section-view-item') export class UmbInstalledPackagesSectionViewItemElement extends UmbLitElement { @property() - public get name(): string | undefined { - return this.#name; - } public set name(value: string | undefined) { const oldValue = this.#name; if (oldValue === value) return; @@ -24,6 +20,9 @@ export class UmbInstalledPackagesSectionViewItemElement extends UmbLitElement { this.#observePackageView(); this.requestUpdate('name', oldValue); } + public get name(): string | undefined { + return this.#name; + } #name?: string | undefined; @property() @@ -32,7 +31,7 @@ export class UmbInstalledPackagesSectionViewItemElement extends UmbLitElement { @property({ type: Boolean, attribute: false }) hasPendingMigrations = false; - @property() + @property({ attribute: 'custom-icon' }) customIcon?: string; @state() @@ -53,11 +52,7 @@ export class UmbInstalledPackagesSectionViewItemElement extends UmbLitElement { #observePackageView() { this.observe( - umbExtensionsRegistry.byType('packageView').pipe( - map((extensions) => { - return extensions.filter((extension) => extension.meta.packageName === this.#name); - }), - ), + umbExtensionsRegistry.byTypeAndFilter('packageView', (manifest) => manifest.meta.packageName === this.#name), (manifests) => { if (manifests.length === 0) { this._packageView = undefined; @@ -69,54 +64,7 @@ export class UmbInstalledPackagesSectionViewItemElement extends UmbLitElement { ); } - async _onMigration() { - if (!this.name) return; - - await umbConfirmModal(this, { - color: 'positive', - headline: `Run migrations for ${this.name}?`, - content: `Do you want to start run migrations for ${this.name}`, - confirmLabel: 'Run migrations', - }); - - this._migrationButtonState = 'waiting'; - const { error } = await tryExecuteAndNotify( - this, - PackageResource.postPackageByNameRunMigration({ name: this.name }), - ); - if (error) return; - this.#notificationContext?.peek('positive', { data: { message: 'Migrations completed' } }); - this._migrationButtonState = 'success'; - this.hasPendingMigrations = false; - } - - render() { - return this.name - ? html` - - ${this.customIcon ? html`` : nothing} -
- ${this.hasPendingMigrations - ? html` - Run pending migrations - ` - : nothing} -
-
- ` - : ''; - } - - private async _onConfigure() { + async #onConfigure() { if (!this._packageView) { console.warn('Tried to configure package without view'); return; @@ -140,6 +88,61 @@ export class UmbInstalledPackagesSectionViewItemElement extends UmbLitElement { */ } + async #onMigration() { + if (!this.name) return; + + await umbConfirmModal(this, { + color: 'positive', + headline: `Run migrations for ${this.name}?`, + content: `Do you want to start run migrations for ${this.name}`, + confirmLabel: 'Run migrations', + }); + + this._migrationButtonState = 'waiting'; + const { error } = await tryExecuteAndNotify( + this, + PackageResource.postPackageByNameRunMigration({ name: this.name }), + ); + + if (error) return; + + this.#notificationContext?.peek('positive', { + data: { + headline: 'Migrations completed', + message: this.localize.term('packager_packageMigrationsComplete'), + }, + }); + + this._migrationButtonState = 'success'; + this.hasPendingMigrations = false; + } + + render() { + return this.name + ? html` + + ${this.customIcon ? html`` : nothing} +
+ ${this.hasPendingMigrations + ? html` + Run pending migrations + ` + : nothing} +
+
+ ` + : ''; + } + static styles = css` :host { display: flex; diff --git a/src/Umbraco.Web.UI.Client/src/packages/packages/package-section/views/installed/installed-packages-section-view.element.ts b/src/Umbraco.Web.UI.Client/src/packages/packages/package-section/views/installed/installed-packages-section-view.element.ts index 2b3b4dfda7..b530d73a29 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/packages/package-section/views/installed/installed-packages-section-view.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/packages/package-section/views/installed/installed-packages-section-view.element.ts @@ -1,12 +1,12 @@ import { UmbPackageRepository } from '../../../package/repository/package.repository.js'; import type { UmbPackageWithMigrationStatus } from '../../../types.js'; -import { html, css, customElement, state, repeat } from '@umbraco-cms/backoffice/external/lit'; -import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; +import { html, css, customElement, state, repeat, nothing, unsafeHTML } from '@umbraco-cms/backoffice/external/lit'; +import { observeMultiple } from '@umbraco-cms/backoffice/observable-api'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import type { UmbSectionViewElement } from '@umbraco-cms/backoffice/extension-registry'; import './installed-packages-section-view-item.element.js'; -import { observeMultiple } from '@umbraco-cms/backoffice/observable-api'; @customElement('umb-installed-packages-section-view') export class UmbInstalledPackagesSectionViewElement extends UmbLitElement implements UmbSectionViewElement { @@ -24,91 +24,90 @@ export class UmbInstalledPackagesSectionViewElement extends UmbLitElement implem } firstUpdated() { - this._loadInstalledPackages(); + this.#loadInstalledPackages(); } - /** - * Fetch the installed packages from the server - */ - private async _loadInstalledPackages() { + async #loadInstalledPackages() { const data = await Promise.all([this.#packageRepository.rootItems(), this.#packageRepository.migrations()]); const [package$, migration$] = data; this.observe(observeMultiple([package$, migration$]), ([packages, migrations]) => { - this._installedPackages = packages.map((p) => { - const migration = migrations.find((m) => m.packageName === p.name); + this._installedPackages = packages.map((pkg) => { + const migration = migrations.find((m) => m.packageName === pkg.name); if (migration) { // Remove that migration from the list - migrations = migrations.filter((m) => m.packageName !== p.name); + migrations = migrations.filter((m) => m.packageName !== pkg.name); } return { - ...p, + ...pkg, hasPendingMigrations: migration?.hasPendingMigrations ?? false, }; }); - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - this._migrationPackages = [ - ...migrations.map((m) => ({ - name: m.packageName, - hasPendingMigrations: m.hasPendingMigrations ?? false, - })), - ]; - /*this._installedPackages = [ - ...this._installedPackages, - ...migrations.map((m) => ({ - name: m.packageName, - hasPendingMigrations: m.hasPendingMigrations ?? false, - })), - ];*/ + this._migrationPackages = migrations.map((m) => ({ + name: m.packageName, + hasPendingMigrations: m.hasPendingMigrations ?? false, + extensions: [], + })); }); } render() { - if (this._installedPackages.length) return html`${this._renderCustomMigrations()} ${this._renderInstalled()} `; - return html`
-

No packages have been installed

-

- Browse through the available packages using the 'Packages' icon in the top right of your screen -

-
`; + if (!this._installedPackages.length) return this.#renderNoPackages(); + return html`${this.#renderCustomMigrations()} ${this.#renderInstalled()} `; } - private _renderInstalled() { - return html` - - ${repeat( - this._installedPackages, - (item) => item.name, - (item) => - html``, - )} - - `; + #renderNoPackages() { + return html` +
+

${this.localize.term('packager_noPackages')}

+

${unsafeHTML(this.localize.term('packager_noPackagesDescription'))}

+
+ `; } - private _renderCustomMigrations() { - if (!this._migrationPackages) return; - return html` - - ${repeat( - this._migrationPackages, - (item) => item.name, - (item) => - html``, - )} - - `; + #renderInstalled() { + return html` + + + ${repeat( + this._installedPackages, + (item) => item.name, + (item) => html` + + + `, + )} + + + `; + } + + #renderCustomMigrations() { + if (!this._migrationPackages.length) return nothing; + return html` + + + ${repeat( + this._migrationPackages, + (item) => item.name, + (item) => html` + + + `, + )} + + + `; } static styles = [