Refactored "Installed Packages" view

This commit is contained in:
leekelleher
2024-04-04 10:22:06 +01:00
parent dd68445775
commit 9ef91edfeb
2 changed files with 130 additions and 128 deletions

View File

@@ -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`
<uui-ref-node-package
name=${ifDefined(this.name)}
version="${ifDefined(this.version ?? undefined)}"
@open=${this._onConfigure}
?disabled="${!this._packageView}">
${this.customIcon ? html`<umb-icon slot="icon" name="${this.customIcon}"></umb-icon>` : nothing}
<div slot="tag">
${this.hasPendingMigrations
? html`<uui-button
@click="${this._onMigration}"
.state=${this._migrationButtonState}
color="warning"
look="primary"
label="Run pending package migrations">
Run pending migrations
</uui-button>`
: nothing}
</div>
</uui-ref-node-package>
`
: '';
}
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`
<uui-ref-node-package
name=${ifDefined(this.name)}
version="${ifDefined(this.version ?? undefined)}"
@open=${this.#onConfigure}
?disabled="${!this._packageView}">
${this.customIcon ? html`<umb-icon slot="icon" name=${this.customIcon}></umb-icon>` : nothing}
<div slot="tag">
${this.hasPendingMigrations
? html`<uui-button
@click="${this.#onMigration}"
.state=${this._migrationButtonState}
color="warning"
look="primary"
label=${this.localize.term('packageMigrationsRun')}>
Run pending migrations
</uui-button>`
: nothing}
</div>
</uui-ref-node-package>
`
: '';
}
static styles = css`
:host {
display: flex;

View File

@@ -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`<div class="no-packages">
<h2><strong>No packages have been installed</strong></h2>
<p>
Browse through the available packages using the <strong>'Packages'</strong> icon in the top right of your screen
</p>
</div>`;
if (!this._installedPackages.length) return this.#renderNoPackages();
return html`${this.#renderCustomMigrations()} ${this.#renderInstalled()} `;
}
private _renderInstalled() {
return html`<uui-box headline="Installed packages" style="--uui-box-default-padding:0">
<uui-ref-list>
${repeat(
this._installedPackages,
(item) => item.name,
(item) =>
html`<umb-installed-packages-section-view-item
.name=${item.name}
.version=${item.version}
.hasPendingMigrations=${item.hasPendingMigrations}></umb-installed-packages-section-view-item>`,
)}
</uui-ref-list>
</uui-box>`;
#renderNoPackages() {
return html`
<div class="no-packages">
<h2><strong>${this.localize.term('packager_noPackages')}</strong></h2>
<p>${unsafeHTML(this.localize.term('packager_noPackagesDescription'))}</p>
</div>
`;
}
private _renderCustomMigrations() {
if (!this._migrationPackages) return;
return html`<uui-box headline="Migrations" style="--uui-box-default-padding:0">
<uui-ref-list>
${repeat(
this._migrationPackages,
(item) => item.name,
(item) =>
html`<umb-installed-packages-section-view-item
.name=${item.name}
.version=${item.version}
.customIcon="${'icon-sync'}"
.hasPendingMigrations=${item.hasPendingMigrations}></umb-installed-packages-section-view-item>`,
)}
</uui-ref-list>
</uui-box>`;
#renderInstalled() {
return html`
<uui-box headline=${this.localize.term('packager_installedPackages')} style="--uui-box-default-padding:0">
<uui-ref-list>
${repeat(
this._installedPackages,
(item) => item.name,
(item) => html`
<umb-installed-packages-section-view-item
.name=${item.name}
.version=${item.version}
.hasPendingMigrations=${item.hasPendingMigrations}>
</umb-installed-packages-section-view-item>
`,
)}
</uui-ref-list>
</uui-box>
`;
}
#renderCustomMigrations() {
if (!this._migrationPackages.length) return nothing;
return html`
<uui-box headline="Migrations" style="--uui-box-default-padding:0">
<uui-ref-list>
${repeat(
this._migrationPackages,
(item) => item.name,
(item) => html`
<umb-installed-packages-section-view-item
custom-icon="icon-sync"
.name=${item.name}
.version=${item.version}
.hasPendingMigrations=${item.hasPendingMigrations}>
</umb-installed-packages-section-view-item>
`,
)}
</uui-ref-list>
</uui-box>
`;
}
static styles = [