From ce5f2d7182d86e8fc9cf8b3092d5d6e4751b5b0a Mon Sep 17 00:00:00 2001 From: Lone Iversen <108085781+loivsen@users.noreply.github.com> Date: Thu, 2 Mar 2023 11:27:06 +0100 Subject: [PATCH] Feature/installed and created packages (#545) * multiple selection in modalhandler is ok? * installed view updates * created view updates * workspace for package builder * package builder * all pickers in workspace * use input-picker rather than property editor ui * installed package view * ui updates * packageview * update handlers * update package views with migrations * update backend api * endpoints * migration & language picker * small update * seperate migrations that doesnt belong to a packag * rename NotificationContext * filter out packages that have no name before they go in to the store --------- Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> --- .../libs/backend-api/src/index.ts | 13 + .../src/models/AuditLogBaseModel.ts | 16 + .../src/models/AuditLogResponseModel.ts | 8 + .../AuditLogWithUsernameResponseModel.ts | 11 + .../backend-api/src/models/AuditTypeModel.ts | 30 ++ .../src/models/LogLevelCountsModel.ts | 12 + .../src/models/PagedAuditLogResponseModel.ts | 11 + .../PagedAuditLogWithUsernameResponseModel.ts | 11 + .../src/services/AuditLogResource.ts | 103 +++++++ .../src/services/LogViewerResource.ts | 3 +- .../src/services/ProfilingResource.ts | 17 ++ .../src/services/TrackedReferenceResource.ts | 2 +- .../libs/models/index.ts | 4 + .../src/backoffice/backoffice.element.ts | 2 +- .../workspace-package-builder.element.ts | 285 +++++++++++++++++- .../workspace/workspace-package.element.ts | 45 ++- .../created-packages-section-view.element.ts | 11 +- .../created/packages-created-item.element.ts | 27 -- .../packages-created-overview.element.ts | 157 ++++++++-- ...lled-packages-section-view-item.element.ts | 98 ++++-- ...installed-packages-section-view.element.ts | 116 ++++++- .../packages/repository/package.repository.ts | 3 +- .../src/core/mocks/browser-handlers.ts | 2 + .../core/mocks/domains/package.handlers.ts | 126 ++++++++ .../src/core/mocks/e2e-handlers.ts | 2 + .../modal-layout-content-picker.element.ts | 2 +- 26 files changed, 1020 insertions(+), 97 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/libs/backend-api/src/models/AuditLogBaseModel.ts create mode 100644 src/Umbraco.Web.UI.Client/libs/backend-api/src/models/AuditLogResponseModel.ts create mode 100644 src/Umbraco.Web.UI.Client/libs/backend-api/src/models/AuditLogWithUsernameResponseModel.ts create mode 100644 src/Umbraco.Web.UI.Client/libs/backend-api/src/models/AuditTypeModel.ts create mode 100644 src/Umbraco.Web.UI.Client/libs/backend-api/src/models/LogLevelCountsModel.ts create mode 100644 src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PagedAuditLogResponseModel.ts create mode 100644 src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PagedAuditLogWithUsernameResponseModel.ts create mode 100644 src/Umbraco.Web.UI.Client/libs/backend-api/src/services/AuditLogResource.ts delete mode 100644 src/Umbraco.Web.UI.Client/src/backoffice/packages/package-section/views/created/packages-created-item.element.ts create mode 100644 src/Umbraco.Web.UI.Client/src/core/mocks/domains/package.handlers.ts diff --git a/src/Umbraco.Web.UI.Client/libs/backend-api/src/index.ts b/src/Umbraco.Web.UI.Client/libs/backend-api/src/index.ts index 1a5f7a1df3..c90638336d 100644 --- a/src/Umbraco.Web.UI.Client/libs/backend-api/src/index.ts +++ b/src/Umbraco.Web.UI.Client/libs/backend-api/src/index.ts @@ -6,6 +6,10 @@ export { CancelablePromise, CancelError } from './core/CancelablePromise'; export { OpenAPI } from './core/OpenAPI'; export type { OpenAPIConfig } from './core/OpenAPI'; +export type { AuditLogBaseModel } from './models/AuditLogBaseModel'; +export type { AuditLogResponseModel } from './models/AuditLogResponseModel'; +export type { AuditLogWithUsernameResponseModel } from './models/AuditLogWithUsernameResponseModel'; +export { AuditTypeModel } from './models/AuditTypeModel'; export type { ConsentLevelModel } from './models/ConsentLevelModel'; export { ContentStateModel } from './models/ContentStateModel'; export type { ContentTreeItemModel } from './models/ContentTreeItemModel'; @@ -74,6 +78,7 @@ export type { LanguageModel } from './models/LanguageModel'; export type { LanguageModelBaseModel } from './models/LanguageModelBaseModel'; export type { LanguageUpdateModel } from './models/LanguageUpdateModel'; export type { LoggerModel } from './models/LoggerModel'; +export type { LogLevelCountsModel } from './models/LogLevelCountsModel'; export { LogLevelModel } from './models/LogLevelModel'; export type { LogMessageModel } from './models/LogMessageModel'; export type { LogMessagePropertyModel } from './models/LogMessagePropertyModel'; @@ -84,7 +89,13 @@ export type { OkResultModel } from './models/OkResultModel'; export { OperatorModel } from './models/OperatorModel'; export type { OutOfDateStatusModel } from './models/OutOfDateStatusModel'; export { OutOfDateTypeModel } from './models/OutOfDateTypeModel'; +export type { PackageCreateModel } from './models/PackageCreateModel'; +export type { PackageDefinitionModel } from './models/PackageDefinitionModel'; export type { PackageMigrationStatusModel } from './models/PackageMigrationStatusModel'; +export type { PackageModelBaseModel } from './models/PackageModelBaseModel'; +export type { PackageUpdateModel } from './models/PackageUpdateModel'; +export type { PagedAuditLogResponseModel } from './models/PagedAuditLogResponseModel'; +export type { PagedAuditLogWithUsernameResponseModel } from './models/PagedAuditLogWithUsernameResponseModel'; export type { PagedContentTreeItemModel } from './models/PagedContentTreeItemModel'; export type { PagedCultureModel } from './models/PagedCultureModel'; export type { PagedDictionaryOverviewModel } from './models/PagedDictionaryOverviewModel'; @@ -101,6 +112,7 @@ export type { PagedLanguageModel } from './models/PagedLanguageModel'; export type { PagedLoggerModel } from './models/PagedLoggerModel'; export type { PagedLogMessageModel } from './models/PagedLogMessageModel'; export type { PagedLogTemplateModel } from './models/PagedLogTemplateModel'; +export type { PagedPackageDefinitionModel } from './models/PagedPackageDefinitionModel'; export type { PagedPackageMigrationStatusModel } from './models/PagedPackageMigrationStatusModel'; export type { PagedRecycleBinItemModel } from './models/PagedRecycleBinItemModel'; export type { PagedRedirectUrlModel } from './models/PagedRedirectUrlModel'; @@ -157,6 +169,7 @@ export type { ValueViewModelBaseModel } from './models/ValueViewModelBaseModel'; export type { VariantViewModelBaseModel } from './models/VariantViewModelBaseModel'; export type { VersionModel } from './models/VersionModel'; +export { AuditLogResource } from './services/AuditLogResource'; export { CultureResource } from './services/CultureResource'; export { DataTypeResource } from './services/DataTypeResource'; export { DictionaryResource } from './services/DictionaryResource'; diff --git a/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/AuditLogBaseModel.ts b/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/AuditLogBaseModel.ts new file mode 100644 index 0000000000..8da67f825a --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/AuditLogBaseModel.ts @@ -0,0 +1,16 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { AuditTypeModel } from './AuditTypeModel'; + +export type AuditLogBaseModel = { + userKey?: string; + entityKey?: string | null; + timestamp?: string; + logType?: AuditTypeModel; + entityType?: string | null; + comment?: string | null; + parameters?: string | null; +}; + diff --git a/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/AuditLogResponseModel.ts b/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/AuditLogResponseModel.ts new file mode 100644 index 0000000000..53aaafdb87 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/AuditLogResponseModel.ts @@ -0,0 +1,8 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { AuditLogBaseModel } from './AuditLogBaseModel'; + +export type AuditLogResponseModel = AuditLogBaseModel; + diff --git a/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/AuditLogWithUsernameResponseModel.ts b/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/AuditLogWithUsernameResponseModel.ts new file mode 100644 index 0000000000..eb768a7c43 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/AuditLogWithUsernameResponseModel.ts @@ -0,0 +1,11 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { AuditLogBaseModel } from './AuditLogBaseModel'; + +export type AuditLogWithUsernameResponseModel = (AuditLogBaseModel & { + userName?: string | null; + userAvatars?: Array | null; +}); + diff --git a/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/AuditTypeModel.ts b/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/AuditTypeModel.ts new file mode 100644 index 0000000000..e030d0564a --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/AuditTypeModel.ts @@ -0,0 +1,30 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +export enum AuditTypeModel { + NEW = 'New', + SAVE = 'Save', + SAVE_VARIANT = 'SaveVariant', + OPEN = 'Open', + DELETE = 'Delete', + PUBLISH = 'Publish', + PUBLISH_VARIANT = 'PublishVariant', + SEND_TO_PUBLISH = 'SendToPublish', + SEND_TO_PUBLISH_VARIANT = 'SendToPublishVariant', + UNPUBLISH = 'Unpublish', + UNPUBLISH_VARIANT = 'UnpublishVariant', + MOVE = 'Move', + COPY = 'Copy', + ASSIGN_DOMAIN = 'AssignDomain', + PUBLIC_ACCESS = 'PublicAccess', + SORT = 'Sort', + NOTIFY = 'Notify', + SYSTEM = 'System', + ROLL_BACK = 'RollBack', + PACKAGER_INSTALL = 'PackagerInstall', + PACKAGER_UNINSTALL = 'PackagerUninstall', + CUSTOM = 'Custom', + CONTENT_VERSION_PREVENT_CLEANUP = 'ContentVersionPreventCleanup', + CONTENT_VERSION_ENABLE_CLEANUP = 'ContentVersionEnableCleanup', +} diff --git a/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/LogLevelCountsModel.ts b/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/LogLevelCountsModel.ts new file mode 100644 index 0000000000..6fbb50efba --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/LogLevelCountsModel.ts @@ -0,0 +1,12 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +export type LogLevelCountsModel = { + information?: number; + debug?: number; + warning?: number; + error?: number; + fatal?: number; +}; + diff --git a/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PagedAuditLogResponseModel.ts b/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PagedAuditLogResponseModel.ts new file mode 100644 index 0000000000..28e4883e9d --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PagedAuditLogResponseModel.ts @@ -0,0 +1,11 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { AuditLogResponseModel } from './AuditLogResponseModel'; + +export type PagedAuditLogResponseModel = { + total: number; + items: Array; +}; + diff --git a/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PagedAuditLogWithUsernameResponseModel.ts b/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PagedAuditLogWithUsernameResponseModel.ts new file mode 100644 index 0000000000..2faa8a352c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PagedAuditLogWithUsernameResponseModel.ts @@ -0,0 +1,11 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { AuditLogWithUsernameResponseModel } from './AuditLogWithUsernameResponseModel'; + +export type PagedAuditLogWithUsernameResponseModel = { + total: number; + items: Array; +}; + diff --git a/src/Umbraco.Web.UI.Client/libs/backend-api/src/services/AuditLogResource.ts b/src/Umbraco.Web.UI.Client/libs/backend-api/src/services/AuditLogResource.ts new file mode 100644 index 0000000000..20a267dcb5 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/backend-api/src/services/AuditLogResource.ts @@ -0,0 +1,103 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { AuditTypeModel } from '../models/AuditTypeModel'; +import type { DirectionModel } from '../models/DirectionModel'; +import type { PagedAuditLogResponseModel } from '../models/PagedAuditLogResponseModel'; +import type { PagedAuditLogWithUsernameResponseModel } from '../models/PagedAuditLogWithUsernameResponseModel'; + +import type { CancelablePromise } from '../core/CancelablePromise'; +import { OpenAPI } from '../core/OpenAPI'; +import { request as __request } from '../core/request'; + +export class AuditLogResource { + + /** + * @returns PagedAuditLogWithUsernameResponseModel Success + * @throws ApiError + */ + public static getAuditLog({ + orderDirection, + sinceDate, + skip, + take = 100, + }: { + orderDirection?: DirectionModel, + sinceDate?: string, + skip?: number, + take?: number, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/umbraco/management/api/v1/audit-log', + query: { + 'orderDirection': orderDirection, + 'sinceDate': sinceDate, + 'skip': skip, + 'take': take, + }, + }); + } + + /** + * @returns PagedAuditLogResponseModel Success + * @throws ApiError + */ + public static getAuditLogByKey({ + key, + orderDirection, + sinceDate, + skip, + take = 100, + }: { + key: string, + orderDirection?: DirectionModel, + sinceDate?: string, + skip?: number, + take?: number, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/umbraco/management/api/v1/audit-log/{key}', + path: { + 'key': key, + }, + query: { + 'orderDirection': orderDirection, + 'sinceDate': sinceDate, + 'skip': skip, + 'take': take, + }, + }); + } + + /** + * @returns PagedAuditLogResponseModel Success + * @throws ApiError + */ + public static getAuditLogTypeByLogType({ + logType, + sinceDate, + skip, + take = 100, + }: { + logType: AuditTypeModel, + sinceDate?: string, + skip?: number, + take?: number, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/umbraco/management/api/v1/audit-log/type/{logType}', + path: { + 'logType': logType, + }, + query: { + 'sinceDate': sinceDate, + 'skip': skip, + 'take': take, + }, + }); + } + +} diff --git a/src/Umbraco.Web.UI.Client/libs/backend-api/src/services/LogViewerResource.ts b/src/Umbraco.Web.UI.Client/libs/backend-api/src/services/LogViewerResource.ts index 6f6da6fbd7..b768fba3a1 100644 --- a/src/Umbraco.Web.UI.Client/libs/backend-api/src/services/LogViewerResource.ts +++ b/src/Umbraco.Web.UI.Client/libs/backend-api/src/services/LogViewerResource.ts @@ -2,6 +2,7 @@ /* tslint:disable */ /* eslint-disable */ import type { DirectionModel } from '../models/DirectionModel'; +import type { LogLevelCountsModel } from '../models/LogLevelCountsModel'; import type { LogLevelModel } from '../models/LogLevelModel'; import type { PagedLoggerModel } from '../models/PagedLoggerModel'; import type { PagedLogMessageModel } from '../models/PagedLogMessageModel'; @@ -46,7 +47,7 @@ export class LogViewerResource { }: { startDate?: string, endDate?: string, - }): CancelablePromise { + }): CancelablePromise { return __request(OpenAPI, { method: 'GET', url: '/umbraco/management/api/v1/log-viewer/level-count', diff --git a/src/Umbraco.Web.UI.Client/libs/backend-api/src/services/ProfilingResource.ts b/src/Umbraco.Web.UI.Client/libs/backend-api/src/services/ProfilingResource.ts index 0560495600..c5d65d6bdc 100644 --- a/src/Umbraco.Web.UI.Client/libs/backend-api/src/services/ProfilingResource.ts +++ b/src/Umbraco.Web.UI.Client/libs/backend-api/src/services/ProfilingResource.ts @@ -20,4 +20,21 @@ export class ProfilingResource { }); } + /** + * @returns any Success + * @throws ApiError + */ + public static putProfilingStatus({ + requestBody, + }: { + requestBody?: ProfilingStatusModel, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'PUT', + url: '/umbraco/management/api/v1/profiling/status', + body: requestBody, + mediaType: 'application/json', + }); + } + } diff --git a/src/Umbraco.Web.UI.Client/libs/backend-api/src/services/TrackedReferenceResource.ts b/src/Umbraco.Web.UI.Client/libs/backend-api/src/services/TrackedReferenceResource.ts index 4eb25900ec..e5637971a9 100644 --- a/src/Umbraco.Web.UI.Client/libs/backend-api/src/services/TrackedReferenceResource.ts +++ b/src/Umbraco.Web.UI.Client/libs/backend-api/src/services/TrackedReferenceResource.ts @@ -46,7 +46,7 @@ export class TrackedReferenceResource { parentKey, skip, take, - filterMustBeIsDependency, + filterMustBeIsDependency = true, }: { parentKey: string, skip?: number, diff --git a/src/Umbraco.Web.UI.Client/libs/models/index.ts b/src/Umbraco.Web.UI.Client/libs/models/index.ts index 55988872da..93f630e8e2 100644 --- a/src/Umbraco.Web.UI.Client/libs/models/index.ts +++ b/src/Umbraco.Web.UI.Client/libs/models/index.ts @@ -159,3 +159,7 @@ export type UmbPackage = { }; export type PagedManifestsResponse = UmbPackage[]; + +export type UmbPackageWithMigrationStatus = UmbPackage & { + hasPendingMigrations: boolean; +}; 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 85df618420..cee5fd1db9 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts @@ -45,9 +45,9 @@ import { } from './settings/languages/app-language-select/app-language.context'; import { UmbPackageStore } from './packages/repository/package.store'; import { UmbServerExtensionController } from './packages/repository/server-extension.controller'; +import { umbExtensionsRegistry } from '@umbraco-cms/extensions-api'; import { UmbNotificationContext, UMB_NOTIFICATION_CONTEXT_TOKEN } from '@umbraco-cms/notification'; import { UmbLitElement } from '@umbraco-cms/element'; -import { umbExtensionsRegistry } from '@umbraco-cms/extensions-api'; import '@umbraco-cms/router'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-builder/workspace/workspace-package-builder.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-builder/workspace/workspace-package-builder.element.ts index 3cafbfe2cc..26b897a91b 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-builder/workspace/workspace-package-builder.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-builder/workspace/workspace-package-builder.element.ts @@ -1,24 +1,295 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; -import { css, html, LitElement } from 'lit'; -import { customElement } from 'lit/decorators.js'; +import { UUIBooleanInputEvent, UUIInputElement, UUIInputEvent } from '@umbraco-ui/uui'; +import { css, html, nothing } from 'lit'; +import { customElement, property, query, state } from 'lit/decorators.js'; +import { ifDefined } from 'lit-html/directives/if-defined.js'; +import { UmbInputDocumentPickerElement } from '../../../shared/components/input-document-picker/input-document-picker.element'; +import { UmbInputMediaPickerElement } from '../../../shared/components/input-media-picker/input-media-picker.element'; +import { UmbInputLanguagePickerElement } from '../../../shared/components/input-language-picker/input-language-picker.element'; +import { UmbLitElement } from '@umbraco-cms/element'; +import { PackageDefinitionModel, PackageResource } from '@umbraco-cms/backend-api'; +import { tryExecuteAndNotify } from '@umbraco-cms/resources'; +import { UmbNotificationContext, UMB_NOTIFICATION_CONTEXT_TOKEN } from '@umbraco-cms/notification'; @customElement('umb-workspace-package-builder') -export class UmbWorkspacePackageBuilderElement extends LitElement { +export class UmbWorkspacePackageBuilderElement extends UmbLitElement { static styles = [ UUITextStyles, css` :host { display: block; - width: 100%; height: 100%; } + + .header { + margin: 0 var(--uui-size-layout-1); + display: flex; + gap: var(--uui-size-space-4); + } + + uui-box { + margin: var(--uui-size-layout-1); + } + + uui-checkbox { + margin-top: var(--uui-size-space-4); + } `, ]; + @property() + entityKey?: string; + + @state() + private _package: PackageDefinitionModel = {}; + + @query('#package-name-input') + private _packageNameInput!: UUIInputElement; + + private _notificationContext?: UmbNotificationContext; + + constructor() { + super(); + this.consumeContext(UMB_NOTIFICATION_CONTEXT_TOKEN, (instance) => { + this._notificationContext = instance; + }); + } + + connectedCallback(): void { + super.connectedCallback(); + if (this.entityKey) this.#getPackageCreated(); + } + + async #getPackageCreated() { + if (!this.entityKey) return; + const { data } = await tryExecuteAndNotify(this, PackageResource.getPackageCreatedByKey({ key: this.entityKey })); + if (!data) return; + this._package = data as PackageDefinitionModel; + } + + async #download() { + if (!this._package?.key) return; + const response = await tryExecuteAndNotify( + this, + PackageResource.getPackageCreatedByKeyDownload({ key: this._package.key }) + ); + } + + #nameDefined() { + const valid = this._packageNameInput.checkValidity(); + if (!valid) this._notificationContext?.peek('danger', { data: { message: 'Package missing a name' } }); + return valid; + } + + async #save() { + if (!this.#nameDefined()) return; + const response = await tryExecuteAndNotify( + this, + PackageResource.postPackageCreated({ requestBody: this._package }) + ); + if (!response.data || response.error) return; + this._package = response.data as PackageDefinitionModel; + this.#navigateBack(); + } + + async #update() { + if (!this.#nameDefined()) return; + if (!this._package?.key) return; + const response = await tryExecuteAndNotify( + this, + PackageResource.putPackageCreatedByKey({ key: this._package.key, requestBody: this._package }) + ); + + if (response.error) return; + this.#navigateBack(); + } + + #navigateBack() { + window.history.pushState({}, '', '/section/packages/view/created'); + } + render() { - return html`PACKAGE BUILDER `; + return html` + + ${this.#renderHeader()} + ${this.#renderEditors()} + ${this.#renderActions()} + + `; + } + + #renderHeader() { + return html`
+ + + + +
`; + } + + #renderActions() { + return html`
+ ${this._package?.key + ? html` + Download + ` + : nothing} + + Save + +
`; + } + + #renderEditors() { + return html` + ${this.#renderContentSection()} + + + ${this.#renderMediaSection()} + + + + ${this.#renderDocumentTypeSection()} + + + + ${this.#renderMediaTypeSection()} + + + + ${this.#renderLanguageSection()} + + + + ${this.#renderDictionarySection()} + + + + ${this.#renderDataTypeSection()} + + + + ${this.#renderTemplateSection()} + + + + ${this.#renderStylesheetsSection()} + + + + ${this.#renderScriptsSection()} + + + + ${this.#renderPartialViewSection()} + `; + } + + #renderContentSection() { + return html` +
+ + + + Include child nodes + +
+ `; + } + + #renderMediaSection() { + return html` +
+ + + Include child nodes + +
+ `; + } + + #renderDocumentTypeSection() { + return html`
+ +
`; + } + + #renderMediaTypeSection() { + return html`
+ +
`; + } + + #renderLanguageSection() { + return html`
+ +
`; + } + + #renderDictionarySection() { + return html`
+ +
`; + } + + #renderDataTypeSection() { + return html`
+ +
`; + } + + #renderTemplateSection() { + return html`
+ +
`; + } + + #renderStylesheetsSection() { + return html`
+ +
`; + } + + #renderScriptsSection() { + return html`
+ +
`; + } + + #renderPartialViewSection() { + return html`
+ +
`; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-repo/workspace/workspace-package.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-repo/workspace/workspace-package.element.ts index a11b56636c..466915fa9d 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-repo/workspace/workspace-package.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-repo/workspace/workspace-package.element.ts @@ -1,22 +1,55 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { css, html, LitElement } from 'lit'; -import { customElement } from 'lit/decorators.js'; +import { customElement, property, state } from 'lit/decorators.js'; +import { path, stripSlash } from 'router-slot'; @customElement('umb-workspace-package') export class UmbWorkspacePackageElement extends LitElement { static styles = [ UUITextStyles, css` - :host { - display: block; - width: 100%; - height: 100%; + .header { + display: flex; + font-size: var(--uui-type-h5-size); } `, ]; + @property() + entityKey?: string; + + @state() + _package?: any; + + connectedCallback(): void { + super.connectedCallback(); + if (this.entityKey) this._getPackageData(); + } + + private _getPackageData() { + //TODO + + this._package = { + key: this.entityKey, + name: 'A created package', + }; + } + + private _navigateBack() { + window.history.pushState({}, '', '/section/packages/view/installed'); + } + + private _renderHeader() { + return html`
+ + + ${this._package.name ?? 'Package name'} + +
`; + } + render() { - return html`PACKAGE Workspace `; + return html` ${this._renderHeader()} `; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-section/views/created/created-packages-section-view.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-section/views/created/created-packages-section-view.element.ts index 24d577c5be..44beef5a18 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-section/views/created/created-packages-section-view.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-section/views/created/created-packages-section-view.element.ts @@ -1,8 +1,8 @@ -import { html } from 'lit'; +import { css, html } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { IRoute, IRoutingInfo } from 'router-slot'; -import type { ManifestWorkspace } from '@umbraco-cms/models'; -import { createExtensionElement , umbExtensionsRegistry } from '@umbraco-cms/extensions-api'; +import type { ManifestTree, ManifestWorkspace } from '@umbraco-cms/models'; +import { createExtensionElement, umbExtensionsRegistry } from '@umbraco-cms/extensions-api'; import { UmbLitElement } from '@umbraco-cms/element'; @customElement('umb-created-packages-section-view') @@ -12,9 +12,10 @@ export class UmbCreatedPackagesSectionViewElement extends UmbLitElement { private _workspaces: Array = []; + private _trees: Array = []; + constructor() { super(); - this.observe(umbExtensionsRegistry?.extensionsOfType('workspace'), (workspaceExtensions) => { this._workspaces = workspaceExtensions; this._createRoutes(); @@ -48,7 +49,7 @@ export class UmbCreatedPackagesSectionViewElement extends UmbLitElement { routes.push({ path: '**', - redirectTo: 'section/packages/view/created/overview', //TODO: this should be dynamic + redirectTo: 'overview', }); this._routes = routes; } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-section/views/created/packages-created-item.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-section/views/created/packages-created-item.element.ts deleted file mode 100644 index 941a137a86..0000000000 --- a/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-section/views/created/packages-created-item.element.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { html, LitElement } from 'lit'; -import { customElement, property } from 'lit/decorators.js'; - -@customElement('umb-packages-created-item') -export class UmbPackagesCreatedItem extends LitElement { - @property({ type: Object }) - package!: any; - - render() { - return html` - - `; - } - - private _onClick() { - window.history.pushState({}, '', `/section/packages/view/created/packageBuilder/${this.package.key}`); - } -} - -declare global { - interface HTMLElementTagNameMap { - 'umb-packages-created-item': UmbPackagesCreatedItem; - } -} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-section/views/created/packages-created-overview.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-section/views/created/packages-created-overview.element.ts index b57d787db1..20b33ad3f8 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-section/views/created/packages-created-overview.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-section/views/created/packages-created-overview.element.ts @@ -1,35 +1,158 @@ -import { html, LitElement } from 'lit'; +import { html, css, nothing } from 'lit'; +import { ifDefined } from 'lit/directives/if-defined.js'; import { customElement, state } from 'lit/decorators.js'; import { repeat } from 'lit/directives/repeat.js'; - -import './packages-created-item.element'; +import { UUIPaginationEvent } from '@umbraco-ui/uui'; +import { PackageDefinitionModel, PackageResource } from '@umbraco-cms/backend-api'; +import { UmbLitElement } from '@umbraco-cms/element'; +import { tryExecuteAndNotify } from '@umbraco-cms/resources'; +import { UmbModalContext, UMB_MODAL_CONTEXT_TOKEN } from '@umbraco-cms/modal'; @customElement('umb-packages-created-overview') -export class UmbPackagesCreatedOverviewElement extends LitElement { - // TODO: implement call to backend - // TODO: add correct model for created packages - @state() - private _createdPackages: any[] = [ - { - alias: 'my.package', - key: '2a0181ec-244b-4068-a1d7-2f95ed7e6da6', - name: 'A created package', - plans: [], - version: '1.0.0', - }, +export class UmbPackagesCreatedOverviewElement extends UmbLitElement { + static styles = [ + css` + :host { + display: block; + margin: var(--uui-size-layout-1); + } + uui-box { + margin: var(--uui-size-space-5) 0; + padding-bottom: var(--uui-size-space-1); + } + + .no-packages { + display: flex; + justify-content: space-around; + } + uui-pagination { + display: inline-block; + } + + .pagination, + .loading { + display: flex; + justify-content: center; + } + `, ]; + private take = 20; + + @state() + private _loading = true; + + @state() + private _createdPackages: PackageDefinitionModel[] = []; + + @state() + private _currentPage = 1; + + @state() + private _total?: number; + + private _modalContext?: UmbModalContext; + + constructor() { + super(); + } + + connectedCallback(): void { + super.connectedCallback(); + this.#getPackages(); + + this.consumeContext(UMB_MODAL_CONTEXT_TOKEN, (instance) => { + this._modalContext = instance; + }); + } + + async #getPackages() { + const skip = this._currentPage * this.take - this.take; + const { data } = await tryExecuteAndNotify(this, PackageResource.getPackageCreated({ skip, take: this.take })); + if (data) { + this._total = data.total; + this._createdPackages = data.items; + } + this._loading = false; + } + + #createNewPackage() { + window.history.pushState({}, '', `/section/packages/view/created/package-builder`); + } + render() { - return html` + return html` + Create package + + ${this._loading ? html`` : this.#renderCreatedPackages()} + ${this.#renderPagination()}`; + } + + #renderCreatedPackages() { + if (!this._createdPackages.length) return html`

No packages have been created yet

`; + + return html` ${repeat( this._createdPackages, (item) => item.key, - (item) => html`` + (item) => this.#renderPackageItem(item) )} `; } + + #renderPackageItem(p: PackageDefinitionModel) { + return html` + + this.#deletePackage(p)} label="Delete package"> + + + + `; + } + + #packageBuilder(p: PackageDefinitionModel) { + if (!p.key) return; + window.history.pushState({}, '', `/section/packages/view/created/package-builder/${p.key}`); + } + + #renderPagination() { + if (!this._total) return nothing; + const totalPages = Math.ceil(this._total / this.take); + if (totalPages <= 1) return nothing; + return html``; + } + + #onPageChange(event: UUIPaginationEvent) { + if (this._currentPage === event.target.current) return; + this._currentPage = event.target.current; + this.#getPackages(); + } + + async #deletePackage(p: PackageDefinitionModel) { + if (!p.key) return; + const modalHandler = this._modalContext?.confirm({ + color: 'danger', + headline: `Remove ${p.name}?`, + content: 'Are you sure you want to delete this package', + confirmLabel: 'Delete', + }); + + const deleteConfirmed = await modalHandler?.onClose().then(({ confirmed }: any) => { + return confirmed; + }); + + if (!deleteConfirmed == true) return; + + const { error } = await tryExecuteAndNotify(this, PackageResource.deletePackageCreatedByKey({ key: p.key })); + if (error) return; + const index = this._createdPackages.findIndex((x) => x.key === p.key); + this._createdPackages.splice(index, 1); + this.requestUpdate(); + } } export default UmbPackagesCreatedOverviewElement; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-section/views/installed/installed-packages-section-view-item.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-section/views/installed/installed-packages-section-view-item.element.ts index 1dca4ecea2..3df5afd999 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-section/views/installed/installed-packages-section-view-item.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-section/views/installed/installed-packages-section-view-item.element.ts @@ -1,27 +1,54 @@ -import { html, nothing } from 'lit'; -import { customElement, property, state } from 'lit/decorators.js'; +import { html, css, nothing } from 'lit'; import { ifDefined } from 'lit/directives/if-defined.js'; +import { customElement, property, state } from 'lit/decorators.js'; import { firstValueFrom, map } from 'rxjs'; +import { UUIButtonState } from '@umbraco-ui/uui'; import { UmbModalContext, UMB_MODAL_CONTEXT_TOKEN } from '../../../../../core/modal'; import { createExtensionElement, umbExtensionsRegistry } from '@umbraco-cms/extensions-api'; -import type { ManifestPackageView, UmbPackage } from '@umbraco-cms/models'; +import type { ManifestPackageView } from '@umbraco-cms/models'; import { UmbLitElement } from '@umbraco-cms/element'; +import { tryExecuteAndNotify } from '@umbraco-cms/resources'; +import { PackageResource } from '@umbraco-cms/backend-api'; +import { UmbNotificationContext, UMB_NOTIFICATION_CONTEXT_TOKEN } from '@umbraco-cms/notification'; @customElement('umb-installed-packages-section-view-item') -export class UmbInstalledPackagesSectionViewItemElement extends UmbLitElement { - @property({ type: Object }) - package!: UmbPackage; +export class UmbInstalledPackagesSectionViewItem extends UmbLitElement { + static styles = css` + :host { + display: flex; + min-height: 47px; + } + `; + + @property() + name?: string; + + @property() + version?: string; + + @property() + hasPendingMigrations = false; + + @property() + customIcon?: string; + + @state() + private _migrationButtonState?: UUIButtonState; @state() private _packageView?: ManifestPackageView; + private _notificationContext?: UmbNotificationContext; private _modalContext?: UmbModalContext; constructor() { super(); + this.consumeContext(UMB_NOTIFICATION_CONTEXT_TOKEN, (instance) => { + this._notificationContext = instance; + }); this.consumeContext(UMB_MODAL_CONTEXT_TOKEN, (instance) => { this._modalContext = instance; }); @@ -30,8 +57,8 @@ export class UmbInstalledPackagesSectionViewItemElement extends UmbLitElement { connectedCallback(): void { super.connectedCallback(); - if (this.package.name?.length) { - this.findPackageView(this.package.name); + if (this.name?.length) { + this.findPackageView(this.name); } } @@ -52,18 +79,51 @@ export class UmbInstalledPackagesSectionViewItemElement extends UmbLitElement { this._packageView = views[0]; } + async _onMigration() { + if (!this.name) return; + const modalHandler = this._modalContext?.confirm({ + color: 'positive', + headline: `Run migrations for ${this.name}?`, + content: `Do you want to start run migrations for ${this.name}`, + confirmLabel: 'Run migrations', + }); + + const migrationConfirmed = await modalHandler?.onClose().then(({ confirmed }: any) => { + return confirmed; + }); + + if (!migrationConfirmed == true) return; + 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 html` - - - ${this._packageView + + ${this.customIcon ? html`` : nothing} +
+ ${this.hasPendingMigrations ? html`` + label="Run pending package migrations"> + Run pending migrations + ` : nothing} - +
`; } @@ -81,12 +141,16 @@ export class UmbInstalledPackagesSectionViewItemElement extends UmbLitElement { return; } - this._modalContext?.open(element, { data: this.package, size: 'small', type: 'sidebar' }); + this._modalContext?.open(element, { + data: { name: this.name, version: this.version }, + size: 'full', + type: 'sidebar', + }); } } declare global { interface HTMLElementTagNameMap { - 'umb-installed-packages-section-view-item': UmbInstalledPackagesSectionViewItemElement; + 'umb-installed-packages-section-view-item': UmbInstalledPackagesSectionViewItem; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-section/views/installed/installed-packages-section-view.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-section/views/installed/installed-packages-section-view.element.ts index 256760912e..08449e0cad 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-section/views/installed/installed-packages-section-view.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-section/views/installed/installed-packages-section-view.element.ts @@ -1,23 +1,56 @@ -import { html } from 'lit'; +import { html, css, nothing } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { repeat } from 'lit/directives/repeat.js'; +import { combineLatest } from 'rxjs'; +import { UUITextStyles } from '@umbraco-ui/uui-css'; import { UmbPackageRepository } from '../../../repository/package.repository'; -import type { UmbPackage } from '@umbraco-cms/models'; import { UmbLitElement } from '@umbraco-cms/element'; +import type { UmbPackageWithMigrationStatus } from '@umbraco-cms/models'; import './installed-packages-section-view-item.element'; @customElement('umb-installed-packages-section-view') export class UmbInstalledPackagesSectionView extends UmbLitElement { - @state() - private _installedPackages: UmbPackage[] = []; + static styles = [ + UUITextStyles, + css` + :host { + display: block; + margin: var(--uui-size-layout-1); + } + uui-box { + margin-top: var(--uui-size-space-5); + padding-bottom: var(--uui-size-space-1); + } - private repository: UmbPackageRepository; + umb-installed-packages-section-view-item { + padding: var(--uui-size-space-3) 0 var(--uui-size-space-2); + } + + umb-installed-packages-section-view-item:not(:first-child) { + border-top: 1px solid var(--uui-color-border, #d8d7d9); + } + + .no-packages { + display: flex; + justify-content: space-around; + flex-direction: column; + align-items: center; + } + `, + ]; + + @state() + private _installedPackages: UmbPackageWithMigrationStatus[] = []; + + @state() + private _migrationPackages: UmbPackageWithMigrationStatus[] = []; + + #packageRepository: UmbPackageRepository; constructor() { super(); - - this.repository = new UmbPackageRepository(this); + this.#packageRepository = new UmbPackageRepository(this); } firstUpdated() { @@ -28,20 +61,77 @@ export class UmbInstalledPackagesSectionView extends UmbLitElement { * Fetch the installed packages from the server */ private async _loadInstalledPackages() { - const package$ = await this.repository.rootItems(); - package$.subscribe((packages) => { - this._installedPackages = packages.filter((p) => !!p.name); + const data = await Promise.all([this.#packageRepository.rootItems(), this.#packageRepository.migrations()]); + + const [package$, migration$] = data; + + combineLatest([package$, migration$]).subscribe(([packages, migrations]) => { + this._installedPackages = packages.map((p) => { + const migration = migrations.find((m) => m.packageName === p.name); + if (migration) { + // Remove that migration from the list + migrations = migrations.filter((m) => m.packageName !== p.name); + } + + return { + ...p, + hasPendingMigrations: migration?.hasPendingMigrations ?? false, + }; + }); + + 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, + })), + ];*/ }); } render() { - return html` + 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 +

+
`; + } + + private _renderInstalled() { + return html` ${repeat( this._installedPackages, (item) => item.name, - (item) => - html`` + (item) => html`` + )} + + `; + } + + private _renderCustomMigrations() { + if (!this._migrationPackages) return; + return html` + + ${repeat( + this._migrationPackages, + (item) => item.name, + (item) => html`` )} `; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/packages/repository/package.repository.ts b/src/Umbraco.Web.UI.Client/src/backoffice/packages/repository/package.repository.ts index ec54c779b4..61c8e33cdd 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/packages/repository/package.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/packages/repository/package.repository.ts @@ -39,7 +39,8 @@ export class UmbPackageRepository { const { data: packages } = await this.#packageSource.getRootItems(); if (packages) { - store.appendItems(packages); + // Append packages to the store but only if they have a name + store.appendItems(packages.filter((p) => p.name?.length)); const extensions: ManifestBase[] = []; packages.forEach((p) => { diff --git a/src/Umbraco.Web.UI.Client/src/core/mocks/browser-handlers.ts b/src/Umbraco.Web.UI.Client/src/core/mocks/browser-handlers.ts index 42d9c200ce..014a4e8c61 100644 --- a/src/Umbraco.Web.UI.Client/src/core/mocks/browser-handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/core/mocks/browser-handlers.ts @@ -24,6 +24,7 @@ import { handlers as templateHandlers } from './domains/template.handlers'; import { handlers as languageHandlers } from './domains/language.handlers'; import { handlers as cultureHandlers } from './domains/culture.handlers'; import { handlers as redirectManagementHandlers } from './domains/redirect-management.handlers'; +import { handlers as packageHandlers } from './domains/package.handlers'; const handlers = [ serverHandlers.serverVersionHandler, @@ -51,6 +52,7 @@ const handlers = [ ...languageHandlers, ...cultureHandlers, ...redirectManagementHandlers, + ...packageHandlers, ]; switch (import.meta.env.VITE_UMBRACO_INSTALL_STATUS) { diff --git a/src/Umbraco.Web.UI.Client/src/core/mocks/domains/package.handlers.ts b/src/Umbraco.Web.UI.Client/src/core/mocks/domains/package.handlers.ts new file mode 100644 index 0000000000..c056cc616a --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/core/mocks/domains/package.handlers.ts @@ -0,0 +1,126 @@ +import { rest } from 'msw'; +import { v4 as uuidv4 } from 'uuid'; + +import { umbracoPath } from '@umbraco-cms/utils'; +import { + PackageCreateModel, + PackageDefinitionModel, + PagedPackageDefinitionModel, + PagedPackageMigrationStatusModel, +} from '@umbraco-cms/backend-api'; + +export const handlers = [ + rest.get(umbracoPath('/package/migration-status'), (_req, res, ctx) => { + return res( + // Respond with a 200 status code + ctx.status(200), + ctx.json({ + total: 3, + items: [ + { + hasPendingMigrations: true, + packageName: 'Named Package', + }, + { + hasPendingMigrations: true, + packageName: 'My Custom Migration', + }, + { + hasPendingMigrations: false, + packageName: 'Package with a view', + }, + ], + }) + ); + }), + + rest.post(umbracoPath('/package/:name/run-migration'), async (_req, res, ctx) => { + const name = _req.params.name as string; + if (!name) return res(ctx.status(404)); + return res(ctx.status(200)); + }), + + rest.get(umbracoPath('/package/created'), async (_req, res, ctx) => { + // read all + return res( + ctx.status(200), + ctx.json({ + total: packageArray.length, + items: packageArray, + }) + ); + }), + + rest.post(umbracoPath('/package/created'), async (_req, res, ctx) => { + //save + const data: PackageCreateModel = await _req.json(); + const newPackage: PackageDefinitionModel = { ...data, key: uuidv4() }; + packageArray.push(newPackage); + return res(ctx.status(200), ctx.json(newPackage)); + }), + + rest.get(umbracoPath('/package/created/:key'), (_req, res, ctx) => { + //read 1 + const key = _req.params.key as string; + if (!key) return res(ctx.status(404)); + const found = packageArray.find((p) => p.key == key); + if (!found) return res(ctx.status(404)); + return res(ctx.status(200), ctx.json(found)); + }), + + rest.put(umbracoPath('/package/created/:key'), async (_req, res, ctx) => { + //update + const data: PackageDefinitionModel = await _req.json(); + if (!data.key) return; + const index = packageArray.findIndex((x) => x.key === data.key); + packageArray[index] = data; + return res(ctx.status(200)); + }), + + rest.delete(umbracoPath('/package/created/:key'), (_req, res, ctx) => { + //delete + const key = _req.params.key as string; + if (!key) return res(ctx.status(404)); + const index = packageArray.findIndex((p) => p.key == key); + if (index <= -1) return res(ctx.status(404)); + packageArray.splice(index, 1); + return res(ctx.status(200)); + }), + + rest.get(umbracoPath('/package/created/:key/download'), (_req, res, ctx) => { + //download + return res(ctx.status(200)); + }), +]; + +const packageArray: PackageDefinitionModel[] = [ + { + key: '2a0181ec-244b-4068-a1d7-2f95ed7e6da6', + packagePath: undefined, + name: 'My Package', + //contentNodeId?: string | null; + //contentLoadChildNodes?: boolean; + //mediaKeys?: Array; + //mediaLoadChildNodes?: boolean; + //documentTypes?: Array; + //mediaTypes?: Array; + //dataTypes?: Array; + //templates?: Array; + //partialViews?: Array; + //stylesheets?: Array; + //scripts?: Array; + //languages?: Array; + //dictionaryItems?: Array; + }, + { + key: '2a0181ec-244b-4068-a1d7-2f95ed7e6da7', + packagePath: undefined, + name: 'My Second Package', + }, + + { + key: '2a0181ec-244b-4068-a1d7-2f95ed7e6da8', + packagePath: undefined, + name: 'My Third Package', + }, +]; diff --git a/src/Umbraco.Web.UI.Client/src/core/mocks/e2e-handlers.ts b/src/Umbraco.Web.UI.Client/src/core/mocks/e2e-handlers.ts index 2c9ab05627..eb8be4c283 100644 --- a/src/Umbraco.Web.UI.Client/src/core/mocks/e2e-handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/core/mocks/e2e-handlers.ts @@ -13,6 +13,7 @@ import { handlers as profileHandlers } from './domains/performance-profiling.han import { handlers as healthCheckHandlers } from './domains/health-check.handlers'; import { handlers as languageHandlers } from './domains/language.handlers'; import { handlers as redirectManagementHandlers } from './domains/redirect-management.handlers'; +import { handlers as packageHandlers } from './domains/package.handlers'; export const handlers = [ serverHandlers.serverRunningHandler, @@ -31,4 +32,5 @@ export const handlers = [ ...healthCheckHandlers, ...languageHandlers, ...redirectManagementHandlers, + ...packageHandlers, ]; diff --git a/src/Umbraco.Web.UI.Client/src/core/modal/layouts/content-picker/modal-layout-content-picker.element.ts b/src/Umbraco.Web.UI.Client/src/core/modal/layouts/content-picker/modal-layout-content-picker.element.ts index 72d991c39d..cc00f957aa 100644 --- a/src/Umbraco.Web.UI.Client/src/core/modal/layouts/content-picker/modal-layout-content-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/core/modal/layouts/content-picker/modal-layout-content-picker.element.ts @@ -5,7 +5,7 @@ import { UmbModalLayoutElement } from '../modal-layout.element'; export interface UmbModalContentPickerData { multiple?: boolean; - selection: Array; + selection?: Array; } import { UmbTreeElement } from '../../../../backoffice/shared/components/tree/tree.element';