diff --git a/src/Umbraco.Web.UI.Client/.env b/src/Umbraco.Web.UI.Client/.env index dadbe466c0..6042061013 100644 --- a/src/Umbraco.Web.UI.Client/.env +++ b/src/Umbraco.Web.UI.Client/.env @@ -3,3 +3,4 @@ VITE_UMBRACO_USE_MSW=on # on = turns on MSW, off = disables all mock handlers VITE_UMBRACO_API_URL=http://localhost:11000 VITE_UMBRACO_INSTALL_STATUS=running # running or must-install or must-upgrade VITE_MSW_QUIET=off # on = turns off MSW console logs, off = turns on MSW console logs +VITE_UMBRACO_EXTENSION_MOCKS=off # on = turns on extension mocks, off = turns off extension mocks diff --git a/src/Umbraco.Web.UI.Client/.github/CONTRIBUTING.md b/src/Umbraco.Web.UI.Client/.github/CONTRIBUTING.md index e38509ec18..38b8362ab1 100644 --- a/src/Umbraco.Web.UI.Client/.github/CONTRIBUTING.md +++ b/src/Umbraco.Web.UI.Client/.github/CONTRIBUTING.md @@ -50,7 +50,7 @@ The frontend has an API formatter that takes the OpenAPI schema file and convert ### Example: Published Cache Status Dashboard -![Published Status Dashboard](.github/images/contributing/published-cache-status-dashboard.png) +![Published Status Dashboard](/.github/images/contributing/published-cache-status-dashboard.png) ### Boilerplate (example using Lit) @@ -155,7 +155,7 @@ Let’s go through each of these properties… Running the app with `npm run dev`, you will quickly notice the API requests turn into 404 errors. In order to hit the API, we need to add a mock handler to define the endpoints which our dashboard will call. In the case of the Published Cache Status section, we have a number of calls to work through. Let’s start by looking at the call to retrieve the current status of the cache: -![Published Status Dashboard](.github/images/contributing/status-of-cache.png) +![Published Status Dashboard](/.github/images/contributing/status-of-cache.png) From the existing functionality, we can see that this is a string message that is received as part of a `GET` request from the server. @@ -184,7 +184,7 @@ It returns a `200 OK` response and a string value with the current “status” An example `POST` is similar. Let’s take the “Refresh status” button as an example: -![Published Status Dashboard](.github/images/contributing/refresh-status.png) +![Published Status Dashboard](/.github/images/contributing/refresh-status.png) From our existing functionality we can see that this makes a `POST`call to the server to prompt a reload of the published cache. So we would add a new endpoint to the mock handler that would look like: 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 d652f4523b..1a5f7a1df3 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 @@ -84,6 +84,7 @@ export type { OkResultModel } from './models/OkResultModel'; export { OperatorModel } from './models/OperatorModel'; export type { OutOfDateStatusModel } from './models/OutOfDateStatusModel'; export { OutOfDateTypeModel } from './models/OutOfDateTypeModel'; +export type { PackageMigrationStatusModel } from './models/PackageMigrationStatusModel'; export type { PagedContentTreeItemModel } from './models/PagedContentTreeItemModel'; export type { PagedCultureModel } from './models/PagedCultureModel'; export type { PagedDictionaryOverviewModel } from './models/PagedDictionaryOverviewModel'; @@ -100,6 +101,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 { PagedPackageMigrationStatusModel } from './models/PagedPackageMigrationStatusModel'; export type { PagedRecycleBinItemModel } from './models/PagedRecycleBinItemModel'; export type { PagedRedirectUrlModel } from './models/PagedRedirectUrlModel'; export type { PagedRelationItemModel } from './models/PagedRelationItemModel'; @@ -172,6 +174,7 @@ export { MediaTypeResource } from './services/MediaTypeResource'; export { MemberGroupResource } from './services/MemberGroupResource'; export { MemberTypeResource } from './services/MemberTypeResource'; export { ModelsBuilderResource } from './services/ModelsBuilderResource'; +export { PackageResource } from './services/PackageResource'; export { PartialViewResource } from './services/PartialViewResource'; export { ProfilingResource } from './services/ProfilingResource'; export { PublishedCacheResource } from './services/PublishedCacheResource'; diff --git a/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PackageCreateModel.ts b/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PackageCreateModel.ts new file mode 100644 index 0000000000..4061ed4560 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PackageCreateModel.ts @@ -0,0 +1,8 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { PackageModelBaseModel } from './PackageModelBaseModel'; + +export type PackageCreateModel = PackageModelBaseModel; + diff --git a/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PackageDefinitionModel.ts b/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PackageDefinitionModel.ts new file mode 100644 index 0000000000..70f174f33d --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PackageDefinitionModel.ts @@ -0,0 +1,11 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { PackageModelBaseModel } from './PackageModelBaseModel'; + +export type PackageDefinitionModel = (PackageModelBaseModel & { + key?: string; + packagePath?: string; +}); + diff --git a/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PackageMigrationStatusModel.ts b/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PackageMigrationStatusModel.ts new file mode 100644 index 0000000000..a0317649c5 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PackageMigrationStatusModel.ts @@ -0,0 +1,9 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +export type PackageMigrationStatusModel = { + packageName?: string; + hasPendingMigrations?: boolean; +}; + diff --git a/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PackageModelBaseModel.ts b/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PackageModelBaseModel.ts new file mode 100644 index 0000000000..a405b0ecc2 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PackageModelBaseModel.ts @@ -0,0 +1,21 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +export type PackageModelBaseModel = { + name?: string; + 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; +}; + diff --git a/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PackageUpdateModel.ts b/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PackageUpdateModel.ts new file mode 100644 index 0000000000..e8bbd052fe --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PackageUpdateModel.ts @@ -0,0 +1,10 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { PackageModelBaseModel } from './PackageModelBaseModel'; + +export type PackageUpdateModel = (PackageModelBaseModel & { + packagePath?: string; +}); + diff --git a/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PagedPackageDefinitionModel.ts b/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PagedPackageDefinitionModel.ts new file mode 100644 index 0000000000..3a596e659a --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PagedPackageDefinitionModel.ts @@ -0,0 +1,11 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { PackageDefinitionModel } from './PackageDefinitionModel'; + +export type PagedPackageDefinitionModel = { + total: number; + items: Array; +}; + diff --git a/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PagedPackageMigrationStatusModel.ts b/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PagedPackageMigrationStatusModel.ts new file mode 100644 index 0000000000..b9a95529d8 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/backend-api/src/models/PagedPackageMigrationStatusModel.ts @@ -0,0 +1,11 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { PackageMigrationStatusModel } from './PackageMigrationStatusModel'; + +export type PagedPackageMigrationStatusModel = { + total: number; + items: Array; +}; + diff --git a/src/Umbraco.Web.UI.Client/libs/backend-api/src/services/PackageResource.ts b/src/Umbraco.Web.UI.Client/libs/backend-api/src/services/PackageResource.ts new file mode 100644 index 0000000000..cc80617938 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/backend-api/src/services/PackageResource.ts @@ -0,0 +1,190 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { PackageCreateModel } from '../models/PackageCreateModel'; +import type { PackageDefinitionModel } from '../models/PackageDefinitionModel'; +import type { PackageUpdateModel } from '../models/PackageUpdateModel'; +import type { PagedPackageDefinitionModel } from '../models/PagedPackageDefinitionModel'; +import type { PagedPackageMigrationStatusModel } from '../models/PagedPackageMigrationStatusModel'; + +import type { CancelablePromise } from '../core/CancelablePromise'; +import { OpenAPI } from '../core/OpenAPI'; +import { request as __request } from '../core/request'; + +export class PackageResource { + + /** + * @returns any Success + * @throws ApiError + */ + public static postPackageByNameRunMigration({ + name, + }: { + name: string, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/umbraco/management/api/v1/package/{name}/run-migration', + path: { + 'name': name, + }, + errors: { + 404: `Not Found`, + 409: `Conflict`, + }, + }); + } + + /** + * @returns PagedPackageDefinitionModel Success + * @throws ApiError + */ + public static getPackageCreated({ + skip, + take = 100, + }: { + skip?: number, + take?: number, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/umbraco/management/api/v1/package/created', + query: { + 'skip': skip, + 'take': take, + }, + }); + } + + /** + * @returns string Created + * @throws ApiError + */ + public static postPackageCreated({ + requestBody, + }: { + requestBody?: PackageCreateModel, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/umbraco/management/api/v1/package/created', + body: requestBody, + mediaType: 'application/json', + responseHeader: 'Location', + errors: { + 400: `Bad Request`, + 404: `Not Found`, + }, + }); + } + + /** + * @returns any Success + * @throws ApiError + */ + public static getPackageCreatedByKey({ + key, + }: { + key: string, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/umbraco/management/api/v1/package/created/{key}', + path: { + 'key': key, + }, + errors: { + 404: `Not Found`, + }, + }); + } + + /** + * @returns any Success + * @throws ApiError + */ + public static deletePackageCreatedByKey({ + key, + }: { + key: string, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'DELETE', + url: '/umbraco/management/api/v1/package/created/{key}', + path: { + 'key': key, + }, + errors: { + 404: `Not Found`, + }, + }); + } + + /** + * @returns any Success + * @throws ApiError + */ + public static putPackageCreatedByKey({ + key, + requestBody, + }: { + key: string, + requestBody?: PackageUpdateModel, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'PUT', + url: '/umbraco/management/api/v1/package/created/{key}', + path: { + 'key': key, + }, + body: requestBody, + mediaType: 'application/json', + errors: { + 404: `Not Found`, + }, + }); + } + + /** + * @returns binary Success + * @throws ApiError + */ + public static getPackageCreatedByKeyDownload({ + key, + }: { + key: string, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/umbraco/management/api/v1/package/created/{key}/download', + path: { + 'key': key, + }, + errors: { + 404: `Not Found`, + }, + }); + } + + /** + * @returns PagedPackageMigrationStatusModel Success + * @throws ApiError + */ + public static getPackageMigrationStatus({ + skip, + take = 100, + }: { + skip?: number, + take?: number, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/umbraco/management/api/v1/package/migration-status', + query: { + 'skip': skip, + 'take': take, + }, + }); + } + +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/action.ts b/src/Umbraco.Web.UI.Client/libs/entity-action/action.ts similarity index 91% rename from src/Umbraco.Web.UI.Client/src/backoffice/shared/action.ts rename to src/Umbraco.Web.UI.Client/libs/entity-action/action.ts index ddbb8e783f..70c4a25985 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/action.ts +++ b/src/Umbraco.Web.UI.Client/libs/entity-action/action.ts @@ -2,7 +2,8 @@ import { UmbControllerHostInterface } from '@umbraco-cms/controller'; import { umbExtensionsRegistry, createExtensionClass } from '@umbraco-cms/extensions-api'; import { UmbObserverController } from '@umbraco-cms/observable-api'; -export interface UmbAction { +export interface UmbAction { + host: UmbControllerHostInterface; repository: RepositoryType; execute(): Promise; } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/entity-actions/copy/copy.action.ts b/src/Umbraco.Web.UI.Client/libs/entity-action/actions/copy/copy.action.ts similarity index 86% rename from src/Umbraco.Web.UI.Client/src/backoffice/shared/entity-actions/copy/copy.action.ts rename to src/Umbraco.Web.UI.Client/libs/entity-action/actions/copy/copy.action.ts index 8f8cb804df..ac5995ea1f 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/entity-actions/copy/copy.action.ts +++ b/src/Umbraco.Web.UI.Client/libs/entity-action/actions/copy/copy.action.ts @@ -1,4 +1,4 @@ -import { UmbEntityActionBase } from '..'; +import { UmbEntityActionBase } from '@umbraco-cms/entity-action'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; export class UmbCopyEntityAction }> extends UmbEntityActionBase { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/entity-actions/delete/delete.action.ts b/src/Umbraco.Web.UI.Client/libs/entity-action/actions/delete/delete.action.ts similarity index 94% rename from src/Umbraco.Web.UI.Client/src/backoffice/shared/entity-actions/delete/delete.action.ts rename to src/Umbraco.Web.UI.Client/libs/entity-action/actions/delete/delete.action.ts index 3521026991..ef218b305a 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/entity-actions/delete/delete.action.ts +++ b/src/Umbraco.Web.UI.Client/libs/entity-action/actions/delete/delete.action.ts @@ -1,4 +1,4 @@ -import { UmbEntityActionBase } from '..'; +import { UmbEntityActionBase } from '@umbraco-cms/entity-action'; import { UmbContextConsumerController } from '@umbraco-cms/context-api'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; import { UmbModalService, UMB_MODAL_SERVICE_CONTEXT_TOKEN } from '@umbraco-cms/modal'; diff --git a/src/Umbraco.Web.UI.Client/libs/entity-action/actions/index.ts b/src/Umbraco.Web.UI.Client/libs/entity-action/actions/index.ts new file mode 100644 index 0000000000..b8fa3d3206 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/entity-action/actions/index.ts @@ -0,0 +1,5 @@ +export * from './copy/copy.action'; +export * from './delete/delete.action'; +export * from './move/move.action'; +export * from './sort-children-of/sort-children-of.action'; +export * from './trash/trash.action'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/entity-actions/move/move.action.ts b/src/Umbraco.Web.UI.Client/libs/entity-action/actions/move/move.action.ts similarity index 86% rename from src/Umbraco.Web.UI.Client/src/backoffice/shared/entity-actions/move/move.action.ts rename to src/Umbraco.Web.UI.Client/libs/entity-action/actions/move/move.action.ts index 7b4666ad8c..79c9a20dd1 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/entity-actions/move/move.action.ts +++ b/src/Umbraco.Web.UI.Client/libs/entity-action/actions/move/move.action.ts @@ -1,4 +1,4 @@ -import { UmbEntityActionBase } from '..'; +import { UmbEntityActionBase } from '@umbraco-cms/entity-action'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; export class UmbMoveEntityAction }> extends UmbEntityActionBase { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/entity-actions/sort-children-of/sort-children-of.action.ts b/src/Umbraco.Web.UI.Client/libs/entity-action/actions/sort-children-of/sort-children-of.action.ts similarity index 87% rename from src/Umbraco.Web.UI.Client/src/backoffice/shared/entity-actions/sort-children-of/sort-children-of.action.ts rename to src/Umbraco.Web.UI.Client/libs/entity-action/actions/sort-children-of/sort-children-of.action.ts index 0860f53ad4..002e0b6613 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/entity-actions/sort-children-of/sort-children-of.action.ts +++ b/src/Umbraco.Web.UI.Client/libs/entity-action/actions/sort-children-of/sort-children-of.action.ts @@ -1,4 +1,4 @@ -import { UmbEntityActionBase } from '..'; +import { UmbEntityActionBase } from '@umbraco-cms/entity-action'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; export class UmbSortChildrenOfEntityAction< diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/entity-actions/trash/trash.action.ts b/src/Umbraco.Web.UI.Client/libs/entity-action/actions/trash/trash.action.ts similarity index 94% rename from src/Umbraco.Web.UI.Client/src/backoffice/shared/entity-actions/trash/trash.action.ts rename to src/Umbraco.Web.UI.Client/libs/entity-action/actions/trash/trash.action.ts index 626452118d..822919e123 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/entity-actions/trash/trash.action.ts +++ b/src/Umbraco.Web.UI.Client/libs/entity-action/actions/trash/trash.action.ts @@ -1,4 +1,4 @@ -import { UmbEntityActionBase } from '..'; +import { UmbEntityActionBase } from '@umbraco-cms/entity-action'; import { UmbContextConsumerController } from '@umbraco-cms/context-api'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; import { UmbModalService, UMB_MODAL_SERVICE_CONTEXT_TOKEN } from '@umbraco-cms/modal'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/entity-actions/index.ts b/src/Umbraco.Web.UI.Client/libs/entity-action/entity-action.ts similarity index 88% rename from src/Umbraco.Web.UI.Client/src/backoffice/shared/entity-actions/index.ts rename to src/Umbraco.Web.UI.Client/libs/entity-action/entity-action.ts index 1a39883d37..17b010128b 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/entity-actions/index.ts +++ b/src/Umbraco.Web.UI.Client/libs/entity-action/entity-action.ts @@ -1,4 +1,4 @@ -import { UmbAction, UmbActionBase } from '../action'; +import { UmbAction, UmbActionBase } from './action'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; export interface UmbEntityAction extends UmbAction { diff --git a/src/Umbraco.Web.UI.Client/libs/entity-action/entity-bulk-action.ts b/src/Umbraco.Web.UI.Client/libs/entity-action/entity-bulk-action.ts new file mode 100644 index 0000000000..a75ae2e498 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/entity-action/entity-bulk-action.ts @@ -0,0 +1,20 @@ +import { UmbAction, UmbActionBase } from './action'; +import { UmbControllerHostInterface } from '@umbraco-cms/controller'; + +export interface UmbEntityBulkAction extends UmbAction { + selection: Array; + setSelection(selection: Array): void; +} + +export class UmbEntityBulkActionBase extends UmbActionBase { + selection: Array; + + constructor(host: UmbControllerHostInterface, repositoryAlias: string, selection: Array) { + super(host, repositoryAlias); + this.selection = selection; + } + + setSelection(selection: Array) { + this.selection = selection; + } +} diff --git a/src/Umbraco.Web.UI.Client/libs/entity-action/index.ts b/src/Umbraco.Web.UI.Client/libs/entity-action/index.ts new file mode 100644 index 0000000000..9503bc670b --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/entity-action/index.ts @@ -0,0 +1,4 @@ +export * from './action'; +export * from './entity-action'; +export * from './entity-bulk-action'; +export * from './actions'; diff --git a/src/Umbraco.Web.UI.Client/libs/entity-action/rollup.config.js b/src/Umbraco.Web.UI.Client/libs/entity-action/rollup.config.js new file mode 100644 index 0000000000..945c0afe88 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/entity-action/rollup.config.js @@ -0,0 +1,4 @@ +import config from '../../utils/rollup.config.js'; +export default { + ...config, +}; diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-api/is-manifest-js-type.function.ts b/src/Umbraco.Web.UI.Client/libs/extensions-api/is-manifest-js-type.function.ts index 5f4244f660..24962b7ec0 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-api/is-manifest-js-type.function.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-api/is-manifest-js-type.function.ts @@ -1,6 +1,6 @@ import { ManifestJSType } from './load-extension.function'; import type { ManifestBase } from '@umbraco-cms/extensions-registry'; -export function isManifestJSType(manifest: ManifestBase): manifest is ManifestJSType { +export function isManifestJSType(manifest: ManifestBase | unknown): manifest is ManifestJSType { return (manifest as ManifestJSType).js !== undefined; } diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/menu-item.models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/menu-item.models.ts new file mode 100644 index 0000000000..783713e834 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/menu-item.models.ts @@ -0,0 +1,13 @@ +import type { ManifestElement } from './models'; + +export interface ManifestMenuItem extends ManifestElement { + type: 'menuItem'; + meta: MetaMenuItem; +} + +export interface MetaMenuItem { + label: string; + icon: string; + menus: Array; + entityType?: string; +} diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/menu.models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/menu.models.ts new file mode 100644 index 0000000000..5e5b0906de --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/menu.models.ts @@ -0,0 +1,5 @@ +import type { ManifestElement } from './models'; + +export interface ManifestMenu extends ManifestElement { + type: 'menu'; +} diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts index 4d4eff91e7..47dfd66afc 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/models.ts @@ -11,8 +11,9 @@ import type { ManifestPropertyAction } from './property-action.models'; import type { ManifestPropertyEditorUI, ManifestPropertyEditorModel } from './property-editor.models'; import type { ManifestSection } from './section.models'; import type { ManifestSectionView } from './section-view.models'; -import type { ManifestSidebarMenu } from './sidebar-menu.models'; -import type { ManifestSidebarMenuItem } from './sidebar-menu-item.models'; +import type { ManifestSectionSidebarApp, ManifestMenuSectionSidebarApp } from './section-sidebar-app.models'; +import type { ManifestMenu } from './menu.models'; +import type { ManifestMenuItem } from './menu-item.models'; import type { ManifestTheme } from './theme.models'; import type { ManifestTree } from './tree.models'; import type { ManifestTreeItemAction } from './tree-item-action.models'; @@ -37,8 +38,9 @@ export * from './property-action.models'; export * from './property-editor.models'; export * from './section-view.models'; export * from './section.models'; -export * from './sidebar-menu.models'; -export * from './sidebar-menu-item.models'; +export * from './section-sidebar-app.models'; +export * from './menu.models'; +export * from './menu-item.models'; export * from './theme.models'; export * from './tree-item-action.models'; export * from './tree.models'; @@ -66,9 +68,11 @@ export type ManifestTypes = | ManifestPropertyEditorUI | ManifestRepository | ManifestSection + | ManifestSectionSidebarApp | ManifestSectionView - | ManifestSidebarMenu - | ManifestSidebarMenuItem + | ManifestMenuSectionSidebarApp + | ManifestMenu + | ManifestMenuItem | ManifestTheme | ManifestTree | ManifestTreeItemAction @@ -76,7 +80,8 @@ export type ManifestTypes = | ManifestWorkspace | ManifestWorkspaceAction | ManifestWorkspaceView - | ManifestWorkspaceViewCollection; + | ManifestWorkspaceViewCollection + | ManifestBase; export type ManifestStandardTypes = ManifestTypes['type']; @@ -112,7 +117,7 @@ export interface ManifestElement extends ManifestWithLoader Promise; - meta?: any; + meta?: unknown; } export interface ManifestWithView extends ManifestElement { @@ -131,11 +136,11 @@ export interface ManifestElementWithElementName extends ManifestElement { export interface ManifestCustom extends ManifestBase { type: 'custom'; - meta?: any; + meta?: unknown; } export interface ManifestWithMeta extends ManifestBase { - meta: any; + meta: unknown; } export interface ManifestEntrypoint extends ManifestBase { diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/package-view.models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/package-view.models.ts index bff9d21a0c..9a8e05cdae 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/package-view.models.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/package-view.models.ts @@ -6,5 +6,5 @@ export interface ManifestPackageView extends ManifestElement { } export interface MetaPackageView { - packageAlias: string; + packageName: string; } diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/section-sidebar-app.models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/section-sidebar-app.models.ts new file mode 100644 index 0000000000..544e64021e --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/section-sidebar-app.models.ts @@ -0,0 +1,21 @@ +import type { ManifestElement } from './models'; + +export interface ManifestSectionSidebarApp extends ManifestElement { + type: 'sectionSidebarApp'; + meta: MetaSectionSidebarApp; +} + +export interface MetaSectionSidebarApp { + sections: Array; +} + +// TODO: this is a temp solution until we implement kinds +export interface ManifestMenuSectionSidebarApp extends ManifestElement { + type: 'menuSectionSidebarApp'; + meta: MetaMenuSectionSidebarApp; +} + +export interface MetaMenuSectionSidebarApp extends MetaSectionSidebarApp { + label: string; + menu: string; +} diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/sidebar-menu-item.models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/sidebar-menu-item.models.ts deleted file mode 100644 index 044d2090e5..0000000000 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/sidebar-menu-item.models.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { ManifestElement } from './models'; - -export interface ManifestSidebarMenuItem extends ManifestElement { - type: 'sidebarMenuItem'; - meta: MetaSidebarMenuItem; -} - -export interface MetaSidebarMenuItem { - label: string; - icon: string; - sidebarMenus: Array; - entityType?: string; -} diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/sidebar-menu.models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/sidebar-menu.models.ts deleted file mode 100644 index 4c48bb3be0..0000000000 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/sidebar-menu.models.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { ManifestElement } from './models'; - -export interface ManifestSidebarMenu extends ManifestElement { - type: 'sidebarMenu'; - meta: MetaSidebarMenu; -} - -export interface MetaSidebarMenu { - label: string; - sections: Array; -} diff --git a/src/Umbraco.Web.UI.Client/libs/extensions-registry/workspace-action.models.ts b/src/Umbraco.Web.UI.Client/libs/extensions-registry/workspace-action.models.ts index e8fc7fe8f9..b18c358d5f 100644 --- a/src/Umbraco.Web.UI.Client/libs/extensions-registry/workspace-action.models.ts +++ b/src/Umbraco.Web.UI.Client/libs/extensions-registry/workspace-action.models.ts @@ -1,5 +1,7 @@ import type { InterfaceColor, InterfaceLook } from '@umbraco-ui/uui-base/lib/types/index'; import type { ManifestElement } from './models'; +import { UmbWorkspaceAction } from '@umbraco-cms/workspace'; +import type { ClassConstructor } from '@umbraco-cms/models'; export interface ManifestWorkspaceAction extends ManifestElement { type: 'workspaceAction'; @@ -11,6 +13,5 @@ export interface MetaWorkspaceAction { label?: string; //TODO: Use or implement additional label-key look?: InterfaceLook; color?: InterfaceColor; - repositoryAlias?: string; // TODO: make mandatory when repositories are fully implemented - api?: any; //TODO: Implement UmbEntityAction + api: ClassConstructor; } diff --git a/src/Umbraco.Web.UI.Client/libs/models/index.ts b/src/Umbraco.Web.UI.Client/libs/models/index.ts index 157a142fbc..55988872da 100644 --- a/src/Umbraco.Web.UI.Client/libs/models/index.ts +++ b/src/Umbraco.Web.UI.Client/libs/models/index.ts @@ -151,3 +151,11 @@ export interface SwatchDetails { label: string; value: string; } + +export type UmbPackage = { + name?: string; + version?: string; + extensions?: unknown[]; +}; + +export type PagedManifestsResponse = UmbPackage[]; diff --git a/src/Umbraco.Web.UI.Client/libs/notification/notification.mdx b/src/Umbraco.Web.UI.Client/libs/notification/stories/notification.mdx similarity index 100% rename from src/Umbraco.Web.UI.Client/libs/notification/notification.mdx rename to src/Umbraco.Web.UI.Client/libs/notification/stories/notification.mdx diff --git a/src/Umbraco.Web.UI.Client/libs/notification/stories/notification.stories.ts b/src/Umbraco.Web.UI.Client/libs/notification/stories/notification.stories.ts new file mode 100644 index 0000000000..ce0460727a --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/notification/stories/notification.stories.ts @@ -0,0 +1,38 @@ +import '../layouts/default'; + +import { Meta, Story } from '@storybook/web-components'; +import { html } from 'lit'; + +import { UmbNotificationService } from '..'; + +export default { + title: 'API/Notifications/Overview', + component: 'ucp-notification-layout-default', + decorators: [ + (story) => + html` + ${story()} + `, + ], +} as Meta; + +const Template: Story = () => html``; + +export const Default = Template.bind({}); +Default.parameters = { + docs: { + source: { + language: 'js', + code: ` +const options: UmbNotificationOptions = { + data: { + headline: 'Headline', + message: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit' + } +}; + +this._notificationService?.peek('positive', options); +`, + }, + }, +}; diff --git a/src/Umbraco.Web.UI.Client/libs/notification/notification.stories.ts b/src/Umbraco.Web.UI.Client/libs/notification/stories/story-notification-default-example.element.ts similarity index 61% rename from src/Umbraco.Web.UI.Client/libs/notification/notification.stories.ts rename to src/Umbraco.Web.UI.Client/libs/notification/stories/story-notification-default-example.element.ts index c890834387..b470aa71f7 100644 --- a/src/Umbraco.Web.UI.Client/libs/notification/notification.stories.ts +++ b/src/Umbraco.Web.UI.Client/libs/notification/stories/story-notification-default-example.element.ts @@ -1,28 +1,14 @@ -import './layouts/default'; - -import { Meta, Story } from '@storybook/web-components'; import { html } from 'lit'; import { customElement } from 'lit/decorators.js'; - -import type { UmbNotificationDefaultData } from './layouts/default'; +import { UmbNotificationDefaultData } from '../layouts/default'; import { UmbNotificationColor, UmbNotificationOptions, UmbNotificationService, - UMB_NOTIFICATION_SERVICE_CONTEXT_TOKEN, -} from '.'; + UMB_NOTIFICATION_SERVICE_CONTEXT_TOKEN +} from '..'; import { UmbLitElement } from '@umbraco-cms/element'; -export default { - title: 'API/Notifications/Overview', - component: 'ucp-notification-layout-default', - decorators: [ - (story) => - html` - ${story()} - `, - ], -} as Meta; @customElement('story-notification-default-example') export class StoryNotificationDefaultExampleElement extends UmbLitElement { @@ -69,24 +55,3 @@ export class StoryNotificationDefaultExampleElement extends UmbLitElement { `; } } - -const Template: Story = () => html``; - -export const Default = Template.bind({}); -Default.parameters = { - docs: { - source: { - language: 'js', - code: ` -const options: UmbNotificationOptions = { - data: { - headline: 'Headline', - message: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit' - } -}; - -this._notificationService?.peek('positive', options); -`, - }, - }, -}; diff --git a/src/Umbraco.Web.UI.Client/libs/workspace/actions/index.ts b/src/Umbraco.Web.UI.Client/libs/workspace/actions/index.ts new file mode 100644 index 0000000000..d1092c53e3 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/workspace/actions/index.ts @@ -0,0 +1,2 @@ +export * from './workspace-action-base'; +export * from './save/save.action'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/workspace-actions/save.action.ts b/src/Umbraco.Web.UI.Client/libs/workspace/actions/save/save.action.ts similarity index 67% rename from src/Umbraco.Web.UI.Client/src/backoffice/shared/workspace-actions/save.action.ts rename to src/Umbraco.Web.UI.Client/libs/workspace/actions/save/save.action.ts index 4719ead35b..7b178ef44a 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/workspace-actions/save.action.ts +++ b/src/Umbraco.Web.UI.Client/libs/workspace/actions/save/save.action.ts @@ -1,11 +1,11 @@ -import { UmbWorkspaceAction } from '../components/workspace/workspace-action'; -import { UmbWorkspaceContextInterface } from '../components/workspace/workspace-context/workspace-context.interface'; +import { UmbWorkspaceContextInterface } from '../../../../src/backoffice/shared/components/workspace/workspace-context/workspace-context.interface'; +import { UmbWorkspaceActionBase } from '@umbraco-cms/workspace'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; // TODO: add interface for repo/partial repo/save-repo -export class UmbSaveWorkspaceAction extends UmbWorkspaceAction { - constructor(host: UmbControllerHostInterface, repositoryAlias: string) { - super(host, repositoryAlias); +export class UmbSaveWorkspaceAction extends UmbWorkspaceActionBase { + constructor(host: UmbControllerHostInterface) { + super(host); } /* TODO: we need a solution for all actions to notify the system that is has been executed. @@ -26,7 +26,8 @@ export class UmbSaveWorkspaceAction extends UmbWorkspaceAction extends UmbActionBase { +export interface UmbWorkspaceAction { + host: UmbControllerHostInterface; + workspaceContext?: T; + execute(): Promise; +} + +export class UmbWorkspaceActionBase { + host: UmbControllerHostInterface; workspaceContext?: WorkspaceType; - constructor(host: UmbControllerHostInterface, repositoryAlias: string) { - super(host, repositoryAlias); + constructor(host: UmbControllerHostInterface) { + this.host = host; new UmbContextConsumerController(this.host, 'umbWorkspaceContext', (instance: WorkspaceType) => { this.workspaceContext = instance; diff --git a/src/Umbraco.Web.UI.Client/libs/workspace/index.ts b/src/Umbraco.Web.UI.Client/libs/workspace/index.ts new file mode 100644 index 0000000000..485f1b10af --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/workspace/index.ts @@ -0,0 +1 @@ +export * from './actions'; diff --git a/src/Umbraco.Web.UI.Client/libs/workspace/rollup.config.js b/src/Umbraco.Web.UI.Client/libs/workspace/rollup.config.js new file mode 100644 index 0000000000..945c0afe88 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/workspace/rollup.config.js @@ -0,0 +1,4 @@ +import config from '../../utils/rollup.config.js'; +export default { + ...config, +}; diff --git a/src/Umbraco.Web.UI.Client/src/app.ts b/src/Umbraco.Web.UI.Client/src/app.ts index 18d11ccbf2..2b389e431d 100644 --- a/src/Umbraco.Web.UI.Client/src/app.ts +++ b/src/Umbraco.Web.UI.Client/src/app.ts @@ -19,7 +19,7 @@ import { UmbLitElement } from '@umbraco-cms/element'; import { tryExecuteAndNotify } from '@umbraco-cms/resources'; import { OpenAPI, RuntimeLevelModel, ServerResource } from '@umbraco-cms/backend-api'; import { UmbIconStore } from '@umbraco-cms/store'; -import { UmbContextDebugRequest, umbDebugContextEventType } from '@umbraco-cms/context-api'; +import { umbDebugContextEventType } from '@umbraco-cms/context-api'; @customElement('umb-app') export class UmbApp extends UmbLitElement { @@ -82,15 +82,14 @@ export class UmbApp extends UmbLitElement { this.provideContext('UMBRACOBASE', OpenAPI.BASE); await this._setInitStatus(); - await this._registerExtensionManifestsFromServer(); this._redirect(); // Listen for the debug event from the component this.addEventListener(umbDebugContextEventType, (event: any) => { // Once we got to the outter most component - // we can send the event containing all the contexts + // we can send the event containing all the contexts // we have collected whilst coming up through the DOM - // and pass it back down to the callback in + // and pass it back down to the callback in // the component that originally fired the event event.callback(event.instances); }); @@ -152,13 +151,6 @@ export class UmbApp extends UmbLitElement { }; } - private async _registerExtensionManifestsFromServer() { - // TODO: Implement once manifest endpoint exists - // const res = await getManifests({}); - // const { manifests } = res.data as unknown as { manifests: ManifestTypes[] }; - // manifests.forEach((manifest) => umbExtensionsRegistry.register(manifest)); - } - render() { return html``; } 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 459c69b1db..c3b5cd94a9 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/backoffice.element.ts @@ -40,9 +40,15 @@ import { UmbTemplateDetailStore } from './templating/templates/workspace/data/te import { UmbThemeContext } from './themes/theme.context'; import { UmbLogSearchesStore } from './settings/logviewer/workspace/data/log-search.store'; import { UmbLanguageStore } from './settings/languages/repository/language.store'; -import { UMB_APP_LANGUAGE_CONTEXT_TOKEN, UmbAppLanguageContext } from './settings/languages/app-language.context'; +import { + UMB_APP_LANGUAGE_CONTEXT_TOKEN, + UmbAppLanguageContext, +} 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 { UmbNotificationService, UMB_NOTIFICATION_SERVICE_CONTEXT_TOKEN } from '@umbraco-cms/notification'; import { UmbLitElement } from '@umbraco-cms/element'; +import { umbExtensionsRegistry } from '@umbraco-cms/extensions-api'; import '@umbraco-cms/router'; @@ -115,6 +121,9 @@ export class UmbBackofficeElement extends UmbLitElement { this.provideContext(UMB_BACKOFFICE_CONTEXT_TOKEN, new UmbBackofficeContext()); this.provideContext(UMB_CURRENT_USER_HISTORY_STORE_CONTEXT_TOKEN, new UmbCurrentUserHistoryStore()); new UmbThemeContext(this); + + new UmbPackageStore(this); + new UmbServerExtensionController(this, umbExtensionsRegistry); } render() { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-blueprints/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-blueprints/manifests.ts index 91d087379a..5bee1cd866 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-blueprints/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-blueprints/manifests.ts @@ -1,4 +1,4 @@ -import { manifests as sidebarMenuItemManifests } from './sidebar-menu-item/manifests'; +import { manifests as menuItemManifests } from './menu-item/manifests'; import { manifests as workspaceManifests } from './workspace/manifests'; -export const manifests = [...sidebarMenuItemManifests, ...workspaceManifests]; +export const manifests = [...menuItemManifests, ...workspaceManifests]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-blueprints/menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-blueprints/menu-item/manifests.ts new file mode 100644 index 0000000000..976c314278 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-blueprints/menu-item/manifests.ts @@ -0,0 +1,16 @@ +import type { ManifestMenuItem } from '@umbraco-cms/models'; + +const menuItem: ManifestMenuItem = { + type: 'menuItem', + alias: 'Umb.MenuItem.DocumentBlueprints', + name: 'Document Blueprints Menu Item', + weight: 90, + meta: { + label: 'Document Blueprints', + icon: 'umb:blueprint', + menus: ['Umb.Menu.Settings'], + entityType: 'document-blueprint-root', + }, +}; + +export const manifests = [menuItem]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-blueprints/sidebar-menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-blueprints/sidebar-menu-item/manifests.ts deleted file mode 100644 index e85282727e..0000000000 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-blueprints/sidebar-menu-item/manifests.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { ManifestSidebarMenuItem } from '@umbraco-cms/models'; - -const sidebarMenuItem: ManifestSidebarMenuItem = { - type: 'sidebarMenuItem', - alias: 'Umb.SidebarMenuItem.DocumentBlueprints', - name: 'Document Blueprints Sidebar Menu Item', - weight: 90, - meta: { - label: 'Document Blueprints', - icon: 'umb:blueprint', - sidebarMenus: ['Umb.SidebarMenu.Settings'], - entityType: 'document-blueprint-root', - }, -}; - -export const manifests = [sidebarMenuItem]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/manifests.ts index 50f50fc98b..02774edbeb 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/manifests.ts @@ -1,6 +1,6 @@ -import { manifests as sidebarMenuItemManifests } from './sidebar-menu-item/manifests'; +import { manifests as menuItemManifests } from './menu-item/manifests'; import { manifests as treeManifests } from './tree/manifests'; import { manifests as workspaceManifests } from './workspace/manifests'; import { manifests as repositoryManifests } from './repository/manifests'; -export const manifests = [...sidebarMenuItemManifests, ...treeManifests, ...repositoryManifests, ...workspaceManifests]; +export const manifests = [...menuItemManifests, ...treeManifests, ...repositoryManifests, ...workspaceManifests]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/sidebar-menu-item/document-types-sidebar-menu-item.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/menu-item/document-types-menu-item.element.ts similarity index 100% rename from src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/sidebar-menu-item/document-types-sidebar-menu-item.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/menu-item/document-types-menu-item.element.ts diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/menu-item/manifests.ts new file mode 100644 index 0000000000..a74b49aab2 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/menu-item/manifests.ts @@ -0,0 +1,16 @@ +import type { ManifestMenuItem } from '@umbraco-cms/models'; + +const menuItem: ManifestMenuItem = { + type: 'menuItem', + alias: 'Umb.MenuItem.DocumentTypes', + name: 'Document Types Menu Item', + weight: 10, + loader: () => import('./document-types-menu-item.element'), + meta: { + label: 'Document Types', + icon: 'umb:folder', + menus: ['Umb.Menu.Settings'], + }, +}; + +export const manifests = [menuItem]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/sidebar-menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/sidebar-menu-item/manifests.ts deleted file mode 100644 index 1d6e662307..0000000000 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/sidebar-menu-item/manifests.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { ManifestSidebarMenuItem } from '@umbraco-cms/models'; - -const sidebarMenuItem: ManifestSidebarMenuItem = { - type: 'sidebarMenuItem', - alias: 'Umb.SidebarMenuItem.DocumentTypes', - name: 'Document Types Sidebar Menu Item', - weight: 10, - loader: () => import('./document-types-sidebar-menu-item.element'), - meta: { - label: 'Document Types', - icon: 'umb:folder', - sidebarMenus: ['Umb.SidebarMenu.Settings'], - }, -}; - -export const manifests = [sidebarMenuItem]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/document-type-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/document-type-workspace.context.ts index ed00528b37..4fcef85092 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/document-type-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/document-type-workspace.context.ts @@ -7,20 +7,15 @@ import { ObjectState } from '@umbraco-cms/observable-api'; type EntityType = DocumentTypeModel; export class UmbWorkspaceDocumentTypeContext - extends UmbWorkspaceContext + extends UmbWorkspaceContext implements UmbWorkspaceEntityContextInterface { - #host: UmbControllerHostInterface; - #repo: UmbDocumentTypeRepository; - #data = new ObjectState(undefined); data = this.#data.asObservable(); name = this.#data.getObservablePart((data) => data?.name); constructor(host: UmbControllerHostInterface) { - super(host); - this.#host = host; - this.#repo = new UmbDocumentTypeRepository(this.#host); + super(host, new UmbDocumentTypeRepository(host)); } public setPropertyValue(alias: string, value: unknown) { @@ -49,21 +44,21 @@ export class UmbWorkspaceDocumentTypeContext } async load(entityKey: string) { - const { data } = await this.#repo.requestByKey(entityKey); + const { data } = await this.repository.requestByKey(entityKey); if (data) { this.#data.next(data); } } async createScaffold(parentKey: string | null) { - const { data } = await this.#repo.createScaffold(parentKey); + const { data } = await this.repository.createScaffold(parentKey); if (!data) return; this.#data.next(data); } async save() { if (!this.#data.value) return; - this.#repo.save(this.#data.value); + this.repository.save(this.#data.value); } public destroy(): void { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/manifests.ts index 82229b33e1..114efb3e7e 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/manifests.ts @@ -1,3 +1,4 @@ +import { UmbSaveWorkspaceAction } from '@umbraco-cms/workspace'; import type { ManifestWorkspace, ManifestWorkspaceAction, ManifestWorkspaceView } from '@umbraco-cms/models'; const workspace: ManifestWorkspace = { @@ -31,12 +32,12 @@ const workspaceActions: Array = [ type: 'workspaceAction', alias: 'Umb.WorkspaceAction.DocumentType.Save', name: 'Save Document Type Workspace Action', - loader: () => - import('../../../shared/components/workspace/workspace-action/save/workspace-action-node-save.element'), meta: { workspaces: ['Umb.Workspace.DocumentType'], + label: 'Save', look: 'primary', color: 'positive', + api: UmbSaveWorkspaceAction, }, }, ]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/create-blueprint.action.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/create-blueprint.action.ts index e9dac9e70a..a0780eb967 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/create-blueprint.action.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/create-blueprint.action.ts @@ -1,5 +1,5 @@ import { UmbDocumentRepository } from '../repository/document.repository'; -import { UmbEntityActionBase } from '../../../shared/entity-actions'; +import { UmbEntityActionBase } from '@umbraco-cms/entity-action'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; export class UmbCreateDocumentBlueprintEntityAction extends UmbEntityActionBase { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/create.action.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/create.action.ts index 938bd470a2..d88cca15bb 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/create.action.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/create.action.ts @@ -1,5 +1,5 @@ import { UmbDocumentRepository } from '../repository/document.repository'; -import { UmbEntityActionBase } from '../../../shared/entity-actions'; +import { UmbEntityActionBase } from '@umbraco-cms/entity-action'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; export class UmbCreateDocumentEntityAction extends UmbEntityActionBase { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/culture-and-hostnames.action.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/culture-and-hostnames.action.ts index 5ae0161080..1ba8de7356 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/culture-and-hostnames.action.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/culture-and-hostnames.action.ts @@ -1,5 +1,5 @@ import { UmbDocumentRepository } from '../repository/document.repository'; -import { UmbEntityActionBase } from '../../../shared/entity-actions'; +import { UmbEntityActionBase } from '@umbraco-cms/entity-action'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; export class UmbDocumentCultureAndHostnamesEntityAction extends UmbEntityActionBase { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/manifests.ts index cbe3767e0d..7dc878c0b6 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/manifests.ts @@ -1,7 +1,3 @@ -import { UmbCopyEntityAction } from '../../../shared/entity-actions/copy/copy.action'; -import { UmbMoveEntityAction } from '../../../shared/entity-actions/move/move.action'; -import { UmbTrashEntityAction } from '../../../shared/entity-actions/trash/trash.action'; -import { UmbSortChildrenOfEntityAction } from '../../../shared/entity-actions/sort-children-of/sort-children-of.action'; import { UmbCreateDocumentEntityAction } from './create.action'; import { UmbPublishDocumentEntityAction } from './publish.action'; import { UmbDocumentCultureAndHostnamesEntityAction } from './culture-and-hostnames.action'; @@ -10,6 +6,12 @@ import { UmbDocumentPublicAccessEntityAction } from './public-access.action'; import { UmbDocumentPermissionsEntityAction } from './permissions.action'; import { UmbUnpublishDocumentEntityAction } from './unpublish.action'; import { UmbRollbackDocumentEntityAction } from './rollback.action'; +import { + UmbCopyEntityAction, + UmbMoveEntityAction, + UmbTrashEntityAction, + UmbSortChildrenOfEntityAction, +} from '@umbraco-cms/entity-action'; import { ManifestEntityAction } from '@umbraco-cms/extensions-registry'; const entityType = 'document'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/permissions.action.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/permissions.action.ts index 2aabec2046..a116358cce 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/permissions.action.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/permissions.action.ts @@ -1,5 +1,5 @@ import { UmbDocumentRepository } from '../repository/document.repository'; -import { UmbEntityActionBase } from '../../../shared/entity-actions'; +import { UmbEntityActionBase } from '@umbraco-cms/entity-action'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; export class UmbDocumentPermissionsEntityAction extends UmbEntityActionBase { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/public-access.action.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/public-access.action.ts index b1374972ee..aff79a03b2 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/public-access.action.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/public-access.action.ts @@ -1,5 +1,5 @@ import { UmbDocumentRepository } from '../repository/document.repository'; -import { UmbEntityActionBase } from '../../../shared/entity-actions'; +import { UmbEntityActionBase } from '@umbraco-cms/entity-action'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; export class UmbDocumentPublicAccessEntityAction extends UmbEntityActionBase { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/publish.action.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/publish.action.ts index 7e12969c18..47d49c6517 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/publish.action.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/publish.action.ts @@ -1,5 +1,5 @@ import { UmbDocumentRepository } from '../repository/document.repository'; -import { UmbEntityActionBase } from '../../../shared/entity-actions'; +import { UmbEntityActionBase } from '@umbraco-cms/entity-action'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; export class UmbPublishDocumentEntityAction extends UmbEntityActionBase { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/rollback.action.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/rollback.action.ts index 1340ee9921..8e473ecbfb 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/rollback.action.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/rollback.action.ts @@ -1,5 +1,5 @@ import { UmbDocumentRepository } from '../repository/document.repository'; -import { UmbEntityActionBase } from '../../../shared/entity-actions'; +import { UmbEntityActionBase } from '@umbraco-cms/entity-action'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; export class UmbRollbackDocumentEntityAction extends UmbEntityActionBase { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/unpublish.action.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/unpublish.action.ts index 461ebb5c04..3820cae4d9 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/unpublish.action.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-actions/unpublish.action.ts @@ -1,5 +1,5 @@ import { UmbDocumentRepository } from '../repository/document.repository'; -import { UmbEntityActionBase } from '../../../shared/entity-actions'; +import { UmbEntityActionBase } from '@umbraco-cms/entity-action'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; export class UmbUnpublishDocumentEntityAction extends UmbEntityActionBase { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-bulk-actions/copy/copy.action.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-bulk-actions/copy/copy.action.ts index cd949ebe5c..daf1482bed 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-bulk-actions/copy/copy.action.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-bulk-actions/copy/copy.action.ts @@ -1,21 +1,14 @@ import { UmbDocumentRepository } from '../../repository/document.repository'; -import { UmbActionBase } from '../../../../shared/action'; +import { UmbEntityBulkActionBase } from '@umbraco-cms/entity-action'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; -export class UmbDocumentCopyEntityBulkAction extends UmbActionBase { - #selection: Array; - +export class UmbDocumentCopyEntityBulkAction extends UmbEntityBulkActionBase { constructor(host: UmbControllerHostInterface, repositoryAlias: string, selection: Array) { - super(host, repositoryAlias); - this.#selection = selection; - } - - setSelection(selection: Array) { - this.#selection = selection; + super(host, repositoryAlias, selection); } async execute() { - console.log(`execute copy for: ${this.#selection}`); + console.log(`execute copy for: ${this.selection}`); await this.repository?.copy(); } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-bulk-actions/move/move.action.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-bulk-actions/move/move.action.ts index 7a42dba038..ebe5bb2a8a 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-bulk-actions/move/move.action.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/entity-bulk-actions/move/move.action.ts @@ -1,21 +1,14 @@ import { UmbDocumentRepository } from '../../repository/document.repository'; -import { UmbActionBase } from '../../../../shared/action'; +import { UmbEntityBulkActionBase } from '@umbraco-cms/entity-action'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; -export class UmbDocumentMoveEntityBulkAction extends UmbActionBase { - #selection: Array; - +export class UmbDocumentMoveEntityBulkAction extends UmbEntityBulkActionBase { constructor(host: UmbControllerHostInterface, repositoryAlias: string, selection: Array) { - super(host, repositoryAlias); - this.#selection = selection; - } - - setSelection(selection: Array) { - this.#selection = selection; + super(host, repositoryAlias, selection); } async execute() { - console.log(`execute move for: ${this.#selection}`); + console.log(`execute move for: ${this.selection}`); await this.repository?.move(); } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/manifests.ts index b7818bc6b0..b36ebb6e5b 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/manifests.ts @@ -1,5 +1,5 @@ import { manifests as collectionManifests } from './collection/manifests'; -import { manifests as sidebarMenuItemManifests } from './sidebar-menu-item/manifests'; +import { manifests as menuItemManifests } from './sidebar-menu-item/manifests'; import { manifests as repositoryManifests } from './repository/manifests'; import { manifests as treeManifests } from './tree/manifests'; import { manifests as workspaceManifests } from './workspace/manifests'; @@ -8,7 +8,7 @@ import { manifests as entityBulkActionManifests } from './entity-bulk-actions/ma export const manifests = [ ...collectionManifests, - ...sidebarMenuItemManifests, + ...menuItemManifests, ...treeManifests, ...repositoryManifests, ...workspaceManifests, diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/sidebar-menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/sidebar-menu-item/manifests.ts index 2273b73a4a..e4bfc4a260 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/sidebar-menu-item/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/sidebar-menu-item/manifests.ts @@ -1,16 +1,16 @@ -import type { ManifestSidebarMenuItem } from '@umbraco-cms/models'; +import type { ManifestMenuItem } from '@umbraco-cms/models'; -const sidebarMenuItem: ManifestSidebarMenuItem = { - type: 'sidebarMenuItem', - alias: 'Umb.SidebarMenuItem.Documents', - name: 'Documents Sidebar Menu Item', +const menuItem: ManifestMenuItem = { + type: 'menuItem', + alias: 'Umb.MenuItem.Documents', + name: 'Documents Menu Item', weight: 100, loader: () => import('./document-sidebar-menu-item.element'), meta: { label: 'Documents', icon: 'umb:folder', - sidebarMenus: ['Umb.SidebarMenu.Content'], + menus: ['Umb.Menu.Content'], }, }; -export const manifests = [sidebarMenuItem]; +export const manifests = [menuItem]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/actions/save-and-preview.action.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/actions/save-and-preview.action.ts index de24db885a..10470f8d25 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/actions/save-and-preview.action.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/actions/save-and-preview.action.ts @@ -1,14 +1,10 @@ -import { UmbWorkspaceAction } from '../../../../shared/components/workspace/workspace-action'; import { UmbDocumentWorkspaceContext } from '../document-workspace.context'; -import { UmbDocumentRepository } from '../../repository/document.repository'; +import { UmbWorkspaceActionBase } from '@umbraco-cms/workspace'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; -export class UmbDocumentSaveAndPreviewWorkspaceAction extends UmbWorkspaceAction< - UmbDocumentRepository, - UmbDocumentWorkspaceContext -> { - constructor(host: UmbControllerHostInterface, repositoryAlias: string) { - super(host, repositoryAlias); +export class UmbDocumentSaveAndPreviewWorkspaceAction extends UmbWorkspaceActionBase { + constructor(host: UmbControllerHostInterface) { + super(host); } async execute() { @@ -17,6 +13,6 @@ export class UmbDocumentSaveAndPreviewWorkspaceAction extends UmbWorkspaceAction const document = this.workspaceContext.getData(); // TODO: handle errors if (!document) return; - this.repository?.saveAndPreview(); + this.workspaceContext.repository?.saveAndPreview(); } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/actions/save-and-publish.action.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/actions/save-and-publish.action.ts index 9d32a23225..ef49816688 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/actions/save-and-publish.action.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/actions/save-and-publish.action.ts @@ -1,14 +1,10 @@ -import { UmbWorkspaceAction } from '../../../../shared/components/workspace/workspace-action'; import { UmbDocumentWorkspaceContext } from '../document-workspace.context'; -import { UmbDocumentRepository } from '../../repository/document.repository'; +import { UmbWorkspaceActionBase } from '@umbraco-cms/workspace'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; -export class UmbDocumentSaveAndPublishWorkspaceAction extends UmbWorkspaceAction< - UmbDocumentRepository, - UmbDocumentWorkspaceContext -> { - constructor(host: UmbControllerHostInterface, repositoryAlias: string) { - super(host, repositoryAlias); +export class UmbDocumentSaveAndPublishWorkspaceAction extends UmbWorkspaceActionBase { + constructor(host: UmbControllerHostInterface) { + super(host); } async execute() { @@ -17,6 +13,6 @@ export class UmbDocumentSaveAndPublishWorkspaceAction extends UmbWorkspaceAction const document = this.workspaceContext.getData(); // TODO: handle errors if (!document) return; - this.repository?.saveAndPublish(); + this.workspaceContext.repository.saveAndPublish(); } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/actions/save-and-schedule.action.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/actions/save-and-schedule.action.ts index 3c79e5fd37..aa630bbc6e 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/actions/save-and-schedule.action.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/actions/save-and-schedule.action.ts @@ -1,14 +1,10 @@ -import { UmbWorkspaceAction } from '../../../../shared/components/workspace/workspace-action'; -import { UmbDocumentRepository } from '../../repository/document.repository'; import { UmbDocumentWorkspaceContext } from '../document-workspace.context'; +import { UmbWorkspaceActionBase } from '@umbraco-cms/workspace'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; -export class UmbSaveAndScheduleDocumentWorkspaceAction extends UmbWorkspaceAction< - UmbDocumentRepository, - UmbDocumentWorkspaceContext -> { - constructor(host: UmbControllerHostInterface, repositoryAlias: string) { - super(host, repositoryAlias); +export class UmbSaveAndScheduleDocumentWorkspaceAction extends UmbWorkspaceActionBase { + constructor(host: UmbControllerHostInterface) { + super(host); } async execute() { @@ -17,6 +13,6 @@ export class UmbSaveAndScheduleDocumentWorkspaceAction extends UmbWorkspaceActio const document = this.workspaceContext.getData(); // TODO: handle errors if (!document) return; - this.repository?.saveAndSchedule(); + this.workspaceContext.repository.saveAndSchedule(); } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/document-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/document-workspace.context.ts index 06d5436491..cce9a30c50 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/document-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/document-workspace.context.ts @@ -19,12 +19,9 @@ export type ActiveVariant = { type EntityType = DocumentModel; export class UmbDocumentWorkspaceContext - extends UmbWorkspaceContext + extends UmbWorkspaceContext implements UmbWorkspaceVariableEntityContextInterface { - #host: UmbControllerHostInterface; - #documentRepository: UmbDocumentRepository; - /** * The document is the current stored version of the document. * For now lets not share this publicly as it can become confusing. @@ -48,18 +45,15 @@ export class UmbDocumentWorkspaceContext readonly structure; constructor(host: UmbControllerHostInterface) { - super(host); - this.#host = host; + super(host, new UmbDocumentRepository(host)); - this.#documentRepository = new UmbDocumentRepository(this.#host); + this.structure = new UmbWorkspacePropertyStructureManager(this.host, new UmbDocumentTypeRepository(this.host)); - this.structure = new UmbWorkspacePropertyStructureManager(this.#host, new UmbDocumentTypeRepository(this.#host)); - - new UmbObserverController(this._host, this.documentTypeKey, (key) => this.structure.loadType(key)); + new UmbObserverController(this.host, this.documentTypeKey, (key) => this.structure.loadType(key)); } async load(entityKey: string) { - const { data } = await this.#documentRepository.requestByKey(entityKey); + const { data } = await this.repository.requestByKey(entityKey); if (!data) return undefined; this.setIsNew(false); @@ -69,7 +63,7 @@ export class UmbDocumentWorkspaceContext } async createScaffold(parentKey: string | null) { - const { data } = await this.#documentRepository.createScaffold(parentKey); + const { data } = await this.repository.createScaffold(parentKey); if (!data) return undefined; this.setIsNew(true); @@ -177,16 +171,16 @@ export class UmbDocumentWorkspaceContext async save() { if (!this.#draft.value) return; if (this.getIsNew()) { - await this.#documentRepository.create(this.#draft.value); + await this.repository.create(this.#draft.value); } else { - await this.#documentRepository.save(this.#draft.value); + await this.repository.save(this.#draft.value); } // If it went well, then its not new anymore?. this.setIsNew(false); } async delete(key: string) { - await this.#documentRepository.delete(key); + await this.repository.delete(key); } /* diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/manifests.ts index 85832b0aa3..be404bc875 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/documents/workspace/manifests.ts @@ -1,8 +1,8 @@ import { DOCUMENT_REPOSITORY_ALIAS } from '../repository/manifests'; -import { UmbSaveWorkspaceAction } from '../../../shared/workspace-actions/save.action'; import { UmbDocumentSaveAndPublishWorkspaceAction } from './actions/save-and-publish.action'; import { UmbDocumentSaveAndPreviewWorkspaceAction } from './actions/save-and-preview.action'; import { UmbSaveAndScheduleDocumentWorkspaceAction } from './actions/save-and-schedule.action'; +import { UmbSaveWorkspaceAction } from '@umbraco-cms/workspace'; import type { ManifestWorkspace, ManifestWorkspaceAction, @@ -81,7 +81,6 @@ const workspaceActions: Array = [ label: 'Save And Publish', look: 'primary', color: 'positive', - repositoryAlias: DOCUMENT_REPOSITORY_ALIAS, api: UmbDocumentSaveAndPublishWorkspaceAction, }, }, @@ -94,7 +93,6 @@ const workspaceActions: Array = [ workspaces: ['Umb.Workspace.Document'], label: 'Save', look: 'secondary', - repositoryAlias: DOCUMENT_REPOSITORY_ALIAS, api: UmbSaveWorkspaceAction, }, }, @@ -106,7 +104,6 @@ const workspaceActions: Array = [ meta: { workspaces: ['Umb.Workspace.Document'], label: 'Save And Preview', - repositoryAlias: DOCUMENT_REPOSITORY_ALIAS, api: UmbDocumentSaveAndPreviewWorkspaceAction, }, }, @@ -118,7 +115,6 @@ const workspaceActions: Array = [ meta: { workspaces: ['Umb.Workspace.Document'], label: 'Save And Schedule', - repositoryAlias: DOCUMENT_REPOSITORY_ALIAS, api: UmbSaveAndScheduleDocumentWorkspaceAction, }, }, diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/index.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/index.ts index 4c63eb521f..5f5aac6a97 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/index.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/index.ts @@ -1,5 +1,6 @@ import { manifests as dashboardManifests } from './dashboards/manifests'; import { manifests as contentSectionManifests } from './section.manifests'; +import { manifests as contentMenuManifest } from './menu.manifests'; import { manifests as documentBlueprintManifests } from './document-blueprints/manifests'; import { manifests as documentTypeManifests } from './document-types/manifests'; import { manifests as documentManifests } from './documents/manifests'; @@ -17,6 +18,7 @@ const registerExtensions = (manifests: Array) => { registerExtensions([ ...dashboardManifests, ...contentSectionManifests, + ...contentMenuManifest, ...documentBlueprintManifests, ...documentTypeManifests, ...documentManifests, diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/menu.manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/menu.manifests.ts new file mode 100644 index 0000000000..1595462273 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/menu.manifests.ts @@ -0,0 +1,12 @@ +import { ManifestMenu } from '@umbraco-cms/extensions-registry'; + +const menu: ManifestMenu = { + type: 'menu', + alias: 'Umb.Menu.Content', + name: 'Content Menu', + meta: { + label: 'Content', + }, +}; + +export const manifests = [menu]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/section.manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/section.manifests.ts index 4787f76123..d8919a3689 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/section.manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/section.manifests.ts @@ -1,4 +1,4 @@ -import type { ManifestSection, ManifestSidebarMenu } from '@umbraco-cms/models'; +import type { ManifestSection, ManifestMenuSectionSidebarApp } from '@umbraco-cms/models'; const sectionAlias = 'Umb.Section.Content'; @@ -13,15 +13,16 @@ const section: ManifestSection = { }, }; -const sidebarMenu: ManifestSidebarMenu = { - type: 'sidebarMenu', +const menuSectionSidebarApp: ManifestMenuSectionSidebarApp = { + type: 'menuSectionSidebarApp', alias: 'Umb.SidebarMenu.Content', name: 'Content Sidebar Menu', weight: 100, meta: { label: 'Content', sections: [sectionAlias], + menu: 'Umb.Menu.Content', }, }; -export const manifests = [section, sidebarMenu]; +export const manifests = [section, menuSectionSidebarApp]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/index.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/index.ts index 2ee56ad17b..7afe8c49db 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/media/index.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/media/index.ts @@ -1,4 +1,5 @@ import { manifests as mediaSectionManifests } from './section.manifests'; +import { manifests as mediaMenuManifests } from './menu.manifests'; import { manifests as mediaManifests } from './media/manifests'; import { manifests as mediaTypesManifests } from './media-types/manifests'; @@ -12,4 +13,4 @@ const registerExtensions = (manifests: Array) => { }); }; -registerExtensions([...mediaSectionManifests, ...mediaManifests, ...mediaTypesManifests]); +registerExtensions([...mediaSectionManifests, ...mediaMenuManifests, ...mediaManifests, ...mediaTypesManifests]); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/entity-actions/create.action.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/entity-actions/create.action.ts index a2e0894606..9d5c7cdf57 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/entity-actions/create.action.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/entity-actions/create.action.ts @@ -1,5 +1,5 @@ import { UmbMediaTypeRepository } from '../repository/media-type.repository'; -import { UmbEntityActionBase } from '../../../shared/entity-actions'; +import { UmbEntityActionBase } from '@umbraco-cms/entity-action'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; export class UmbCreateMediaTypeEntityAction extends UmbEntityActionBase { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/entity-actions/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/entity-actions/manifests.ts index 32332fbc1b..cd094dcd3d 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/entity-actions/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/entity-actions/manifests.ts @@ -1,9 +1,7 @@ -import { UmbDeleteEntityAction } from '../../../../backoffice/shared/entity-actions/delete/delete.action'; -import { UmbMoveEntityAction } from '../../../../backoffice/shared/entity-actions/move/move.action'; import { MEDIA_TYPE_REPOSITORY_ALIAS } from '../repository/manifests'; -import { UmbCopyEntityAction } from '../../../../backoffice/shared/entity-actions/copy/copy.action'; import { UmbCreateMediaTypeEntityAction } from './create.action'; import UmbReloadMediaTypeEntityAction from './reload.action'; +import { UmbDeleteEntityAction, UmbMoveEntityAction, UmbCopyEntityAction } from '@umbraco-cms/entity-action'; import type { ManifestEntityAction } from '@umbraco-cms/models'; const entityType = 'media-type'; @@ -62,7 +60,7 @@ const entityActions: Array = [ api: UmbDeleteEntityAction, }, }, - { + { type: 'entityAction', alias: 'Umb.EntityAction.MediaType.Reload', name: 'Reload Media Type Entity Action', diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/entity-actions/reload.action.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/entity-actions/reload.action.ts index f07f5b8767..e12ee63785 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/entity-actions/reload.action.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/entity-actions/reload.action.ts @@ -1,6 +1,6 @@ import { UUITextStyles } from '@umbraco-ui/uui-css'; -import { UmbEntityActionBase } from '../../../shared/entity-actions'; import { UmbMediaTypeRepository } from '../repository/media-type.repository'; +import { UmbEntityActionBase } from '@umbraco-cms/entity-action'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; export default class UmbReloadMediaTypeEntityAction extends UmbEntityActionBase { @@ -11,6 +11,6 @@ export default class UmbReloadMediaTypeEntityAction extends UmbEntityActionBase< } async execute() { - alert('refresh') + alert('refresh'); } -} \ No newline at end of file +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/manifests.ts index 860a44f996..7e628554a5 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/manifests.ts @@ -1,11 +1,11 @@ -import { manifests as sidebarMenuItemManifests } from './sidebar-menu-item/manifests'; +import { manifests as menuItemManifests } from './menu-item/manifests'; import { manifests as treeManifests } from './tree/manifests'; import { manifests as workspaceManifests } from './workspace/manifests'; import { manifests as repositoryManifests } from './repository/manifests'; import { manifests as entityActionManifests } from './entity-actions/manifests'; export const manifests = [ - ...sidebarMenuItemManifests, + ...menuItemManifests, ...treeManifests, ...repositoryManifests, ...workspaceManifests, diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/menu-item/manifests.ts new file mode 100644 index 0000000000..5cb7de2e11 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/menu-item/manifests.ts @@ -0,0 +1,16 @@ +import type { ManifestMenuItem } from '@umbraco-cms/models'; + +const menuItem: ManifestMenuItem = { + type: 'menuItem', + alias: 'Umb.MenuItem.MediaTypes', + name: 'Media Types Menu Item', + weight: 20, + loader: () => import('./media-types-menu-item.element'), + meta: { + label: 'Media Types', + icon: 'umb:folder', + menus: ['Umb.Menu.Settings'], + }, +}; + +export const manifests = [menuItem]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/sidebar-menu-item/media-types-sidebar-menu-item.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/menu-item/media-types-menu-item.element.ts similarity index 78% rename from src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/sidebar-menu-item/media-types-sidebar-menu-item.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/menu-item/media-types-menu-item.element.ts index 1ad71be2bb..f38a1bb8d1 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/sidebar-menu-item/media-types-sidebar-menu-item.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/menu-item/media-types-menu-item.element.ts @@ -2,8 +2,8 @@ import { html, nothing } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { UmbLitElement } from '@umbraco-cms/element'; -@customElement('umb-media-types-sidebar-menu-item') -export class UmbMediaTypesSidebarMenuItemElement extends UmbLitElement { +@customElement('umb-media-types-menu-item') +export class UmbMediaTypesMenuItemElement extends UmbLitElement { @state() private _renderTree = false; @@ -30,10 +30,10 @@ export class UmbMediaTypesSidebarMenuItemElement extends UmbLitElement { } } -export default UmbMediaTypesSidebarMenuItemElement; +export default UmbMediaTypesMenuItemElement; declare global { interface HTMLElementTagNameMap { - 'umb-media-types-sidebar-menu-item': UmbMediaTypesSidebarMenuItemElement; + 'umb-media-types-menu-item': UmbMediaTypesMenuItemElement; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/sidebar-menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/sidebar-menu-item/manifests.ts deleted file mode 100644 index 2ecc9391f3..0000000000 --- a/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/sidebar-menu-item/manifests.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { ManifestSidebarMenuItem } from '@umbraco-cms/models'; - -const sidebarMenuItem: ManifestSidebarMenuItem = { - type: 'sidebarMenuItem', - alias: 'Umb.SidebarMenuItem.MediaTypes', - name: 'Media Types Sidebar Menu Item', - weight: 20, - loader: () => import('./media-types-sidebar-menu-item.element'), - meta: { - label: 'Media Types', - icon: 'umb:folder', - sidebarMenus: ['Umb.SidebarMenu.Settings'], - }, -}; - -export const manifests = [sidebarMenuItem]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/workspace/media-type-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/workspace/media-type-workspace.context.ts index 2445086e43..2e89adea0b 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/workspace/media-type-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/media/media-types/workspace/media-type-workspace.context.ts @@ -7,20 +7,15 @@ import type { MediaTypeDetails } from '@umbraco-cms/models'; type EntityType = MediaTypeDetails; export class UmbWorkspaceMediaTypeContext - extends UmbWorkspaceContext + extends UmbWorkspaceContext implements UmbWorkspaceEntityContextInterface { - #host: UmbControllerHostInterface; - #repo: UmbMediaTypeRepository; - #data = new ObjectState(undefined); data = this.#data.asObservable(); name = this.#data.getObservablePart((data) => data?.name); constructor(host: UmbControllerHostInterface) { - super(host); - this.#host = host; - this.#repo = new UmbMediaTypeRepository(this.#host); + super(host, new UmbMediaTypeRepository(host)); } getData() { @@ -44,14 +39,14 @@ export class UmbWorkspaceMediaTypeContext } async load(entityKey: string) { - const { data } = await this.#repo.requestDetails(entityKey); + const { data } = await this.repository.requestDetails(entityKey); if (data) { this.#data.next(data); } } async createScaffold() { - const { data } = await this.#repo.createScaffold(); + const { data } = await this.repository.createScaffold(); if (!data) return; this.setIsNew(true); this.#data.next(data); @@ -59,7 +54,7 @@ export class UmbWorkspaceMediaTypeContext async save() { if (!this.#data.value) return; - await this.#repo.save(this.#data.value); + await this.repository.save(this.#data.value); this.setIsNew(false); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/entity-actions/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/entity-actions/manifests.ts index edab42e14f..07c8ca11f8 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/entity-actions/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/entity-actions/manifests.ts @@ -1,4 +1,4 @@ -import { UmbTrashEntityAction } from '../../../shared/entity-actions/trash/trash.action'; +import { UmbTrashEntityAction } from '@umbraco-cms/entity-action'; import { ManifestEntityAction } from 'libs/extensions-registry/entity-action.models'; const entityActions: Array = [ diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/entity-bulk-actions/copy/copy.action.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/entity-bulk-actions/copy/copy.action.ts index 5b1be09218..273334c4b7 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/entity-bulk-actions/copy/copy.action.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/entity-bulk-actions/copy/copy.action.ts @@ -1,21 +1,14 @@ import type { UmbMediaRepository } from '../../repository/media.repository'; -import { UmbActionBase } from '../../../../shared/action'; +import { UmbEntityBulkActionBase } from '@umbraco-cms/entity-action'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; -export class UmbMediaCopyEntityBulkAction extends UmbActionBase { - #selection: Array; - +export class UmbMediaCopyEntityBulkAction extends UmbEntityBulkActionBase { constructor(host: UmbControllerHostInterface, repositoryAlias: string, selection: Array) { - super(host, repositoryAlias); - this.#selection = selection; - } - - setSelection(selection: Array) { - this.#selection = selection; + super(host, repositoryAlias, selection); } async execute() { - console.log(`execute copy for: ${this.#selection}`); + console.log(`execute copy for: ${this.selection}`); await this.repository?.copy([], ''); } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/entity-bulk-actions/move/move.action.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/entity-bulk-actions/move/move.action.ts index 2b1b44d03d..03ae8d0722 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/entity-bulk-actions/move/move.action.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/entity-bulk-actions/move/move.action.ts @@ -1,31 +1,25 @@ import type { UmbMediaRepository } from '../../repository/media.repository'; -import { UmbActionBase } from '../../../../shared/action'; +import { UmbEntityBulkActionBase } from '@umbraco-cms/entity-action'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; import { UmbContextConsumerController } from '@umbraco-cms/context-api'; import { UmbModalService, UMB_MODAL_SERVICE_CONTEXT_TOKEN } from '@umbraco-cms/modal'; -export class UmbMediaMoveEntityBulkAction extends UmbActionBase { - #selection: Array; +export class UmbMediaMoveEntityBulkAction extends UmbEntityBulkActionBase { #modalService?: UmbModalService; constructor(host: UmbControllerHostInterface, repositoryAlias: string, selection: Array) { - super(host, repositoryAlias); - this.#selection = selection; + super(host, repositoryAlias, selection); new UmbContextConsumerController(host, UMB_MODAL_SERVICE_CONTEXT_TOKEN, (instance) => { this.#modalService = instance; }); } - setSelection(selection: Array) { - this.#selection = selection; - } - async execute() { // TODO: the picker should be single picker by default const modalHandler = this.#modalService?.mediaPicker({ selection: [], multiple: false }); const selection = await modalHandler?.onClose(); const destination = selection[0]; - await this.repository?.move(this.#selection, destination); + await this.repository?.move(this.selection, destination); } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/entity-bulk-actions/trash/trash.action.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/entity-bulk-actions/trash/trash.action.ts index ce1a7d15fa..b767646fee 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/entity-bulk-actions/trash/trash.action.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/entity-bulk-actions/trash/trash.action.ts @@ -1,38 +1,32 @@ import { html } from 'lit'; import type { UmbMediaRepository } from '../../repository/media.repository'; -import { UmbActionBase } from '../../../../shared/action'; +import { UmbEntityBulkActionBase } from '@umbraco-cms/entity-action'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; import { UmbContextConsumerController } from '@umbraco-cms/context-api'; import { UmbModalService, UMB_MODAL_SERVICE_CONTEXT_TOKEN } from '@umbraco-cms/modal'; -export class UmbMediaTrashEntityBulkAction extends UmbActionBase { - #selection: Array; +export class UmbMediaTrashEntityBulkAction extends UmbEntityBulkActionBase { #modalService?: UmbModalService; constructor(host: UmbControllerHostInterface, repositoryAlias: string, selection: Array) { - super(host, repositoryAlias); - this.#selection = selection; + super(host, repositoryAlias, selection); new UmbContextConsumerController(host, UMB_MODAL_SERVICE_CONTEXT_TOKEN, (instance) => { this.#modalService = instance; }); } - setSelection(selection: Array) { - this.#selection = selection; - } - async execute() { // TODO: show error if (!this.#modalService || !this.repository) return; // TODO: should we subscribe in cases like this? - const { data } = await this.repository.requestTreeItems(this.#selection); + const { data } = await this.repository.requestTreeItems(this.selection); if (data) { // TODO: use correct markup const modalHandler = this.#modalService?.confirm({ - headline: `Deleting ${this.#selection.length} items`, + headline: `Deleting ${this.selection.length} items`, content: html` This will delete the following files:
    @@ -45,7 +39,7 @@ export class UmbMediaTrashEntityBulkAction extends UmbActionBase import('./media-menu-item.element'), + meta: { + label: 'Media', + icon: 'umb:folder', + menus: ['Umb.Menu.Media'], + }, +}; + +export const manifests = [menuItem]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/sidebar-menu-item/media-sidebar-menu-item.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/menu-item/media-menu-item.element.ts similarity index 54% rename from src/Umbraco.Web.UI.Client/src/backoffice/media/media/sidebar-menu-item/media-sidebar-menu-item.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/media/media/menu-item/media-menu-item.element.ts index a32ff11d13..6bba1af067 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/sidebar-menu-item/media-sidebar-menu-item.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/menu-item/media-menu-item.element.ts @@ -2,17 +2,17 @@ import { html } from 'lit'; import { customElement } from 'lit/decorators.js'; import { UmbLitElement } from '@umbraco-cms/element'; -@customElement('umb-media-sidebar-menu-item') -export class UmbMediaSidebarMenuItemElement extends UmbLitElement { +@customElement('umb-media-menu-item') +export class UmbMediaMenuItemElement extends UmbLitElement { render() { return html``; } } -export default UmbMediaSidebarMenuItemElement; +export default UmbMediaMenuItemElement; declare global { interface HTMLElementTagNameMap { - 'umb-media-sidebar-menu-item': UmbMediaSidebarMenuItemElement; + 'umb-media-menu-item': UmbMediaMenuItemElement; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/sidebar-menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/sidebar-menu-item/manifests.ts deleted file mode 100644 index f14f90cc8c..0000000000 --- a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/sidebar-menu-item/manifests.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { ManifestSidebarMenuItem } from '@umbraco-cms/models'; - -const sidebarMenuItem: ManifestSidebarMenuItem = { - type: 'sidebarMenuItem', - alias: 'Umb.SidebarMenuItem.Media', - name: 'Media Sidebar Menu Item', - weight: 100, - loader: () => import('./media-sidebar-menu-item.element'), - meta: { - label: 'Media', - icon: 'umb:folder', - sidebarMenus: ['Umb.SidebarMenu.Media'], - }, -}; - -export const manifests = [sidebarMenuItem]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/workspace/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/workspace/manifests.ts index 34a4e9137d..29af2a95c6 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/workspace/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/workspace/manifests.ts @@ -1,3 +1,4 @@ +import { UmbSaveWorkspaceAction } from '@umbraco-cms/workspace'; import type { ManifestWorkspace, ManifestWorkspaceAction, @@ -68,12 +69,12 @@ const workspaceActions: Array = [ type: 'workspaceAction', alias: 'Umb.WorkspaceAction.Media.Save', name: 'Save Media Workspace Action', - loader: () => - import('src/backoffice/shared/components/workspace/workspace-action/save/workspace-action-node-save.element'), meta: { workspaces: ['Umb.Workspace.Media'], + label: 'Save', look: 'primary', color: 'positive', + api: UmbSaveWorkspaceAction, }, }, ]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/workspace/media-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/workspace/media-workspace.context.ts index fe27ecb936..89847721d6 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/media/media/workspace/media-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/media/media/workspace/media-workspace.context.ts @@ -7,20 +7,15 @@ import type { MediaDetails } from '@umbraco-cms/models'; type EntityType = MediaDetails; export class UmbMediaWorkspaceContext - extends UmbWorkspaceContext + extends UmbWorkspaceContext implements UmbWorkspaceEntityContextInterface { - #host: UmbControllerHostInterface; - #detailRepository: UmbMediaRepository; - #data = new ObjectState(undefined); data = this.#data.asObservable(); name = this.#data.getObservablePart((data) => data?.name); constructor(host: UmbControllerHostInterface) { - super(host); - this.#host = host; - this.#detailRepository = new UmbMediaRepository(this.#host); + super(host, new UmbMediaRepository(host)); } getData() { @@ -51,7 +46,7 @@ export class UmbMediaWorkspaceContext } async load(entityKey: string) { - const { data } = await this.#detailRepository.requestByKey(entityKey); + const { data } = await this.repository.requestByKey(entityKey); if (data) { this.setIsNew(false); this.#data.next(data); @@ -59,7 +54,7 @@ export class UmbMediaWorkspaceContext } async createScaffold(parentKey: string | null) { - const { data } = await this.#detailRepository.createScaffold(parentKey); + const { data } = await this.repository.createScaffold(parentKey); if (!data) return; this.setIsNew(true); this.#data.next(data); @@ -68,16 +63,16 @@ export class UmbMediaWorkspaceContext async save() { if (!this.#data.value) return; if (this.isNew) { - await this.#detailRepository.create(this.#data.value); + await this.repository.create(this.#data.value); } else { - await this.#detailRepository.save(this.#data.value); + await this.repository.save(this.#data.value); } // If it went well, then its not new anymore?. this.setIsNew(false); } async delete(key: string) { - await this.#detailRepository.delete(key); + await this.repository.delete(key); } public destroy(): void { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/menu.manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/menu.manifests.ts new file mode 100644 index 0000000000..48f15abb44 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/media/menu.manifests.ts @@ -0,0 +1,12 @@ +import { ManifestMenu } from '@umbraco-cms/extensions-registry'; + +const menu: ManifestMenu = { + type: 'menu', + alias: 'Umb.Menu.Media', + name: 'Media Menu', + meta: { + label: 'Media', + }, +}; + +export const manifests = [menu]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/media/section.manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/media/section.manifests.ts index 05557e3e1a..e7f137f2b8 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/media/section.manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/media/section.manifests.ts @@ -1,4 +1,4 @@ -import type { ManifestDashboardCollection, ManifestSection, ManifestSidebarMenu } from '@umbraco-cms/models'; +import type { ManifestDashboardCollection, ManifestSection, ManifestMenuSectionSidebarApp } from '@umbraco-cms/models'; const sectionAlias = 'Umb.Section.Media'; @@ -29,15 +29,16 @@ const dashboards: Array = [ }, ]; -const sidebarMenu: ManifestSidebarMenu = { - type: 'sidebarMenu', - alias: 'Umb.SidebarMenu.Media', - name: 'Media Sidebar Menu', +const menuSectionSidebarApp: ManifestMenuSectionSidebarApp = { + type: 'menuSectionSidebarApp', + alias: 'Umb.SectionSidebarMenu.Media', + name: 'Media Section Sidebar Menu', weight: 100, meta: { label: 'Media', sections: [sectionAlias], + menu: 'Umb.Menu.Media', }, }; -export const manifests = [section, sidebarMenu, ...dashboards]; +export const manifests = [section, menuSectionSidebarApp, ...dashboards]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/index.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/index.ts index 4ffc37485b..0f5f91f7e7 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/index.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/index.ts @@ -1,4 +1,5 @@ import { manifests as memberSectionManifests } from './section.manifests'; +import { manifests as menuSectionManifests } from './menu.manifests'; import { manifests as memberGroupManifests } from './member-groups/manifests'; import { manifests as memberTypeManifests } from './member-types/manifests'; import { manifests as memberManifests } from './members/manifests'; @@ -13,4 +14,10 @@ const registerExtensions = (manifests: Array) => { }); }; -registerExtensions([...memberSectionManifests, ...memberGroupManifests, ...memberTypeManifests, ...memberManifests]); +registerExtensions([ + ...memberSectionManifests, + ...menuSectionManifests, + ...memberGroupManifests, + ...memberTypeManifests, + ...memberManifests, +]); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/entity-actions/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/entity-actions/manifests.ts index 6b010cf284..5e84d8d6db 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/entity-actions/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/entity-actions/manifests.ts @@ -1,4 +1,4 @@ -import { UmbDeleteEntityAction } from '../../../shared/entity-actions/delete/delete.action'; +import { UmbDeleteEntityAction } from '@umbraco-cms/entity-action'; import { ManifestEntityAction } from 'libs/extensions-registry/entity-action.models'; const entityActions: Array = [ diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/manifests.ts index 629f81b657..bc9e01ae46 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/manifests.ts @@ -1,13 +1,13 @@ import { manifests as repositoryManifests } from './repository/manifests'; import { manifests as entityActionManifests } from './entity-actions/manifests'; -import { manifests as sidebarMenuItemManifests } from './sidebar-menu-item/manifests'; +import { manifests as menuItemManifests } from './menu-item/manifests'; import { manifests as treeManifests } from './tree/manifests'; import { manifests as workspaceManifests } from './workspace/manifests'; export const manifests = [ ...repositoryManifests, ...entityActionManifests, - ...sidebarMenuItemManifests, + ...menuItemManifests, ...treeManifests, ...workspaceManifests, ]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/menu-item/manifests.ts new file mode 100644 index 0000000000..cccc4c0247 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/menu-item/manifests.ts @@ -0,0 +1,16 @@ +import type { ManifestMenuItem } from '@umbraco-cms/models'; + +const menuItem: ManifestMenuItem = { + type: 'menuItem', + alias: 'Umb.MenuItem.MemberGroups', + name: 'Member Groups Menu Item', + weight: 800, + loader: () => import('./member-groups-menu-item.element'), + meta: { + label: 'Member Groups', + icon: 'umb:folder', + menus: ['Umb.Menu.Members'], + }, +}; + +export const manifests = [menuItem]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/sidebar-menu-item/member-groups-sidebar-menu-item.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/menu-item/member-groups-menu-item.element.ts similarity index 77% rename from src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/sidebar-menu-item/member-groups-sidebar-menu-item.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/menu-item/member-groups-menu-item.element.ts index 2ef51fc654..aaa72bd20a 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/sidebar-menu-item/member-groups-sidebar-menu-item.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/menu-item/member-groups-menu-item.element.ts @@ -2,8 +2,8 @@ import { html, nothing } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { UmbLitElement } from '@umbraco-cms/element'; -@customElement('umb-member-groups-sidebar-menu-item') -export class UmbMemberGroupsSidebarMenuItemElement extends UmbLitElement { +@customElement('umb-member-groups-menu-item') +export class UmbMemberGroupsMenuItemElement extends UmbLitElement { @state() private _renderTree = false; @@ -30,10 +30,10 @@ export class UmbMemberGroupsSidebarMenuItemElement extends UmbLitElement { } } -export default UmbMemberGroupsSidebarMenuItemElement; +export default UmbMemberGroupsMenuItemElement; declare global { interface HTMLElementTagNameMap { - 'umb-member-groups-sidebar-menu-item': UmbMemberGroupsSidebarMenuItemElement; + 'umb-member-groups-menu-item': UmbMemberGroupsMenuItemElement; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/sidebar-menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/sidebar-menu-item/manifests.ts deleted file mode 100644 index d3caac84de..0000000000 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/sidebar-menu-item/manifests.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { ManifestSidebarMenuItem } from '@umbraco-cms/models'; - -const sidebarMenuItem: ManifestSidebarMenuItem = { - type: 'sidebarMenuItem', - alias: 'Umb.SidebarMenuItem.MemberGroups', - name: 'Member Groups Sidebar Menu Item', - weight: 800, - loader: () => import('./member-groups-sidebar-menu-item.element'), - meta: { - label: 'Member Groups', - icon: 'umb:folder', - sidebarMenus: ['Umb.SidebarMenu.Members'], - }, -}; - -export const manifests = [sidebarMenuItem]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/workspace/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/workspace/manifests.ts index b6258433fb..da187f5066 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/workspace/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/workspace/manifests.ts @@ -1,5 +1,5 @@ import { MEMBER_GROUP_REPOSITORY_ALIAS } from '../repository/manifests'; -import { UmbSaveWorkspaceAction } from '../../../shared/workspace-actions/save.action'; +import { UmbSaveWorkspaceAction } from '@umbraco-cms/workspace'; import type { ManifestWorkspace, ManifestWorkspaceAction, ManifestWorkspaceView } from '@umbraco-cms/models'; const workspace: ManifestWorkspace = { @@ -38,7 +38,6 @@ const workspaceActions: Array = [ label: 'Save', look: 'primary', color: 'positive', - repositoryAlias: MEMBER_GROUP_REPOSITORY_ALIAS, api: UmbSaveWorkspaceAction, }, }, diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/workspace/member-group-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/workspace/member-group-workspace.context.ts index 0368570c64..6acdae22d8 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/workspace/member-group-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-groups/workspace/member-group-workspace.context.ts @@ -7,20 +7,15 @@ import { ObjectState } from '@umbraco-cms/observable-api'; type EntityType = MemberGroupDetails; export class UmbWorkspaceMemberGroupContext - extends UmbWorkspaceContext + extends UmbWorkspaceContext implements UmbWorkspaceEntityContextInterface { - #host: UmbControllerHostInterface; - #repo: UmbMemberGroupRepository; - #data = new ObjectState(undefined); data = this.#data.asObservable(); name = this.#data.getObservablePart((data) => data?.name); constructor(host: UmbControllerHostInterface) { - super(host); - this.#host = host; - this.#repo = new UmbMemberGroupRepository(this.#host); + super(host, new UmbMemberGroupRepository(host)); } getData() { @@ -46,14 +41,14 @@ export class UmbWorkspaceMemberGroupContext } async load(entityKey: string) { - const { data } = await this.#repo.requestByKey(entityKey); + const { data } = await this.repository.requestByKey(entityKey); if (data) { this.#data.next(data); } } async createScaffold() { - const { data } = await this.#repo.createScaffold(); + const { data } = await this.repository.createScaffold(); if (!data) return; this.setIsNew(true); this.#data.next(data); @@ -61,7 +56,7 @@ export class UmbWorkspaceMemberGroupContext async save() { if (!this.#data.value) return; - await this.#repo.save(this.#data.value); + await this.repository.save(this.#data.value); this.setIsNew(true); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/entity-actions/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/entity-actions/manifests.ts index 1926cca973..71e673d409 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/entity-actions/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/entity-actions/manifests.ts @@ -1,5 +1,5 @@ -import { UmbDeleteEntityAction } from '../../../../backoffice/shared/entity-actions/delete/delete.action'; import { MEMBER_TYPES_REPOSITORY_ALIAS } from '../repository/manifests'; +import { UmbDeleteEntityAction } from '@umbraco-cms/entity-action'; import type { ManifestEntityAction } from '@umbraco-cms/models'; const entityType = 'member-type'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/manifests.ts index cfe54ac0a3..430748aa0f 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/manifests.ts @@ -1,13 +1,13 @@ -import { manifests as sidebarMenuItemManifests } from './sidebar-menu-item/manifests'; +import { manifests as menuItemManifests } from './menu-item/manifests'; import { manifests as treeManifests } from './tree/manifests'; -import { manifests as respositoryManifests } from './repository/manifests'; +import { manifests as repositoryManifests } from './repository/manifests'; import { manifests as workspaceManifests } from './workspace/manifests'; import { manifests as entityActionManifests } from './entity-actions/manifests'; export const manifests = [ - ...sidebarMenuItemManifests, + ...menuItemManifests, ...treeManifests, - ...respositoryManifests, + ...repositoryManifests, ...workspaceManifests, ...entityActionManifests, ]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/menu-item/manifests.ts new file mode 100644 index 0000000000..02892c46d9 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/menu-item/manifests.ts @@ -0,0 +1,16 @@ +import type { ManifestMenuItem } from '@umbraco-cms/models'; + +const menuItem: ManifestMenuItem = { + type: 'menuItem', + alias: 'Umb.MenuItem.MemberTypes', + name: 'Member Types Menu Item', + weight: 30, + loader: () => import('./member-types-menu-item.element'), + meta: { + label: 'Member Types', + icon: 'umb:folder', + menus: ['Umb.Menu.Settings'], + }, +}; + +export const manifests = [menuItem]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/sidebar-menu-item/member-types-sidebar-menu-item.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/menu-item/member-types-menu-item.element.ts similarity index 77% rename from src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/sidebar-menu-item/member-types-sidebar-menu-item.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/menu-item/member-types-menu-item.element.ts index d23919ce4c..42e3449cc6 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/sidebar-menu-item/member-types-sidebar-menu-item.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/menu-item/member-types-menu-item.element.ts @@ -2,8 +2,8 @@ import { html, nothing } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { UmbLitElement } from '@umbraco-cms/element'; -@customElement('umb-member-types-sidebar-menu-item') -export class UmbMemberTypesSidebarMenuItemElement extends UmbLitElement { +@customElement('umb-member-types-menu-item') +export class UmbMemberTypesMenuItemElement extends UmbLitElement { @state() private _renderTree = false; @@ -30,10 +30,10 @@ export class UmbMemberTypesSidebarMenuItemElement extends UmbLitElement { } } -export default UmbMemberTypesSidebarMenuItemElement; +export default UmbMemberTypesMenuItemElement; declare global { interface HTMLElementTagNameMap { - 'umb-member-types-sidebar-menu-item': UmbMemberTypesSidebarMenuItemElement; + 'umb-member-types-menu-item': UmbMemberTypesMenuItemElement; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/sidebar-menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/sidebar-menu-item/manifests.ts deleted file mode 100644 index e62397b44b..0000000000 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/sidebar-menu-item/manifests.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { ManifestSidebarMenuItem } from '@umbraco-cms/models'; - -const sidebarMenuItem: ManifestSidebarMenuItem = { - type: 'sidebarMenuItem', - alias: 'Umb.SidebarMenuItem.MemberTypes', - name: 'Member Types Sidebar Menu Item', - weight: 30, - loader: () => import('./member-types-sidebar-menu-item.element'), - meta: { - label: 'Member Types', - icon: 'umb:folder', - sidebarMenus: ['Umb.SidebarMenu.Settings'], - }, -}; - -export const manifests = [sidebarMenuItem]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/workspace/member-type-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/workspace/member-type-workspace.context.ts index 166d07c469..ac7107e361 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/workspace/member-type-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/member-types/workspace/member-type-workspace.context.ts @@ -8,23 +8,18 @@ import { UmbControllerHostInterface } from '@umbraco-cms/controller'; type EntityType = any; export class UmbWorkspaceMemberTypeContext - extends UmbWorkspaceContext + extends UmbWorkspaceContext implements UmbWorkspaceEntityContextInterface { - #host: UmbControllerHostInterface; - #dataTypeRepository: UmbMemberTypeRepository; - #data = new ObjectState(undefined); name = this.#data.getObservablePart((data) => data?.name); constructor(host: UmbControllerHostInterface) { - super(host); - this.#host = host; - this.#dataTypeRepository = new UmbMemberTypeRepository(this.#host); + super(host, new UmbMemberTypeRepository(host)); } async load(entityKey: string) { - const { data } = await this.#dataTypeRepository.requestByKey(entityKey); + const { data } = await this.repository.requestByKey(entityKey); if (data) { this.setIsNew(false); this.#data.next(data); @@ -32,7 +27,7 @@ export class UmbWorkspaceMemberTypeContext } async createScaffold() { - const { data } = await this.#dataTypeRepository.createScaffold(); + const { data } = await this.repository.createScaffold(); if (!data) return; this.setIsNew(true); this.#data.next(data); @@ -61,16 +56,16 @@ export class UmbWorkspaceMemberTypeContext async save() { if (!this.#data.value) return; if (this.isNew) { - await this.#dataTypeRepository.create(this.#data.value); + await this.repository.create(this.#data.value); } else { - await this.#dataTypeRepository.save(this.#data.value); + await this.repository.save(this.#data.value); } // If it went well, then its not new anymore?. this.setIsNew(false); } async delete(key: string) { - await this.#dataTypeRepository.delete(key); + await this.repository.delete(key); } public destroy(): void { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/entity-actions/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/entity-actions/manifests.ts index 679b387dbf..6f040a256b 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/entity-actions/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/entity-actions/manifests.ts @@ -1,4 +1,4 @@ -import { UmbDeleteEntityAction } from '../../../shared/entity-actions/delete/delete.action'; +import { UmbDeleteEntityAction } from '@umbraco-cms/entity-action'; import { ManifestEntityAction } from 'libs/extensions-registry/entity-action.models'; const entityActions: Array = [ diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/manifests.ts index 629f81b657..bc9e01ae46 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/manifests.ts @@ -1,13 +1,13 @@ import { manifests as repositoryManifests } from './repository/manifests'; import { manifests as entityActionManifests } from './entity-actions/manifests'; -import { manifests as sidebarMenuItemManifests } from './sidebar-menu-item/manifests'; +import { manifests as menuItemManifests } from './menu-item/manifests'; import { manifests as treeManifests } from './tree/manifests'; import { manifests as workspaceManifests } from './workspace/manifests'; export const manifests = [ ...repositoryManifests, ...entityActionManifests, - ...sidebarMenuItemManifests, + ...menuItemManifests, ...treeManifests, ...workspaceManifests, ]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/menu-item/manifests.ts new file mode 100644 index 0000000000..4ab22621b1 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/menu-item/manifests.ts @@ -0,0 +1,17 @@ +import type { ManifestMenuItem } from '@umbraco-cms/models'; + +const menuItem: ManifestMenuItem = { + type: 'menuItem', + alias: 'Umb.MenuItem.Members', + name: 'Members Menu Item', + weight: 400, + loader: () => import('./members-menu-item.element'), + meta: { + label: 'Members', + icon: 'umb:folder', + entityType: 'member', + menus: ['Umb.Menu.Members'], + }, +}; + +export const manifests = [menuItem]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/sidebar-menu-item/members-sidebar-menu-item.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/menu-item/members-menu-item.element.ts similarity index 79% rename from src/Umbraco.Web.UI.Client/src/backoffice/members/members/sidebar-menu-item/members-sidebar-menu-item.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/members/members/menu-item/members-menu-item.element.ts index 8ab8e3b82e..a5ab1f7248 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/sidebar-menu-item/members-sidebar-menu-item.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/menu-item/members-menu-item.element.ts @@ -2,8 +2,8 @@ import { html, nothing } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { UmbLitElement } from '@umbraco-cms/element'; -@customElement('umb-members-sidebar-menu-item') -export class UmbMembersSidebarMenuItemElement extends UmbLitElement { +@customElement('umb-members-menu-item') +export class UmbMembersMenuItemElement extends UmbLitElement { @state() private _renderTree = false; @@ -30,10 +30,10 @@ export class UmbMembersSidebarMenuItemElement extends UmbLitElement { } } -export default UmbMembersSidebarMenuItemElement; +export default UmbMembersMenuItemElement; declare global { interface HTMLElementTagNameMap { - 'umb-members-sidebar-menu-item': UmbMembersSidebarMenuItemElement; + 'umb-members-menu-item': UmbMembersMenuItemElement; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/sidebar-menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/sidebar-menu-item/manifests.ts deleted file mode 100644 index c8935378c2..0000000000 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/sidebar-menu-item/manifests.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { ManifestSidebarMenuItem } from '@umbraco-cms/models'; - -const sidebarMenuItem: ManifestSidebarMenuItem = { - type: 'sidebarMenuItem', - alias: 'Umb.SidebarMenuItem.Members', - name: 'Members Sidebar Menu Item', - weight: 400, - loader: () => import('./members-sidebar-menu-item.element'), - meta: { - label: 'Members', - icon: 'umb:folder', - entityType: 'member', - sidebarMenus: ['Umb.SidebarMenu.Members'], - }, -}; - -export const manifests = [sidebarMenuItem]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/workspace/member-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/workspace/member-workspace.context.ts index 1dd1698dc5..b7cb38e6ec 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/members/workspace/member-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/members/workspace/member-workspace.context.ts @@ -2,17 +2,23 @@ import { UmbEntityWorkspaceManager } from '../../../shared/components/workspace/ import { UmbWorkspaceContext } from '../../../shared/components/workspace/workspace-context/workspace-context'; import { UmbWorkspaceEntityContextInterface } from '../../../shared/components/workspace/workspace-context/workspace-entity-context.interface'; import { UMB_MEMBER_DETAIL_STORE_CONTEXT_TOKEN } from '../member.detail.store'; +import { UmbMemberRepository } from '../repository/member.repository'; import type { MemberDetails } from '@umbraco-cms/models'; +import { UmbControllerHostInterface } from '@umbraco-cms/controller'; export class UmbWorkspaceMemberContext - extends UmbWorkspaceContext + extends UmbWorkspaceContext implements UmbWorkspaceEntityContextInterface { - #manager = new UmbEntityWorkspaceManager(this._host, 'member', UMB_MEMBER_DETAIL_STORE_CONTEXT_TOKEN); + #manager = new UmbEntityWorkspaceManager(this.host, 'member', UMB_MEMBER_DETAIL_STORE_CONTEXT_TOKEN); public readonly data = this.#manager.state.asObservable(); public readonly name = this.#manager.state.getObservablePart((state) => state?.name); + constructor(host: UmbControllerHostInterface) { + super(host, new UmbMemberRepository(host)); + } + setPropertyValue(alias: string, value: string) { return; } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/menu.manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/menu.manifests.ts new file mode 100644 index 0000000000..1bd7ca6a85 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/menu.manifests.ts @@ -0,0 +1,12 @@ +import { ManifestMenu } from '@umbraco-cms/extensions-registry'; + +const menu: ManifestMenu = { + type: 'menu', + alias: 'Umb.Menu.Members', + name: 'Members Menu', + meta: { + label: 'Members', + }, +}; + +export const manifests = [menu]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/members/section.manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/members/section.manifests.ts index aa94eb7b7a..bfc8719566 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/members/section.manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/members/section.manifests.ts @@ -1,4 +1,4 @@ -import type { ManifestDashboard, ManifestSection, ManifestSidebarMenu } from '@umbraco-cms/models'; +import type { ManifestDashboard, ManifestSection, ManifestMenuSectionSidebarApp } from '@umbraco-cms/models'; const sectionAlias = 'Umb.Section.Members'; @@ -28,15 +28,16 @@ const dashboards: Array = [ }, ]; -const sidebarMenu: ManifestSidebarMenu = { - type: 'sidebarMenu', - alias: 'Umb.SidebarMenu.Members', - name: 'Members Sidebar Menu', +const menuSectionSidebarApp: ManifestMenuSectionSidebarApp = { + type: 'menuSectionSidebarApp', + alias: 'Umb.SectionSidebarMenu.Members', + name: 'Members Section Sidebar Menu', weight: 100, meta: { label: 'Members', sections: [sectionAlias], + menu: 'Umb.Menu.Members', }, }; -export const manifests = [section, sidebarMenu, ...dashboards]; +export const manifests = [section, menuSectionSidebarApp, ...dashboards]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-section/views/installed/packages-installed-item.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-section/views/installed/installed-packages-section-view-item.element.ts similarity index 69% rename from src/Umbraco.Web.UI.Client/src/backoffice/packages/package-section/views/installed/packages-installed-item.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/packages/package-section/views/installed/installed-packages-section-view-item.element.ts index 0ef2ee1f54..23025cb334 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-section/views/installed/packages-installed-item.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-section/views/installed/installed-packages-section-view-item.element.ts @@ -1,17 +1,18 @@ import { html, nothing } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; +import { ifDefined } from 'lit/directives/if-defined.js'; import { firstValueFrom, map } from 'rxjs'; import { UmbModalService, UMB_MODAL_SERVICE_CONTEXT_TOKEN } from '../../../../../core/modal'; -import { createExtensionElement , umbExtensionsRegistry } from '@umbraco-cms/extensions-api'; +import { createExtensionElement, umbExtensionsRegistry } from '@umbraco-cms/extensions-api'; -import type { ManifestPackageView } from '@umbraco-cms/models'; +import type { ManifestPackageView, UmbPackage } from '@umbraco-cms/models'; import { UmbLitElement } from '@umbraco-cms/element'; -@customElement('umb-packages-installed-item') -export class UmbPackagesInstalledItem extends UmbLitElement { +@customElement('umb-installed-packages-section-view-item') +export class UmbInstalledPackagesSectionViewItemElement extends UmbLitElement { @property({ type: Object }) - package!: any; // TODO: Use real type + package!: UmbPackage; @state() private _packageView?: ManifestPackageView; @@ -28,13 +29,16 @@ export class UmbPackagesInstalledItem extends UmbLitElement { connectedCallback(): void { super.connectedCallback(); - this.findPackageView(this.package.alias); + + if (this.package.name?.length) { + this.findPackageView(this.package.name); + } } private async findPackageView(alias: string) { const observable = umbExtensionsRegistry ?.extensionsOfType('packageView') - .pipe(map((e) => e.filter((m) => m.meta.packageAlias === alias))); + .pipe(map((e) => e.filter((m) => m.meta.packageName === alias))); if (!observable) { return; @@ -50,7 +54,7 @@ export class UmbPackagesInstalledItem extends UmbLitElement { render() { return html` - + ${this._packageView ? html` = []; +@customElement('umb-installed-packages-section-view') +export class UmbInstalledPackagesSectionView extends UmbLitElement { + @state() + private _installedPackages: UmbPackage[] = []; + + private repository: UmbPackageRepository; constructor() { super(); - this.observe(umbExtensionsRegistry?.extensionsOfType('workspace'), (workspaceExtensions) => { - this._workspaces = workspaceExtensions; - this._createRoutes(); - }); + this.repository = new UmbPackageRepository(this); } - private _createRoutes() { - const routes: any[] = [ - { - path: 'overview', - component: () => import('./packages-installed-overview.element'), - }, - ]; + firstUpdated() { + this._loadInstalledPackages(); + } - // TODO: find a way to make this reuseable across: - this._workspaces?.map((workspace: ManifestWorkspace) => { - routes.push({ - path: `${workspace.meta.entityType}/:key`, - component: () => createExtensionElement(workspace), - setup: (component: Promise, info: IRoutingInfo) => { - component.then((el: HTMLElement) => { - (el as any).entityKey = info.match.params.key; - }); - }, - }); - routes.push({ - path: workspace.meta.entityType, - component: () => createExtensionElement(workspace), - }); + /** + * 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); }); - - routes.push({ - path: '**', - redirectTo: 'section/packages/view/installed/overview', //TODO: this should be dynamic - }); - this._routes = routes; } render() { - return html``; + return html` + + ${repeat( + this._installedPackages, + (item) => item.name, + (item) => + html`` + )} + + `; } } -export default UmbInstalledPackagesSectionViewElement; +export default UmbInstalledPackagesSectionView; declare global { interface HTMLElementTagNameMap { - 'umb-section-view-packages-installed': UmbInstalledPackagesSectionViewElement; + 'umb-installed-packages-section-view': UmbInstalledPackagesSectionView; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-section/views/installed/packages-installed-overview.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-section/views/installed/packages-installed-overview.element.ts deleted file mode 100644 index eaee3d37bd..0000000000 --- a/src/Umbraco.Web.UI.Client/src/backoffice/packages/package-section/views/installed/packages-installed-overview.element.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { html, LitElement, nothing } from 'lit'; -import { customElement, state } from 'lit/decorators.js'; -import { repeat } from 'lit/directives/repeat.js'; - -import './packages-installed-item.element'; - -@customElement('umb-packages-installed-overview') -export class UmbPackagesInstalledOverviewElement extends LitElement { - @state() - private _installedPackages: any[] = []; // TODO: Use real type - - @state() - private _errorMessage = ''; - - firstUpdated() { - this._loadInstalledPackages(); - } - - /** - * Fetch the installed packages from the server - */ - private async _loadInstalledPackages() { - this._errorMessage = ''; - - // TODO: Implement when API is ready - // try { - // const { - // data: { packages }, - // } = await getPackagesInstalled({}); - // this._installedPackages = packages; - // } catch (e) { - // if (e instanceof getPackagesInstalled.Error) { - // const error = e.getActualType(); - // this._errorMessage = error.data.detail ?? 'An error occurred while loading the installed packages'; - // } - // } - } - - render() { - return html` - ${this._errorMessage ? html`${this._errorMessage}` : nothing} - - ${repeat( - this._installedPackages, - (item) => item.id, - (item) => html`` - )} - - `; - } -} - -export default UmbPackagesInstalledOverviewElement; - -declare global { - interface HTMLElementTagNameMap { - 'umb-packages-installed': UmbPackagesInstalledOverviewElement; - } -} 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 new file mode 100644 index 0000000000..ec54c779b4 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/packages/repository/package.repository.ts @@ -0,0 +1,101 @@ +import { UmbPackageStore, UMB_PACKAGE_STORE_TOKEN } from './package.store'; +import { UmbPackageServerDataSource } from './sources/package.server.data'; +import { UmbControllerHostInterface } from '@umbraco-cms/controller'; +import { UmbContextConsumerController } from '@umbraco-cms/context-api'; +import { ManifestBase } from '@umbraco-cms/extensions-registry'; + +// TODO: Figure out if we should base stores like this on something more generic for "collections" rather than trees. + +/** + * A repository for Packages which mimicks a tree store. + * @export + */ +export class UmbPackageRepository { + #init!: Promise; + #packageStore?: UmbPackageStore; + #packageSource: UmbPackageServerDataSource; + + constructor(host: UmbControllerHostInterface) { + this.#packageSource = new UmbPackageServerDataSource(host); + this.#init = new Promise((res) => { + new UmbContextConsumerController(host, UMB_PACKAGE_STORE_TOKEN, (instance) => { + this.#packageStore = instance; + this.requestRootItems(instance); + this.requestPackageMigrations(instance); + res(); + }); + }); + } + + /** + * Request the root items from the Data Source + * @memberOf UmbPackageRepository + */ + async requestRootItems(store: UmbPackageStore) { + if (store.isPackagesLoaded) { + return; + } + + const { data: packages } = await this.#packageSource.getRootItems(); + + if (packages) { + store.appendItems(packages); + const extensions: ManifestBase[] = []; + + packages.forEach((p) => { + p.extensions?.forEach((e) => { + // Crudely validate that the extension at least follows a basic manifest structure + // Idea: Use `Zod` to validate the manifest + if (this.isManifestBase(e)) { + extensions.push(e); + } + }); + }); + + store.appendExtensions(extensions); + } + } + + /** + * Request the package migrations from the Data Source + * @memberOf UmbPackageRepository + */ + async requestPackageMigrations(store: UmbPackageStore) { + const { data: migrations } = await this.#packageSource.getPackageMigrations(); + + if (migrations) { + store.appendMigrations(migrations.items); + } + } + + /** + * Observable of root items + * @memberOf UmbPackageRepository + */ + async rootItems() { + await this.#init; + return this.#packageStore!.rootItems; + } + + /** + * Observable of extensions + * @memberOf UmbPackageRepository + */ + async extensions() { + await this.#init; + return this.#packageStore!.extensions; + } + + /** + * Observable of migrations + * @memberOf UmbPackageRepository + */ + async migrations() { + await this.#init; + return this.#packageStore!.migrations; + } + + private isManifestBase(x: unknown): x is ManifestBase { + return typeof x === 'object' && x !== null && 'alias' in x; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/packages/repository/package.store.ts b/src/Umbraco.Web.UI.Client/src/backoffice/packages/repository/package.store.ts new file mode 100644 index 0000000000..f581b2045d --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/packages/repository/package.store.ts @@ -0,0 +1,62 @@ +import { ReplaySubject } from 'rxjs'; +import { UmbContextToken } from '@umbraco-cms/context-api'; +import { UmbControllerHostInterface } from '@umbraco-cms/controller'; +import { UmbStoreBase } from '@umbraco-cms/store'; +import type { ManifestBase, UmbPackage } from '@umbraco-cms/models'; +import type { PackageMigrationStatusModel } from '@umbraco-cms/backend-api'; +import { ArrayState } from '@umbraco-cms/observable-api'; + +/** + * Store for Packages + * @export + * @extends {UmbStoreBase} + */ +export class UmbPackageStore extends UmbStoreBase { + /** + * Array of packages with extensions + * @private + */ + #packages = new ReplaySubject>(1); + + #extensions = new ArrayState([], (e) => e.alias); + + #migrations = new ArrayState([], (e) => e.packageName); + + /** + * Observable of packages with extensions + */ + rootItems = this.#packages.asObservable(); + + extensions = this.#extensions.asObservable(); + + migrations = this.#migrations.asObservable(); + + isPackagesLoaded = false; + + /** + * Creates an instance of PackageStore. + * @param {UmbControllerHostInterface} host + * @memberof PackageStore + */ + constructor(host: UmbControllerHostInterface) { + super(host, UmbPackageStore.name); + } + + /** + * Append items to the store + */ + appendItems(packages: Array) { + this.#packages.next(packages); + this.isPackagesLoaded = true; + } + + appendExtensions(extensions: ManifestBase[]) { + this.#extensions.append(extensions); + } + + appendMigrations(migrations: PackageMigrationStatusModel[]) { + this.#migrations.append(migrations); + } +} + +export const UMB_PACKAGE_STORE_TOKEN = new UmbContextToken(UmbPackageStore.name); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/packages/repository/server-extension.controller.ts b/src/Umbraco.Web.UI.Client/src/backoffice/packages/repository/server-extension.controller.ts new file mode 100644 index 0000000000..0073576b89 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/packages/repository/server-extension.controller.ts @@ -0,0 +1,45 @@ +import { Subject, takeUntil } from 'rxjs'; +import { UmbPackageRepository } from './package.repository'; +import { UmbController, UmbControllerHostInterface } from '@umbraco-cms/controller'; +import { isManifestJSType, UmbExtensionRegistry } from '@umbraco-cms/extensions-api'; + +export class UmbServerExtensionController extends UmbController { + #unobserve = new Subject(); + #repository: UmbPackageRepository; + + constructor(host: UmbControllerHostInterface, private readonly extensionRegistry: UmbExtensionRegistry) { + super(host, UmbServerExtensionController.name); + + this.#repository = new UmbPackageRepository(host); + } + + hostConnected(): void { + this.#loadPackages(); + } + + hostDisconnected(): void { + this.#unobserve.next(); + this.#unobserve.complete(); + } + + async #loadPackages() { + const extensions$ = await this.#repository.extensions(); + + extensions$ + .pipe( + // If the app breaks then stop the request + takeUntil(this.#unobserve) + ) + .subscribe((extensions) => { + extensions.forEach((extension) => { + /** + * Crude check to see if extension is of type "js" since it is safe to assume we do not + * need to load any other types of extensions in the backoffice (we need a js file to load) + */ + if (isManifestJSType(extension)) { + this.extensionRegistry.register(extension); + } + }); + }); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/packages/repository/sources/package.server.data.ts b/src/Umbraco.Web.UI.Client/src/backoffice/packages/repository/sources/package.server.data.ts new file mode 100644 index 0000000000..e2bdd212fa --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/packages/repository/sources/package.server.data.ts @@ -0,0 +1,33 @@ +import { PackageResource } from '@umbraco-cms/backend-api'; +import { UmbControllerHostInterface } from '@umbraco-cms/controller'; +import type { DataSourceResponse, UmbPackage } from '@umbraco-cms/models'; +import { tryExecuteAndNotify } from '@umbraco-cms/resources'; +import { umbracoPath } from '@umbraco-cms/utils'; + +/** + * Data source for packages from the server + * @export + */ +export class UmbPackageServerDataSource { + constructor(private readonly host: UmbControllerHostInterface) {} + + /** + * Get the root items from the server + * @memberof UmbPackageServerDataSource + */ + getRootItems(): Promise> { + // TODO: Use real resource when available + return tryExecuteAndNotify( + this.host, + fetch(umbracoPath('/package/manifest')).then((res) => res.json()) + ); + } + + /** + * Get the package migrations from the server + * @memberof UmbPackageServerDataSource + */ + getPackageMigrations() { + return tryExecuteAndNotify(this.host, PackageResource.getPackageMigrationStatus({ skip: 0, take: 9999 })); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/manifests.ts index 7fddd3f55d..ddaa4babdc 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/manifests.ts @@ -1,6 +1,6 @@ import { manifests as repositoryManifests } from './repository/manifests'; -import { manifests as sidebarMenuItemManifests } from './sidebar-menu-item/manifests'; +import { manifests as menuItemManifests } from './menu-item/manifests'; import { manifests as treeManifests } from './tree/manifests'; import { manifests as workspaceManifests } from './workspace/manifests'; -export const manifests = [...repositoryManifests, ...sidebarMenuItemManifests, ...treeManifests, ...workspaceManifests]; +export const manifests = [...repositoryManifests, ...menuItemManifests, ...treeManifests, ...workspaceManifests]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/sidebar-menu-item/data-types-sidebar-menu-item.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/menu-item/data-types-menu-item.element.ts similarity index 78% rename from src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/sidebar-menu-item/data-types-sidebar-menu-item.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/menu-item/data-types-menu-item.element.ts index cb94248015..2887568f1b 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/sidebar-menu-item/data-types-sidebar-menu-item.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/menu-item/data-types-menu-item.element.ts @@ -2,8 +2,8 @@ import { html, nothing } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { UmbLitElement } from '@umbraco-cms/element'; -@customElement('umb-data-types-sidebar-menu-item') -export class UmbDataTypesSidebarMenuItemElement extends UmbLitElement { +@customElement('umb-data-types-menu-item') +export class UmbDataTypesMenuItemElement extends UmbLitElement { @state() private _renderTree = false; @@ -31,10 +31,10 @@ export class UmbDataTypesSidebarMenuItemElement extends UmbLitElement { } } -export default UmbDataTypesSidebarMenuItemElement; +export default UmbDataTypesMenuItemElement; declare global { interface HTMLElementTagNameMap { - 'umb-data-types-sidebar-menu-item': UmbDataTypesSidebarMenuItemElement; + 'umb-data-types-menu-item': UmbDataTypesMenuItemElement; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/menu-item/manifests.ts new file mode 100644 index 0000000000..25eb1fdef7 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/menu-item/manifests.ts @@ -0,0 +1,17 @@ +import type { ManifestMenuItem } from '@umbraco-cms/models'; + +const menuItem: ManifestMenuItem = { + type: 'menuItem', + alias: 'Umb.MenuItem.DataTypes', + name: 'Data Types Menu Item', + weight: 40, + loader: () => import('./data-types-menu-item.element'), + meta: { + label: 'Data Types', + icon: 'umb:folder', + entityType: 'data-type', + menus: ['Umb.Menu.Settings'], + }, +}; + +export const manifests = [menuItem]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/sidebar-menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/sidebar-menu-item/manifests.ts deleted file mode 100644 index 5d8ce90554..0000000000 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/sidebar-menu-item/manifests.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { ManifestSidebarMenuItem } from '@umbraco-cms/models'; - -const sidebarMenuItem: ManifestSidebarMenuItem = { - type: 'sidebarMenuItem', - alias: 'Umb.SidebarMenuItem.DataTypes', - name: 'Data Types Sidebar Menu Item', - weight: 40, - loader: () => import('./data-types-sidebar-menu-item.element'), - meta: { - label: 'Data Types', - icon: 'umb:folder', - entityType: 'data-type', - sidebarMenus: ['Umb.SidebarMenu.Settings'], - }, -}; - -export const manifests = [sidebarMenuItem]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/workspace/data-type-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/workspace/data-type-workspace.context.ts index e07767d67a..531531c39d 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/workspace/data-type-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/workspace/data-type-workspace.context.ts @@ -6,25 +6,20 @@ import { appendToFrozenArray, ObjectState } from '@umbraco-cms/observable-api'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; export class UmbDataTypeWorkspaceContext - extends UmbWorkspaceContext + extends UmbWorkspaceContext implements UmbWorkspaceEntityContextInterface { - #host: UmbControllerHostInterface; - #dataTypeRepository: UmbDataTypeRepository; - #data = new ObjectState(undefined); data = this.#data.asObservable(); name = this.#data.getObservablePart((data) => data?.name); key = this.#data.getObservablePart((data) => data?.key); constructor(host: UmbControllerHostInterface) { - super(host); - this.#host = host; - this.#dataTypeRepository = new UmbDataTypeRepository(this.#host); + super(host, new UmbDataTypeRepository(host)); } async load(key: string) { - const { data } = await this.#dataTypeRepository.requestByKey(key); + const { data } = await this.repository.requestByKey(key); if (data) { this.setIsNew(false); this.#data.update(data); @@ -32,7 +27,7 @@ export class UmbDataTypeWorkspaceContext } async createScaffold(parentKey: string | null) { - const { data } = await this.#dataTypeRepository.createScaffold(parentKey); + const { data } = await this.repository.createScaffold(parentKey); if (!data) return; this.setIsNew(true); this.#data.next(data); @@ -76,16 +71,16 @@ export class UmbDataTypeWorkspaceContext async save() { if (!this.#data.value) return; if (this.isNew) { - await this.#dataTypeRepository.create(this.#data.value); + await this.repository.create(this.#data.value); } else { - await this.#dataTypeRepository.save(this.#data.value); + await this.repository.save(this.#data.value); } // If it went well, then its not new anymore?. this.setIsNew(false); } async delete(key: string) { - await this.#dataTypeRepository.delete(key); + await this.repository.delete(key); } public destroy(): void { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/workspace/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/workspace/manifests.ts index 952199ab0b..f23cb76d4e 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/workspace/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/data-types/workspace/manifests.ts @@ -1,3 +1,4 @@ +import { UmbSaveWorkspaceAction } from '@umbraco-cms/workspace'; import type { ManifestWorkspace, ManifestWorkspaceAction, ManifestWorkspaceView } from '@umbraco-cms/models'; const workspace: ManifestWorkspace = { @@ -44,12 +45,12 @@ const workspaceActions: Array = [ type: 'workspaceAction', alias: 'Umb.WorkspaceAction.DataType.Save', name: 'Save Data Type Workspace Action', - loader: () => - import('src/backoffice/shared/components/workspace/workspace-action/save/workspace-action-node-save.element'), meta: { workspaces: ['Umb.Workspace.DataType'], + label: 'Save', look: 'primary', color: 'positive', + api: UmbSaveWorkspaceAction, }, }, ]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/extensions/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/extensions/manifests.ts index 91d087379a..5bee1cd866 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/extensions/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/extensions/manifests.ts @@ -1,4 +1,4 @@ -import { manifests as sidebarMenuItemManifests } from './sidebar-menu-item/manifests'; +import { manifests as menuItemManifests } from './menu-item/manifests'; import { manifests as workspaceManifests } from './workspace/manifests'; -export const manifests = [...sidebarMenuItemManifests, ...workspaceManifests]; +export const manifests = [...menuItemManifests, ...workspaceManifests]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/extensions/menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/extensions/menu-item/manifests.ts new file mode 100644 index 0000000000..aa8ba20a12 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/extensions/menu-item/manifests.ts @@ -0,0 +1,16 @@ +import type { ManifestMenuItem } from '@umbraco-cms/models'; + +const menuItem: ManifestMenuItem = { + type: 'menuItem', + alias: 'Umb.MenuItem.Extensions', + name: 'Extensions Menu Item', + weight: 100, + meta: { + label: 'Extensions', + icon: 'umb:wand', + entityType: 'extension-root', + menus: ['Umb.Menu.Settings'], + }, +}; + +export const manifests = [menuItem]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/extensions/sidebar-menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/extensions/sidebar-menu-item/manifests.ts deleted file mode 100644 index 12b25aaf7f..0000000000 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/extensions/sidebar-menu-item/manifests.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { ManifestSidebarMenuItem } from '@umbraco-cms/models'; - -const sidebarMenuItem: ManifestSidebarMenuItem = { - type: 'sidebarMenuItem', - alias: 'Umb.SidebarMenuItem.Extensions', - name: 'Extensions Sidebar Menu Item', - weight: 100, - meta: { - label: 'Extensions', - icon: 'umb:wand', - entityType: 'extension-root', - sidebarMenus: ['Umb.SidebarMenu.Settings'], - }, -}; - -export const manifests = [sidebarMenuItem]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/index.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/index.ts index 43ef6bfa40..f566504513 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/index.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/index.ts @@ -1,4 +1,5 @@ import { manifests as settingsSectionManifests } from './section.manifests'; +import { manifests as settingsMenuManifests } from './menu.manifests'; import { manifests as dashboardManifests } from './dashboards/manifests'; import { manifests as dataTypeManifests } from './data-types/manifests'; import { manifests as extensionManifests } from './extensions/manifests'; @@ -18,6 +19,7 @@ const registerExtensions = (manifests: Array) => { registerExtensions([ ...settingsSectionManifests, + ...settingsMenuManifests, ...dashboardManifests, ...dataTypeManifests, ...extensionManifests, diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/app-language-select.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/app-language-select/app-language-select.element.ts similarity index 96% rename from src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/app-language-select.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/app-language-select/app-language-select.element.ts index 1415471f37..d0a2f1604d 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/app-language-select.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/app-language-select/app-language-select.element.ts @@ -4,7 +4,7 @@ import { customElement, state } from 'lit/decorators.js'; import { repeat } from 'lit/directives/repeat.js'; import { ifDefined } from 'lit-html/directives/if-defined.js'; import { UUIMenuItemEvent } from '@umbraco-ui/uui'; -import { UmbLanguageRepository } from './repository/language.repository'; +import { UmbLanguageRepository } from '../repository/language.repository'; import { UMB_APP_LANGUAGE_CONTEXT_TOKEN, UmbAppLanguageContext } from './app-language.context'; import { UmbLitElement } from '@umbraco-cms/element'; import { LanguageModel } from '@umbraco-cms/backend-api'; @@ -142,6 +142,8 @@ export class UmbAppLanguageSelectElement extends UmbLitElement { } } +export default UmbAppLanguageSelectElement; + declare global { interface HTMLElementTagNameMap { 'umb-app-language-select': UmbAppLanguageSelectElement; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/app-language.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/app-language-select/app-language.context.ts similarity index 95% rename from src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/app-language.context.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/app-language-select/app-language.context.ts index 603e2e4955..82c2d32649 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/app-language.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/app-language-select/app-language.context.ts @@ -1,4 +1,4 @@ -import { UmbLanguageRepository } from './repository/language.repository'; +import { UmbLanguageRepository } from '../repository/language.repository'; import { ObjectState, UmbObserverController } from '@umbraco-cms/observable-api'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; import { UmbContextToken } from '@umbraco-cms/context-api'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/app-language-select/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/app-language-select/manifests.ts new file mode 100644 index 0000000000..345c971563 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/app-language-select/manifests.ts @@ -0,0 +1,15 @@ +import { ManifestSectionSidebarApp } from '@umbraco-cms/extensions-registry'; + +const entityActions: Array = [ + { + type: 'sectionSidebarApp', + alias: 'Umb.SectionSidebarItem.LanguageSelect', + name: 'App Language Select Section Sidebar Item', + loader: () => import('./app-language-select.element'), + meta: { + sections: ['Umb.Section.Content'], + }, + }, +]; + +export const manifests = [...entityActions]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/entity-actions/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/entity-actions/manifests.ts index 84b57075b0..e8846b75a6 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/entity-actions/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/entity-actions/manifests.ts @@ -1,4 +1,4 @@ -import { UmbDeleteEntityAction } from '../../../shared/entity-actions/delete/delete.action'; +import { UmbDeleteEntityAction } from '@umbraco-cms/entity-action'; import { ManifestEntityAction } from '@umbraco-cms/extensions-registry'; const entityType = 'language'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/manifests.ts index c7e92f8c72..4d649f5cd8 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/manifests.ts @@ -1,6 +1,13 @@ import { manifests as repositoryManifests } from './repository/manifests'; -import { manifests as treeManifests } from './sidebar-menu-item/manifests'; +import { manifests as treeManifests } from './menu-item/manifests'; import { manifests as entityActions } from './entity-actions/manifests'; import { manifests as workspaceManifests } from './workspace/manifests'; +import { manifests as appLanguageSelect } from './app-language-select/manifests'; -export const manifests = [...repositoryManifests, ...entityActions, ...treeManifests, ...workspaceManifests]; +export const manifests = [ + ...repositoryManifests, + ...entityActions, + ...treeManifests, + ...workspaceManifests, + ...appLanguageSelect, +]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/menu-item/manifests.ts new file mode 100644 index 0000000000..258f0a95c1 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/menu-item/manifests.ts @@ -0,0 +1,16 @@ +import type { ManifestMenuItem } from '@umbraco-cms/models'; + +const menuItem: ManifestMenuItem = { + type: 'menuItem', + alias: 'Umb.MenuItem.Languages', + name: 'Languages Menu Item', + weight: 80, + meta: { + label: 'Languages', + icon: 'umb:globe', + entityType: 'language-root', + menus: ['Umb.Menu.Settings'], + }, +}; + +export const manifests = [menuItem]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/sidebar-menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/sidebar-menu-item/manifests.ts deleted file mode 100644 index c9f1fa57d3..0000000000 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/sidebar-menu-item/manifests.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { ManifestSidebarMenuItem } from '@umbraco-cms/models'; - -const sidebarMenuItem: ManifestSidebarMenuItem = { - type: 'sidebarMenuItem', - alias: 'Umb.SidebarMenuItem.Languages', - name: 'Languages Sidebar Menu Item', - weight: 80, - meta: { - label: 'Languages', - icon: 'umb:globe', - entityType: 'language-root', - sidebarMenus: ['Umb.SidebarMenu.Settings'], - }, -}; - -export const manifests = [sidebarMenuItem]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/workspace/language/language-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/workspace/language/language-workspace.context.ts index 8f1fd0b0f4..a31db582a7 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/workspace/language/language-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/workspace/language/language-workspace.context.ts @@ -4,10 +4,7 @@ import type { LanguageModel } from '@umbraco-cms/backend-api'; import { ObjectState } from '@umbraco-cms/observable-api'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; -export class UmbLanguageWorkspaceContext extends UmbWorkspaceContext { - #host: UmbControllerHostInterface; - #languageRepository: UmbLanguageRepository; - +export class UmbLanguageWorkspaceContext extends UmbWorkspaceContext { #data = new ObjectState(undefined); data = this.#data.asObservable(); @@ -16,13 +13,11 @@ export class UmbLanguageWorkspaceContext extends UmbWorkspaceContext { validationErrors = this.#validationErrors.asObservable(); constructor(host: UmbControllerHostInterface) { - super(host); - this.#host = host; - this.#languageRepository = new UmbLanguageRepository(this.#host); + super(host, new UmbLanguageRepository(host)); } async load(isoCode: string) { - const { data } = await this.#languageRepository.requestByIsoCode(isoCode); + const { data } = await this.repository.requestByIsoCode(isoCode); if (data) { this.setIsNew(false); this.#data.update(data); @@ -30,7 +25,7 @@ export class UmbLanguageWorkspaceContext extends UmbWorkspaceContext { } async createScaffold() { - const { data } = await this.#languageRepository.createScaffold(); + const { data } = await this.repository.createScaffold(); if (!data) return; this.setIsNew(true); this.#data.update(data); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/workspace/language/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/workspace/language/manifests.ts index b2581f133d..94bc97a049 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/workspace/language/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/workspace/language/manifests.ts @@ -1,5 +1,5 @@ -import { UmbSaveWorkspaceAction } from '../../../../shared/workspace-actions/save.action'; import { LANGUAGE_REPOSITORY_ALIAS } from '../../repository/manifests'; +import { UmbSaveWorkspaceAction } from '@umbraco-cms/workspace'; import type { ManifestWorkspace, ManifestWorkspaceAction, ManifestWorkspaceView } from '@umbraco-cms/models'; const workspace: ManifestWorkspace = { @@ -38,7 +38,6 @@ const workspaceActions: Array = [ look: 'primary', color: 'positive', label: 'Save', - repositoryAlias: LANGUAGE_REPOSITORY_ALIAS, api: UmbSaveWorkspaceAction, }, }, diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/workspace/language/views/edit/edit-language-workspace-view.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/workspace/language/views/edit/edit-language-workspace-view.element.ts index d8bc8c3ebe..0c27e84f7d 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/workspace/language/views/edit/edit-language-workspace-view.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/languages/workspace/language/views/edit/edit-language-workspace-view.element.ts @@ -3,10 +3,10 @@ import { UUITextStyles } from '@umbraco-ui/uui-css'; import { css, html, nothing } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { ifDefined } from 'lit/directives/if-defined.js'; -import { UmbChangeEvent } from '@umbraco-cms/events'; import { UmbLanguageWorkspaceContext } from '../../language-workspace.context'; import UmbInputCultureSelectElement from '../../../../../../shared/components/input-culture-select/input-culture-select.element'; import UmbInputLanguagePickerElement from '../../../../../../shared/components/input-language-picker/input-language-picker.element'; +import { UmbChangeEvent } from '@umbraco-cms/events'; import { UmbLitElement } from '@umbraco-cms/element'; import { LanguageModel } from '@umbraco-cms/backend-api'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/logviewer/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/logviewer/manifests.ts index 450deac4e9..767c99acee 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/logviewer/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/logviewer/manifests.ts @@ -1,4 +1,4 @@ -import { manifests as treeManifests } from './sidebar-menu-item/manifests'; +import { manifests as treeManifests } from './menu-item/manifests'; import { manifests as workspaceManifests } from './workspace/manifests'; export const manifests = [...treeManifests, ...workspaceManifests]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/logviewer/menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/logviewer/menu-item/manifests.ts new file mode 100644 index 0000000000..dc7b08158f --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/logviewer/menu-item/manifests.ts @@ -0,0 +1,16 @@ +import type { ManifestMenuItem } from '@umbraco-cms/models'; + +const menuItem: ManifestMenuItem = { + type: 'menuItem', + alias: 'Umb.MenuItem.LogViewer', + name: 'LogViewer Menu Item', + weight: 70, + meta: { + label: 'Log Viewer', + icon: 'umb:box-alt', + entityType: 'logviewer-root', + menus: ['Umb.Menu.Settings'], + }, +}; + +export const manifests = [menuItem]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/logviewer/sidebar-menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/logviewer/sidebar-menu-item/manifests.ts deleted file mode 100644 index 460c5170aa..0000000000 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/logviewer/sidebar-menu-item/manifests.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { ManifestSidebarMenuItem } from '@umbraco-cms/models'; - -const sidebarMenuItem: ManifestSidebarMenuItem = { - type: 'sidebarMenuItem', - alias: 'Umb.SidebarMenuItem.LogViewer', - name: 'LogViewer Sidebar Menu Item', - weight: 70, - meta: { - label: 'Log Viewer', - icon: 'umb:box-alt', - entityType: 'logviewer', - sidebarMenus: ['Umb.SidebarMenu.Settings'], - }, -}; - -export const manifests = [sidebarMenuItem]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/menu.manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/menu.manifests.ts new file mode 100644 index 0000000000..9147a6a50a --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/menu.manifests.ts @@ -0,0 +1,12 @@ +import { ManifestMenu } from '@umbraco-cms/extensions-registry'; + +const menu: ManifestMenu = { + type: 'menu', + alias: 'Umb.Menu.Settings', + name: 'Settings Menu', + meta: { + label: 'Settings', + }, +}; + +export const manifests = [menu]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/settings/section.manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/settings/section.manifests.ts index fa9ce27835..90b8cb4a4c 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/settings/section.manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/settings/section.manifests.ts @@ -1,4 +1,4 @@ -import type { ManifestSection, ManifestSidebarMenu } from '@umbraco-cms/models'; +import type { ManifestSection, ManifestMenuSectionSidebarApp } from '@umbraco-cms/models'; const sectionAlias = 'Umb.Section.Settings'; @@ -13,15 +13,16 @@ const section: ManifestSection = { }, }; -const sidebarMenu: ManifestSidebarMenu = { - type: 'sidebarMenu', - alias: 'Umb.SidebarMenu.Settings', - name: 'Settings Sidebar Menu', +const menuSectionSidebarApp: ManifestMenuSectionSidebarApp = { + type: 'menuSectionSidebarApp', + alias: 'Umb.SectionSidebarMenu.Settings', + name: 'Settings Section Sidebar Menu', weight: 100, meta: { label: 'Settings', sections: [sectionAlias], + menu: 'Umb.Menu.Settings', }, }; -export const manifests = [section, sidebarMenu]; +export const manifests = [section, menuSectionSidebarApp]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/collection/collection-selection-actions.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/collection/collection-selection-actions.element.ts index dd7d75eba1..099877a7b1 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/collection/collection-selection-actions.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/collection/collection-selection-actions.element.ts @@ -8,7 +8,7 @@ import { UmbLitElement } from '@umbraco-cms/element'; import { umbExtensionsRegistry } from '@umbraco-cms/extensions-api'; import { UmbExecutedEvent } from '@umbraco-cms/events'; -import '../entity-bulk-actions/entity-bulk-action.element'; +import '../components/entity-bulk-action/entity-bulk-action.element'; @customElement('umb-collection-selection-actions') export class UmbCollectionSelectionActionsElement extends UmbLitElement { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/entity-actions/entity-action-list.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/entity-action/entity-action-list.element.ts similarity index 100% rename from src/Umbraco.Web.UI.Client/src/backoffice/shared/entity-actions/entity-action-list.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/shared/components/entity-action/entity-action-list.element.ts diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/entity-actions/entity-action.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/entity-action/entity-action.element.ts similarity index 100% rename from src/Umbraco.Web.UI.Client/src/backoffice/shared/entity-actions/entity-action.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/shared/components/entity-action/entity-action.element.ts diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/entity-bulk-actions/entity-bulk-action.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/entity-bulk-action/entity-bulk-action.element.ts similarity index 93% rename from src/Umbraco.Web.UI.Client/src/backoffice/shared/entity-bulk-actions/entity-bulk-action.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/shared/components/entity-bulk-action/entity-bulk-action.element.ts index 530ec2ab46..01b150f737 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/entity-bulk-actions/entity-bulk-action.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/entity-bulk-action/entity-bulk-action.element.ts @@ -1,6 +1,7 @@ import { html } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { ifDefined } from 'lit-html/directives/if-defined.js'; +import { UmbEntityBulkAction } from '@umbraco-cms/entity-action'; import { UmbExecutedEvent } from '@umbraco-cms/events'; import { UmbLitElement } from '@umbraco-cms/element'; import { ManifestEntityBulkAction } from '@umbraco-cms/extensions-registry'; @@ -40,9 +41,10 @@ class UmbEntityBulkActionElement extends UmbLitElement { this.#api = new this._manifest.meta.api(this, this._manifest.meta.repositoryAlias, this._selection); } - #api: any; + #api?: UmbEntityBulkAction; async #onClick(event: PointerEvent) { + if (!this.#api) return; event.stopPropagation(); await this.#api.execute(); this.dispatchEvent(new UmbExecutedEvent()); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/index.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/index.ts index 429dfc5d57..53be448e4c 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/index.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/index.ts @@ -1,8 +1,8 @@ //TODO: we need to figure out what components should be available for extensions and load them upfront // TODO: we need to move these files into their respective folders/silos. We then need a way for a silo to globally register a component -import '../entity-actions/entity-action-list.element'; -import '../entity-actions/entity-action.element'; +import './entity-action/entity-action-list.element'; +import './entity-action/entity-action.element'; import './backoffice-frame/backoffice-header.element'; import './backoffice-frame/backoffice-main.element'; import './backoffice-frame/backoffice-modal-container.element'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-culture-select/input-culture-select.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-culture-select/input-culture-select.element.ts index 3e4d61e854..bdcf53b259 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-culture-select/input-culture-select.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-culture-select/input-culture-select.element.ts @@ -5,8 +5,8 @@ import { FormControlMixin } from '@umbraco-ui/uui-base/lib/mixins'; import { ifDefined } from 'lit-html/directives/if-defined.js'; import { repeat } from 'lit/directives/repeat.js'; import { UUIComboboxElement, UUIComboboxEvent } from '@umbraco-ui/uui'; -import { UmbChangeEvent } from '@umbraco-cms/events'; import { UmbCultureRepository } from '../../../settings/cultures/repository/culture.repository'; +import { UmbChangeEvent } from '@umbraco-cms/events'; import { UmbLitElement } from '@umbraco-cms/element'; import { CultureModel } from '@umbraco-cms/backend-api'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.element.ts index b44005a3df..2ef9748513 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/input-language-picker/input-language-picker.element.ts @@ -3,9 +3,9 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, property, state } from 'lit/decorators.js'; import { ifDefined } from 'lit-html/directives/if-defined.js'; import { FormControlMixin } from '@umbraco-ui/uui-base/lib/mixins'; -import { UmbChangeEvent } from '@umbraco-cms/events'; import { UmbModalService, UMB_MODAL_SERVICE_CONTEXT_TOKEN } from '../../../../core/modal'; import { UmbLanguageRepository } from '../../../settings/languages/repository/language.repository'; +import { UmbChangeEvent } from '@umbraco-cms/events'; import { UmbLitElement } from '@umbraco-cms/element'; import type { LanguageModel } from '@umbraco-cms/backend-api'; import type { UmbObserverController } from '@umbraco-cms/observable-api'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-sidebar-menu/sidebar-menu-item.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/menu-item/menu-item.element.ts similarity index 64% rename from src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-sidebar-menu/sidebar-menu-item.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/shared/components/menu-item/menu-item.element.ts index 81df6319d5..22fa6c93c6 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-sidebar-menu/sidebar-menu-item.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/menu-item/menu-item.element.ts @@ -3,28 +3,28 @@ import { css, html } from 'lit'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { customElement, property } from 'lit/decorators.js'; import { UmbLitElement } from '@umbraco-cms/element'; -import type { ManifestSidebarMenuItem } from '@umbraco-cms/models'; +import type { ManifestMenuItem } from '@umbraco-cms/models'; -@customElement('umb-sidebar-menu-item') -export class UmbSidebarMenuItem extends UmbLitElement { +@customElement('umb-menu-item') +export class UmbMenuItem extends UmbLitElement { static styles = [UUITextStyles, css``]; private _key = uuidv4(); @property({ type: Object, attribute: false }) - manifest!: ManifestSidebarMenuItem; + manifest!: ManifestMenuItem; render() { return html``; + .entityType=${this.manifest.meta.entityType || ''}>`; } } declare global { interface HTMLElementTagNameMap { - 'umb-sidebar-menu-item': UmbSidebarMenuItem; + 'umb-menu-item': UmbMenuItem; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/menu/menu.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/menu/menu.element.ts new file mode 100644 index 0000000000..6e5e62bbd6 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/menu/menu.element.ts @@ -0,0 +1,30 @@ +import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; +import { html } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; +import { ManifestMenu, ManifestMenuItem } from '@umbraco-cms/extensions-registry'; +import { UmbLitElement } from '@umbraco-cms/element'; + +import '../menu-item/menu-item.element'; + +@customElement('umb-menu') +export class UmbMenuElement extends UmbLitElement { + static styles = [UUITextStyles]; + + @property() + manifest?: ManifestMenu; + + render() { + return html` items.meta.menus.includes(this.manifest!.alias)} + default-element="umb-menu-item">`; + } +} + +export default UmbMenuElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-menu': UmbMenuElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-dashboards/section-dashboards.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-dashboards/section-dashboards.element.ts index 61f4bf1fd3..e38dd43cb5 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-dashboards/section-dashboards.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-dashboards/section-dashboards.element.ts @@ -95,9 +95,7 @@ export class UmbSectionDashboardsElement extends UmbLitElement { ?.extensionsOfTypes(['dashboard', 'dashboardCollection']) .pipe( map((extensions) => - extensions.filter((extension) => - (extension as ManifestWithMeta).meta.sections.includes(this._currentSectionAlias) - ) + extensions.filter((extension) => extension.meta.sections.includes(this._currentSectionAlias ?? '')) ) ), (dashboards) => { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-sidebar-menu/section-sidebar-menu.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-sidebar-menu/section-sidebar-menu.element.ts index f355df2597..a3d5197748 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-sidebar-menu/section-sidebar-menu.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section-sidebar-menu/section-sidebar-menu.element.ts @@ -1,10 +1,10 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import { css, html } from 'lit'; import { customElement, property } from 'lit/decorators.js'; -import { ManifestSidebarMenu, ManifestSidebarMenuItem } from '@umbraco-cms/extensions-registry'; +import { ManifestMenu, ManifestMenuSectionSidebarApp } from '@umbraco-cms/extensions-registry'; import { UmbLitElement } from '@umbraco-cms/element'; -import './sidebar-menu-item.element.ts'; +import '../../menu/menu.element'; @customElement('umb-section-sidebar-menu') export class UmbSectionSidebarMenuElement extends UmbLitElement { @@ -18,15 +18,15 @@ export class UmbSectionSidebarMenuElement extends UmbLitElement { ]; @property() - manifest?: ManifestSidebarMenu; + manifest?: ManifestMenuSectionSidebarApp; render() { // TODO: link to dashboards when clicking on the menu item header return html`

    ${this.manifest?.meta.label}

    items.meta.sidebarMenus.includes(this.manifest!.alias)} - default-element="umb-sidebar-menu-item">`; + type="menu" + .filter=${(menu: ManifestMenu) => menu.alias === this.manifest!.meta.menu} + default-element="umb-menu">`; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section.element.ts index 03440f01c1..a144c9666c 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/section/section.element.ts @@ -5,13 +5,13 @@ import { map } from 'rxjs'; import { IRoutingInfo } from 'router-slot'; import type { UmbWorkspaceEntityElement } from '../workspace/workspace-entity-element.interface'; import { UmbSectionContext, UMB_SECTION_CONTEXT_TOKEN } from './section.context'; -import type { ManifestSectionView, ManifestWorkspace, ManifestSidebarMenu } from '@umbraco-cms/models'; +import type { ManifestSectionView, ManifestWorkspace, ManifestMenuSectionSidebarApp } from '@umbraco-cms/models'; import { umbExtensionsRegistry, createExtensionElement } from '@umbraco-cms/extensions-api'; import { UmbLitElement } from '@umbraco-cms/element'; import './section-sidebar-menu/section-sidebar-menu.element.ts'; import './section-views/section-views.element.ts'; -import '../../../settings/languages/app-language-select.element.ts'; +import '../../../settings/languages/app-language-select/app-language-select.element.ts'; import { UmbRouterSlotChangeEvent } from '@umbraco-cms/router'; @customElement('umb-section') @@ -40,7 +40,7 @@ export class UmbSectionElement extends UmbLitElement { private _routes: Array = []; @state() - private _menus?: Array; + private _menus?: Array; @state() private _views?: Array; @@ -84,7 +84,7 @@ export class UmbSectionElement extends UmbLitElement { if (sectionAlias) { this.observe( umbExtensionsRegistry - ?.extensionsOfType('sidebarMenu') + ?.extensionsOfType('menuSectionSidebarApp') .pipe(map((manifests) => manifests.filter((manifest) => manifest.meta.sections.includes(sectionAlias)))), (manifests) => { this._menus = manifests; @@ -199,12 +199,17 @@ export class UmbSectionElement extends UmbLitElement { return html` ${this._menus && this._menus.length > 0 ? html` + - - items.meta.sections.includes(this._sectionAlias || '')} + type="sectionSidebarApp" + .filter=${(items: ManifestMenuSectionSidebarApp) => + items.meta.sections.includes(this._sectionAlias || '')}> + + + items.meta.sections.includes(this._sectionAlias || '')} default-element="umb-section-sidebar-menu"> ` diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-action/save/workspace-action-node-save.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-action/save/workspace-action-node-save.element.ts deleted file mode 100644 index 29fac1453f..0000000000 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-action/save/workspace-action-node-save.element.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { css, html } from 'lit'; -import { customElement, state } from 'lit/decorators.js'; -import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; -import type { UUIButtonState } from '@umbraco-ui/uui'; -import { UmbWorkspaceEntityContextInterface } from '../../workspace-context/workspace-entity-context.interface'; -import { UmbLitElement } from '@umbraco-cms/element'; -import type { ManifestWorkspaceAction } from '@umbraco-cms/models'; - -@customElement('umb-workspace-action-node-save') -export class UmbWorkspaceActionNodeSaveElement extends UmbLitElement { - static styles = [UUITextStyles, css``]; - - @state() - private _saveButtonState?: UUIButtonState; - - private _workspaceContext?: UmbWorkspaceEntityContextInterface; - - public manifest?: ManifestWorkspaceAction; - - constructor() { - super(); - - // TODO: Figure out how to get the magic string for the workspace context. - this.consumeContext('umbWorkspaceContext', (instance) => { - this._workspaceContext = instance; - }); - } - - private async _onSave() { - if (!this._workspaceContext) return; - - this._saveButtonState = 'waiting'; - await this._workspaceContext - .save() - .then(() => { - this._saveButtonState = 'success'; - }) - .catch(() => { - this._saveButtonState = 'failed'; - }); - } - - render() { - return html` - - `; - } -} - -export default UmbWorkspaceActionNodeSaveElement; - -declare global { - interface HTMLElementTagNameMap { - 'umb-workspace-action-node-save': UmbWorkspaceActionNodeSaveElement; - } -} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-action/workspace-action.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-action/workspace-action.element.ts index 88e0fcac15..17fea95c41 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-action/workspace-action.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-action/workspace-action.element.ts @@ -2,6 +2,7 @@ import { css, html } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import { UUITextStyles } from '@umbraco-ui/uui-css/lib'; import type { UUIButtonState } from '@umbraco-ui/uui'; +import { UmbWorkspaceAction } from '@umbraco-cms/workspace'; import { UmbExecutedEvent } from '@umbraco-cms/events'; import { UmbLitElement } from '@umbraco-cms/element'; import type { ManifestWorkspaceAction } from '@umbraco-cms/models'; @@ -30,12 +31,13 @@ export class UmbWorkspaceActionElement extends UmbLitElement { #createApi() { if (!this._manifest?.meta.api) return; - this.#api = new this._manifest.meta.api(this, this._manifest.meta.repositoryAlias); + this.#api = new this._manifest.meta.api(this); } - #api: any; + #api?: UmbWorkspaceAction; private async _onClick() { + if (!this.#api) return; await this.#api.execute(); this.dispatchEvent(new UmbExecutedEvent()); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-context.interface.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-context.interface.ts index e372dfc228..c756452a21 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-context.interface.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-context.interface.ts @@ -1,6 +1,9 @@ import { Observable } from 'rxjs'; +import { UmbControllerHostInterface } from '@umbraco-cms/controller'; export interface UmbWorkspaceContextInterface { + host: UmbControllerHostInterface; + repository: any; // TODO: add type isNew: Observable; getIsNew(): boolean; setIsNew(value: boolean): void; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-context.ts index ca0407059d..66c5cbab0c 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/shared/components/workspace/workspace-context/workspace-context.ts @@ -7,14 +7,16 @@ import { DeepState } from '@umbraco-cms/observable-api'; TODO: We need to figure out if we like to keep using same alias for all workspace contexts. If so we need to align on a interface that all of these implements. otherwise consumers cant trust the workspace-context. */ -export abstract class UmbWorkspaceContext { - protected _host: UmbControllerHostInterface; +export abstract class UmbWorkspaceContext { + public host: UmbControllerHostInterface; + public repository: T; #isNew = new DeepState(false); isNew = this.#isNew.asObservable(); - constructor(host: UmbControllerHostInterface) { - this._host = host; + constructor(host: UmbControllerHostInterface, repository: T) { + this.host = host; + this.repository = repository; new UmbContextProviderController(host, 'umbWorkspaceContext', this); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/templating/index.ts b/src/Umbraco.Web.UI.Client/src/backoffice/templating/index.ts index 2666a82bfc..1a8e8d3ed7 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/templating/index.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/templating/index.ts @@ -1,4 +1,4 @@ -import { manifests as menuManifests } from './manifests'; +import { manifests as menuManifests } from './menu.manifests'; import { manifests as templateManifests } from './templates/manifests'; import { umbExtensionsRegistry } from '@umbraco-cms/extensions-api'; import { ManifestTypes } from '@umbraco-cms/extensions-registry'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/templating/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/templating/manifests.ts deleted file mode 100644 index 5b76467241..0000000000 --- a/src/Umbraco.Web.UI.Client/src/backoffice/templating/manifests.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { ManifestSidebarMenu } from '@umbraco-cms/models'; - -const sidebarMenu: ManifestSidebarMenu = { - type: 'sidebarMenu', - alias: 'Umb.SidebarMenu.Templating', - name: 'Settings Sidebar Menu', - weight: 100, - meta: { - label: 'Templating', - sections: ['Umb.Section.Settings'], - }, -}; - -export const manifests = [sidebarMenu]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/templating/menu.manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/templating/menu.manifests.ts new file mode 100644 index 0000000000..700ff9b7be --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/templating/menu.manifests.ts @@ -0,0 +1,24 @@ +import { ManifestMenuSectionSidebarApp, ManifestMenu } from '@umbraco-cms/extensions-registry'; + +const menu: ManifestMenu = { + type: 'menu', + alias: 'Umb.Menu.Templating', + name: 'Templating Menu', + meta: { + label: 'Templating', + }, +}; + +const menuSectionSidebarApp: ManifestMenuSectionSidebarApp = { + type: 'menuSectionSidebarApp', + alias: 'Umb.SectionSidebarMenu.Templating', + name: 'Templating Section Sidebar Menu', + weight: 100, + meta: { + label: 'Templating', + sections: ['Umb.Section.Settings'], + menu: 'Umb.Menu.Templating', + }, +}; + +export const manifests = [menu, menuSectionSidebarApp]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/entity-actions/create/create.action.ts b/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/entity-actions/create/create.action.ts index 12af1d77c2..eb5c1bca61 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/entity-actions/create/create.action.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/entity-actions/create/create.action.ts @@ -1,4 +1,4 @@ -import { UmbEntityActionBase } from '../../../../shared/entity-actions'; +import { UmbEntityActionBase } from '@umbraco-cms/entity-action'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; export class UmbCreateEntityAction }> extends UmbEntityActionBase { diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/entity-actions/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/entity-actions/manifests.ts index 35518ab257..b5ee6cf27b 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/entity-actions/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/entity-actions/manifests.ts @@ -1,5 +1,5 @@ -import { UmbDeleteEntityAction } from '../../../shared/entity-actions/delete/delete.action'; import { UmbCreateEntityAction } from './create/create.action'; +import { UmbDeleteEntityAction } from '@umbraco-cms/entity-action'; import { ManifestEntityAction } from 'libs/extensions-registry/entity-action.models'; const entityActions: Array = [ diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/manifests.ts index 9ca5faf660..84c48ea0b7 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/manifests.ts @@ -1,12 +1,12 @@ import { manifests as repositoryManifests } from './repository/manifests'; -import { manifests as sidebarMenuItemManifests } from './sidebar-menu-item/manifests'; +import { manifests as menuItemManifests } from './menu-item/manifests'; import { manifests as treeManifests } from './tree/manifests'; import { manifests as entityActionsManifests } from './entity-actions/manifests'; import { manifests as workspaceManifests } from './workspace/manifests'; export const manifests = [ ...repositoryManifests, - ...sidebarMenuItemManifests, + ...menuItemManifests, ...treeManifests, ...entityActionsManifests, ...workspaceManifests, diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/menu-item/manifests.ts new file mode 100644 index 0000000000..1f84068f1d --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/menu-item/manifests.ts @@ -0,0 +1,17 @@ +import type { ManifestMenuItem } from '@umbraco-cms/models'; + +const menuItem: ManifestMenuItem = { + type: 'menuItem', + alias: 'Umb.MenuItem.Templates', + name: 'Templates Menu Item', + weight: 40, + loader: () => import('./templates-menu-item.element'), + meta: { + label: 'Templates', + icon: 'umb:folder', + entityType: 'template', + menus: ['Umb.Menu.Templating'], + }, +}; + +export const manifests = [menuItem]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/sidebar-menu-item/templates-sidebar-menu-item.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/menu-item/templates-menu-item.element.ts similarity index 78% rename from src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/sidebar-menu-item/templates-sidebar-menu-item.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/menu-item/templates-menu-item.element.ts index 866b1e58b7..d9b9600990 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/sidebar-menu-item/templates-sidebar-menu-item.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/menu-item/templates-menu-item.element.ts @@ -2,8 +2,8 @@ import { html, nothing } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { UmbLitElement } from '@umbraco-cms/element'; -@customElement('umb-templates-sidebar-menu-item') -export class UmbTemplatesSidebarMenuItemElement extends UmbLitElement { +@customElement('umb-templates-menu-item') +export class UmbTemplatesMenuItemElement extends UmbLitElement { @state() private _renderTree = false; @@ -31,10 +31,10 @@ export class UmbTemplatesSidebarMenuItemElement extends UmbLitElement { } } -export default UmbTemplatesSidebarMenuItemElement; +export default UmbTemplatesMenuItemElement; declare global { interface HTMLElementTagNameMap { - 'umb-templates-sidebar-menu-item': UmbTemplatesSidebarMenuItemElement; + 'umb-templates-menu-item': UmbTemplatesMenuItemElement; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/sidebar-menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/sidebar-menu-item/manifests.ts deleted file mode 100644 index 202143e1b5..0000000000 --- a/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/sidebar-menu-item/manifests.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { ManifestSidebarMenuItem } from '@umbraco-cms/models'; - -const sidebarMenuItem: ManifestSidebarMenuItem = { - type: 'sidebarMenuItem', - alias: 'Umb.SidebarMenuItem.Templates', - name: 'Templates Sidebar Menu Item', - weight: 40, - loader: () => import('./templates-sidebar-menu-item.element'), - meta: { - label: 'Templates', - icon: 'umb:folder', - entityType: 'template', - sidebarMenus: ['Umb.SidebarMenu.Templating'], - }, -}; - -export const manifests = [sidebarMenuItem]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/workspace/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/workspace/manifests.ts index ec7fa7daef..6330096a9c 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/workspace/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/templating/templates/workspace/manifests.ts @@ -1,5 +1,5 @@ import { TEMPLATE_REPOSITORY_ALIAS } from '../repository/manifests'; -import { UmbSaveWorkspaceAction } from '../../../shared/workspace-actions/save.action'; +import { UmbSaveWorkspaceAction } from '@umbraco-cms/workspace'; import type { ManifestWorkspace, ManifestWorkspaceAction, ManifestWorkspaceView } from '@umbraco-cms/models'; const workspace: ManifestWorkspace = { @@ -25,7 +25,6 @@ const workspaceActions: Array = [ color: 'positive', workspaces: ['Umb.Workspace.Template'], label: 'Save', - repositoryAlias: TEMPLATE_REPOSITORY_ALIAS, api: UmbSaveWorkspaceAction, }, }, diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/entity-actions/create/create.action.ts b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/entity-actions/create/create.action.ts index ae4396f5c1..73440c8f6b 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/entity-actions/create/create.action.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/entity-actions/create/create.action.ts @@ -1,11 +1,11 @@ import { UUITextStyles } from '@umbraco-ui/uui-css'; -import { UmbEntityActionBase } from '../../../../shared/entity-actions'; import { UmbDictionaryRepository } from '../../repository/dictionary.repository'; import { UmbSectionSidebarContext, UMB_SECTION_SIDEBAR_CONTEXT_TOKEN, } from '../../../../../backoffice/shared/components/section/section-sidebar/section-sidebar.context'; import type { UmbCreateDictionaryModalResultData } from './create-dictionary-modal-layout.element'; +import { UmbEntityActionBase } from '@umbraco-cms/entity-action'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; import { UmbContextConsumerController } from '@umbraco-cms/context-api'; import { UmbModalService, UMB_MODAL_SERVICE_CONTEXT_TOKEN } from '@umbraco-cms/modal'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/entity-actions/export/export.action.ts b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/entity-actions/export/export.action.ts index d13e557ded..6fe67c257c 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/entity-actions/export/export.action.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/entity-actions/export/export.action.ts @@ -1,7 +1,7 @@ import { UUITextStyles } from '@umbraco-ui/uui-css'; -import { UmbEntityActionBase } from '../../../../shared/entity-actions'; import { UmbDictionaryRepository } from '../../repository/dictionary.repository'; import type { UmbExportDictionaryModalResultData } from './export-dictionary-modal-layout.element'; +import { UmbEntityActionBase } from '@umbraco-cms/entity-action'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; import { UmbContextConsumerController } from '@umbraco-cms/context-api'; import { UmbModalService, UMB_MODAL_SERVICE_CONTEXT_TOKEN } from '@umbraco-cms/modal'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/entity-actions/import/import.action.ts b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/entity-actions/import/import.action.ts index b091cc0e36..da5e2a7dfc 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/entity-actions/import/import.action.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/entity-actions/import/import.action.ts @@ -1,7 +1,7 @@ import { UUITextStyles } from '@umbraco-ui/uui-css'; -import { UmbEntityActionBase } from '../../../../shared/entity-actions'; import { UmbDictionaryRepository } from '../../repository/dictionary.repository'; import type { UmbImportDictionaryModalResultData } from './import-dictionary-modal-layout.element'; +import { UmbEntityActionBase } from '@umbraco-cms/entity-action'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; import { UmbContextConsumerController } from '@umbraco-cms/context-api'; import { UmbModalService, UMB_MODAL_SERVICE_CONTEXT_TOKEN } from '@umbraco-cms/modal'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/entity-actions/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/entity-actions/manifests.ts index b83f66480b..176e975a92 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/entity-actions/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/entity-actions/manifests.ts @@ -1,10 +1,9 @@ -import { UmbDeleteEntityAction } from '../../../../backoffice/shared/entity-actions/delete/delete.action'; -import { UmbMoveEntityAction } from '../../../../backoffice/shared/entity-actions/move/move.action'; import { DICTIONARY_REPOSITORY_ALIAS } from '../repository/manifests'; import UmbReloadDictionaryEntityAction from './reload.action'; import UmbImportDictionaryEntityAction from './import/import.action'; import UmbExportDictionaryEntityAction from './export/export.action'; import UmbCreateDictionaryEntityAction from './create/create.action'; +import { UmbDeleteEntityAction, UmbMoveEntityAction } from '@umbraco-cms/entity-action'; import type { ManifestEntityAction } from '@umbraco-cms/models'; const entityType = 'dictionary-item'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/entity-actions/reload.action.ts b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/entity-actions/reload.action.ts index 19f607129d..dd31434f25 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/entity-actions/reload.action.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/entity-actions/reload.action.ts @@ -1,6 +1,6 @@ import { UUITextStyles } from '@umbraco-ui/uui-css'; -import { UmbEntityActionBase } from '../../../shared/entity-actions'; import { UmbDictionaryRepository } from '../repository/dictionary.repository'; +import { UmbEntityActionBase } from '@umbraco-cms/entity-action'; import { UmbControllerHostInterface } from '@umbraco-cms/controller'; export default class UmbReloadDictionaryEntityAction extends UmbEntityActionBase { @@ -11,6 +11,6 @@ export default class UmbReloadDictionaryEntityAction extends UmbEntityActionBase } async execute() { - alert('refresh') + alert('refresh'); } -} \ No newline at end of file +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/manifests.ts index 6c4d56a671..406f298371 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/manifests.ts @@ -1,11 +1,13 @@ -import { manifests as sidebarMenuItemManifests } from './sidebar-menu-item/manifests'; +import { manifests as menuManifests } from './menu.manifests'; +import { manifests as menuItemManifests } from './menu-item/manifests'; import { manifests as treeManifests } from './tree/manifests'; import { manifests as repositoryManifests } from './repository/manifests'; import { manifests as workspaceManifests } from './workspace/manifests'; import { manifests as entityActionManifests } from './entity-actions/manifests'; export const manifests = [ - ...sidebarMenuItemManifests, + ...menuManifests, + ...menuItemManifests, ...treeManifests, ...repositoryManifests, ...workspaceManifests, diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/sidebar-menu-item/dictionary-sidebar-menu-item.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/menu-item/dictionary-menu-item.element.ts similarity index 52% rename from src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/sidebar-menu-item/dictionary-sidebar-menu-item.element.ts rename to src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/menu-item/dictionary-menu-item.element.ts index f06a051ad3..98dffdf557 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/sidebar-menu-item/dictionary-sidebar-menu-item.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/menu-item/dictionary-menu-item.element.ts @@ -2,17 +2,17 @@ import { html } from 'lit'; import { customElement } from 'lit/decorators.js'; import { UmbLitElement } from '@umbraco-cms/element'; -@customElement('umb-dictionary-sidebar-menu-item') -export class UmbDictionarySidebarMenuItemElement extends UmbLitElement { +@customElement('umb-dictionary-menu-item') +export class UmbDictionaryMenuItemElement extends UmbLitElement { render() { return html``; } } -export default UmbDictionarySidebarMenuItemElement; +export default UmbDictionaryMenuItemElement; declare global { interface HTMLElementTagNameMap { - 'umb-dictionary-sidebar-menu-item': UmbDictionarySidebarMenuItemElement; + 'umb-dictionary-menu-item': UmbDictionaryMenuItemElement; } } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/menu-item/manifests.ts new file mode 100644 index 0000000000..c62856cc82 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/menu-item/manifests.ts @@ -0,0 +1,17 @@ +import type { ManifestMenuItem } from '@umbraco-cms/models'; + +const menuItem: ManifestMenuItem = { + type: 'menuItem', + alias: 'Umb.MenuItem.Dictionary', + name: 'Dictionary Menu Item', + weight: 400, + loader: () => import('./dictionary-menu-item.element'), + meta: { + label: 'Dictionary', + icon: 'umb:book-alt', + entityType: 'dictionary-item', + menus: ['Umb.Menu.Dictionary'], + }, +}; + +export const manifests = [menuItem]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/menu.manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/menu.manifests.ts new file mode 100644 index 0000000000..de5891031c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/menu.manifests.ts @@ -0,0 +1,12 @@ +import { ManifestMenu } from '@umbraco-cms/extensions-registry'; + +const menu: ManifestMenu = { + type: 'menu', + alias: 'Umb.Menu.Dictionary', + name: 'Dictionary Menu', + meta: { + label: 'Dictionary', + }, +}; + +export const manifests = [menu]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/sidebar-menu-item/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/sidebar-menu-item/manifests.ts deleted file mode 100644 index 68a080417a..0000000000 --- a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/sidebar-menu-item/manifests.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { ManifestSidebarMenuItem } from '@umbraco-cms/models'; - -const sidebarMenuItem: ManifestSidebarMenuItem = { - type: 'sidebarMenuItem', - alias: 'Umb.SidebarMenuItem.Dictionary', - name: 'Dictionary Sidebar Menu Item', - weight: 400, - loader: () => import('./dictionary-sidebar-menu-item.element'), - meta: { - label: 'Dictionary', - icon: 'umb:book-alt', - entityType: 'dictionary-item', - sidebarMenus: ['Umb.SidebarMenu.Translation'], - }, -}; - -export const manifests = [sidebarMenuItem]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/workspace/dictionary-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/workspace/dictionary-workspace.context.ts index d8d1080ead..9ee60311ee 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/workspace/dictionary-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/workspace/dictionary-workspace.context.ts @@ -7,21 +7,16 @@ import type { DictionaryDetails } from '@umbraco-cms/models'; type EntityType = DictionaryDetails; export class UmbWorkspaceDictionaryContext - extends UmbWorkspaceContext + extends UmbWorkspaceContext implements UmbWorkspaceEntityContextInterface { - #host: UmbControllerHostInterface; - #repo: UmbDictionaryRepository; - #data = new ObjectState(undefined); data = this.#data.asObservable(); name = this.#data.getObservablePart((data) => data?.name); dictionary = this.#data.getObservablePart((data) => data); constructor(host: UmbControllerHostInterface) { - super(host); - this.#host = host; - this.#repo = new UmbDictionaryRepository(this.#host); + super(host, new UmbDictionaryRepository(host)); } getData() { @@ -61,7 +56,7 @@ export class UmbWorkspaceDictionaryContext } async load(entityKey: string) { - const { data } = await this.#repo.requestByKey(entityKey); + const { data } = await this.repository.requestByKey(entityKey); if (data) { this.setIsNew(false); this.#data.next(data); @@ -69,7 +64,7 @@ export class UmbWorkspaceDictionaryContext } async createScaffold(parentKey: string | null) { - const { data } = await this.#repo.createScaffold(parentKey); + const { data } = await this.repository.createScaffold(parentKey); if (!data) return; this.setIsNew(true); this.#data.next(data); @@ -77,7 +72,7 @@ export class UmbWorkspaceDictionaryContext async save() { if (!this.#data.value) return; - await this.#repo.save(this.#data.value); + await this.repository.save(this.#data.value); this.setIsNew(false); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/workspace/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/workspace/manifests.ts index 55b41e8202..38d81ac4bb 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/workspace/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/translation/dictionary/workspace/manifests.ts @@ -1,5 +1,5 @@ import { DICTIONARY_REPOSITORY_ALIAS } from '../repository/manifests'; -import { UmbSaveWorkspaceAction } from '../../../../backoffice/shared/workspace-actions/save.action'; +import { UmbSaveWorkspaceAction } from '@umbraco-cms/workspace'; import type { ManifestWorkspace, ManifestWorkspaceAction, ManifestWorkspaceView } from '@umbraco-cms/models'; const workspaceAlias = 'Umb.Workspace.Dictionary'; @@ -41,7 +41,6 @@ const workspaceActions: Array = [ label: 'Save', look: 'primary', color: 'positive', - repositoryAlias: DICTIONARY_REPOSITORY_ALIAS, api: UmbSaveWorkspaceAction, }, }, diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/translation/section.manifest.ts b/src/Umbraco.Web.UI.Client/src/backoffice/translation/section.manifest.ts index 6e60134aa8..aeaee59e29 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/translation/section.manifest.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/translation/section.manifest.ts @@ -1,4 +1,4 @@ -import type { ManifestDashboard, ManifestSection } from '@umbraco-cms/models'; +import type { ManifestDashboard, ManifestSection, ManifestMenuSectionSidebarApp } from '@umbraco-cms/models'; const sectionAlias = 'Umb.Section.Translation'; @@ -13,6 +13,18 @@ const section: ManifestSection = { }, }; +const menuSectionSidebarApp: ManifestMenuSectionSidebarApp = { + type: 'menuSectionSidebarApp', + alias: 'Umb.SidebarMenu.Dictionary', + name: 'Dictionary Sidebar Menu', + weight: 100, + meta: { + label: 'Dictionary', + sections: [sectionAlias], + menu: 'Umb.Menu.Dictionary', + }, +}; + const dashboards: Array = [ { type: 'dashboard', @@ -28,5 +40,4 @@ const dashboards: Array = [ }, ]; - -export const manifests = [section, ...dashboards]; +export const manifests = [section, menuSectionSidebarApp, ...dashboards]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/users/user-groups/repository/user-group.repository.ts b/src/Umbraco.Web.UI.Client/src/backoffice/users/user-groups/repository/user-group.repository.ts new file mode 100644 index 0000000000..33e825330d --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/users/user-groups/repository/user-group.repository.ts @@ -0,0 +1,11 @@ +import { UmbControllerHostInterface } from '@umbraco-cms/controller'; + +// TODO: implement +export class UmbUserGroupRepository { + #host: UmbControllerHostInterface; + + constructor(host: UmbControllerHostInterface) { + this.#host = host; + console.log(this.#host); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/users/user-groups/workspace/user-group-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/users/user-groups/workspace/user-group-workspace.context.ts index 90f77a8f7b..e91149211a 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/users/user-groups/workspace/user-group-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/users/user-groups/workspace/user-group-workspace.context.ts @@ -2,17 +2,23 @@ import { UmbEntityWorkspaceManager } from '../../../shared/components/workspace/ import { UmbWorkspaceContext } from '../../../shared/components/workspace/workspace-context/workspace-context'; import { UmbWorkspaceEntityContextInterface } from '../../../shared/components/workspace/workspace-context/workspace-entity-context.interface'; import { UMB_USER_GROUP_STORE_CONTEXT_TOKEN } from '../user-group.store'; +import { UmbUserGroupRepository } from '../repository/user-group.repository'; import type { UserGroupDetails } from '@umbraco-cms/models'; +import { UmbControllerHostInterface } from '@umbraco-cms/controller'; export class UmbWorkspaceUserGroupContext - extends UmbWorkspaceContext + extends UmbWorkspaceContext implements UmbWorkspaceEntityContextInterface { - #manager = new UmbEntityWorkspaceManager(this._host, 'user-group', UMB_USER_GROUP_STORE_CONTEXT_TOKEN); + #manager = new UmbEntityWorkspaceManager(this.host, 'user-group', UMB_USER_GROUP_STORE_CONTEXT_TOKEN); public readonly data = this.#manager.state.asObservable(); public readonly name = this.#manager.state.getObservablePart((state) => state?.name); + constructor(host: UmbControllerHostInterface) { + super(host, new UmbUserGroupRepository(host)); + } + setName(name: string) { this.#manager.state.update({ name: name }); } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/users/user-groups/workspace/user-group-workspace.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/users/user-groups/workspace/user-group-workspace.element.ts index 64c508556c..43d00f80d4 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/users/user-groups/workspace/user-group-workspace.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/users/user-groups/workspace/user-group-workspace.element.ts @@ -3,10 +3,10 @@ import { UUITextStyles } from '@umbraco-ui/uui-css'; import { css, html, nothing } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { repeat } from 'lit/directives/repeat.js'; -import { distinctUntilChanged } from 'rxjs'; import { UmbUserStore, UMB_USER_STORE_CONTEXT_TOKEN } from '../../../users/users/user.store'; import { UmbWorkspaceEntityElement } from '../../../shared/components/workspace/workspace-entity-element.interface'; import { UmbWorkspaceUserGroupContext } from './user-group-workspace.context'; +import { UmbSaveWorkspaceAction } from '@umbraco-cms/workspace'; import type { ManifestWorkspaceAction, UserGroupDetails } from '@umbraco-cms/models'; import { umbExtensionsRegistry } from '@umbraco-cms/extensions-api'; @@ -224,12 +224,12 @@ export class UmbUserGroupWorkspaceElement extends UmbLitElement implements UmbWo type: 'workspaceAction', alias: 'Umb.WorkspaceAction.UserGroup.Save', name: 'Save User Group Workspace Action', - loader: () => - import('../../../shared/components/workspace/workspace-action/save/workspace-action-node-save.element'), meta: { workspaces: ['Umb.Workspace.UserGroup'], + label: 'Save', look: 'primary', color: 'positive', + api: UmbSaveWorkspaceAction, }, }, ]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/users/users/repository/user.repository.ts b/src/Umbraco.Web.UI.Client/src/backoffice/users/users/repository/user.repository.ts new file mode 100644 index 0000000000..25ad4bc740 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/backoffice/users/users/repository/user.repository.ts @@ -0,0 +1,11 @@ +import { UmbControllerHostInterface } from '@umbraco-cms/controller'; + +// TODO: implement +export class UmbUserRepository { + #host: UmbControllerHostInterface; + + constructor(host: UmbControllerHostInterface) { + this.#host = host; + console.log(this.#host); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/users/users/workspace/manifests.ts b/src/Umbraco.Web.UI.Client/src/backoffice/users/users/workspace/manifests.ts index 566eed14f1..eeb5c42f4b 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/users/users/workspace/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/users/users/workspace/manifests.ts @@ -1,3 +1,4 @@ +import { UmbSaveWorkspaceAction } from '@umbraco-cms/workspace'; import type { ManifestWorkspace, ManifestWorkspaceAction, ManifestWorkspaceView } from '@umbraco-cms/models'; const workspace: ManifestWorkspace = { @@ -16,12 +17,12 @@ const workspaceActions: Array = [ type: 'workspaceAction', alias: 'Umb.WorkspaceAction.User.Save', name: 'Save User Workspace Action', - loader: () => - import('src/backoffice/shared/components/workspace/workspace-action/save/workspace-action-node-save.element'), meta: { workspaces: ['Umb.Workspace.User'], + label: 'Save', look: 'primary', color: 'positive', + api: UmbSaveWorkspaceAction, }, }, ]; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/users/users/workspace/user-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/backoffice/users/users/workspace/user-workspace.context.ts index f7960b71c6..5a6bd37a0c 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/users/users/workspace/user-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/users/users/workspace/user-workspace.context.ts @@ -2,13 +2,15 @@ import { UMB_USER_STORE_CONTEXT_TOKEN } from '../../users/user.store'; import { UmbWorkspaceContext } from '../../../shared/components/workspace/workspace-context/workspace-context'; import { UmbWorkspaceEntityContextInterface } from '../../../shared/components/workspace/workspace-context/workspace-entity-context.interface'; import { UmbEntityWorkspaceManager } from '../../../shared/components/workspace/workspace-context/entity-manager-controller'; +import { UmbUserRepository } from '../repository/user.repository'; import type { UserDetails } from '@umbraco-cms/models'; +import { UmbControllerHostInterface } from '@umbraco-cms/controller'; export class UmbWorkspaceUserContext - extends UmbWorkspaceContext + extends UmbWorkspaceContext implements UmbWorkspaceEntityContextInterface { - #manager = new UmbEntityWorkspaceManager(this._host, 'user', UMB_USER_STORE_CONTEXT_TOKEN); + #manager = new UmbEntityWorkspaceManager(this.host, 'user', UMB_USER_STORE_CONTEXT_TOKEN); public readonly data = this.#manager.state.asObservable(); public readonly name = this.#manager.state.getObservablePart((state) => state?.name); @@ -16,6 +18,10 @@ export class UmbWorkspaceUserContext // TODO: remove this magic connection, instead create the necessary methods to update parts. update = this.#manager.state.update; + constructor(host: UmbControllerHostInterface) { + super(host, new UmbUserRepository(host)); + } + setName(name: string) { this.#manager.state.update({ name: name }); } 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 4b6f4e6c95..6b5eb89fb0 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 @@ -35,7 +35,6 @@ const handlers = [ ...mediaHandlers, ...dataTypeHandlers, ...documentTypeHandlers, - ...manifestsHandlers.default, ...telemetryHandlers, ...publishedStatusHandlers, ...usersHandlers, @@ -67,8 +66,8 @@ switch (import.meta.env.VITE_UMBRACO_INSTALL_STATUS) { handlers.push(serverHandlers.serverRunningHandler); } -switch (import.meta.env.MODE) { - case 'development': +switch (import.meta.env.VITE_UMBRACO_EXTENSION_MOCKS) { + case 'on': handlers.push(manifestsHandlers.manifestDevelopmentHandler); break; diff --git a/src/Umbraco.Web.UI.Client/src/core/mocks/domains/manifests.handlers.ts b/src/Umbraco.Web.UI.Client/src/core/mocks/domains/manifests.handlers.ts index bdb9806ecc..a5f0be9773 100644 --- a/src/Umbraco.Web.UI.Client/src/core/mocks/domains/manifests.handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/core/mocks/domains/manifests.handlers.ts @@ -1,98 +1,76 @@ import { rest } from 'msw'; import { umbracoPath } from '@umbraco-cms/utils'; +import type { PagedManifestsResponse } from '@umbraco-cms/models'; -type ManifestsResponse = Record; -type ManifestsPackagesInstalledResponse = ManifestsResponse; - -export const manifestDevelopmentHandler = rest.get(umbracoPath('/manifests'), (_req, res, ctx) => { +export const manifestDevelopmentHandler = rest.get(umbracoPath('/package/manifest'), (_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', - weight: 1, - meta: { - label: 'Custom', - pathname: 'my-custom', - }, - }, - { - 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: { - label: 'My Custom Property', - icon: 'document', - group: 'Common', - propertyEditorModel: 'Umbraco.JSON', - }, - }, - { - type: 'entrypoint', - name: 'My Custom Entry Point', - alias: 'My.Entrypoint.Custom', - js: '/App_Plugins/custom-entrypoint.js', - }, - { - type: 'packageView', - alias: 'My.PackageView.Custom', - name: 'My Custom Package View', - js: '/App_Plugins/package-view.js', - meta: { - packageAlias: 'my.package', - }, - }, - ], - }) - ); -}); - -export const manifestEmptyHandler = rest.get(umbracoPath('/manifests'), (_req, res, ctx) => { - return res( - // Respond with a 200 status code - ctx.status(200), - ctx.json({ - manifests: [], - }) - ); -}); - -export default [ - rest.get(umbracoPath('/manifests/packages/installed'), (_req, res, ctx) => { - return res( - // Respond with a 200 status code - ctx.status(200), - ctx.json({ - packages: [ + ctx.json([ + { + name: 'Named Package', + version: '1.0.0', + extensions: [ { - id: '2a0181ec-244b-4068-a1d7-2f95ed7e6da6', - name: 'My very own package', - alias: 'my.package', - version: '1.0.0', - hasMigrations: false, - hasPendingMigrations: false, - plans: [], + type: 'section', + alias: 'My.Section.Custom', + name: 'Custom Section', + js: '/App_Plugins/section.js', + elementName: 'my-section-custom', + weight: 1, + meta: { + label: 'Custom', + pathname: 'my-custom', + }, }, { - id: '240d95be-bfdb-4ca2-a601-ed2bfd5ed069', - name: 'Some other community package', - alias: 'our.package', - version: '2.0.1', - hasMigrations: false, - hasPendingMigrations: false, - plans: [], + 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: { + label: 'My Custom Property', + icon: 'document', + group: 'Common', + propertyEditorModel: 'Umbraco.JSON', + }, }, ], - }) - ); - }), -]; + }, + { + extensions: [ + { + type: 'entrypoint', + name: 'My Custom Entry Point', + alias: 'My.Entrypoint.Custom', + js: '/App_Plugins/custom-entrypoint.js', + }, + ], + }, + { + name: 'Package with a view', + extensions: [ + { + type: 'packageView', + alias: 'My.PackageView.Custom', + name: 'My Custom Package View', + js: '/App_Plugins/package-view.js', + meta: { + packageName: 'my.package', + }, + }, + ], + }, + ]) + ); +}); + +export const manifestEmptyHandler = rest.get(umbracoPath('/package/manifest'), (_req, res, ctx) => { + return res( + // Respond with a 200 status code + ctx.status(200), + ctx.json([]) + ); +}); 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 45fb7f2e96..2c9ab05627 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 @@ -17,13 +17,12 @@ import { handlers as redirectManagementHandlers } from './domains/redirect-manag export const handlers = [ serverHandlers.serverRunningHandler, serverHandlers.serverVersionHandler, - manifestsHandlers.manifestDevelopmentHandler, + manifestsHandlers.manifestEmptyHandler, ...installHandlers, ...upgradeHandlers, ...userHandlers, ...dataTypeHandlers, ...documentTypeHandlers, - ...manifestsHandlers.default, ...telemetryHandlers, ...publishedStatusHandlers, ...examineManagementHandlers, diff --git a/src/Umbraco.Web.UI.Client/src/core/modal/modal.mdx b/src/Umbraco.Web.UI.Client/src/core/modal/stories/modal.mdx similarity index 100% rename from src/Umbraco.Web.UI.Client/src/core/modal/modal.mdx rename to src/Umbraco.Web.UI.Client/src/core/modal/stories/modal.mdx diff --git a/src/Umbraco.Web.UI.Client/src/core/modal/stories/modal.stories.ts b/src/Umbraco.Web.UI.Client/src/core/modal/stories/modal.stories.ts new file mode 100644 index 0000000000..b0ab354948 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/core/modal/stories/modal.stories.ts @@ -0,0 +1,20 @@ +import { Meta, Story } from '@storybook/web-components'; +import { html } from 'lit-html'; + + +export default { + title: 'API/Modals', + id: 'umb-modal-service', + argTypes: { + modalLayout: { + control: 'select', + options: ['Confirm', 'Content Picker', 'Property Editor UI Picker', 'Icon Picker'], + }, + }, +} as Meta; + +const Template: Story = (props) => { + return html` `; +}; + +export const Overview = Template.bind({}); diff --git a/src/Umbraco.Web.UI.Client/src/core/modal/modal.stories.ts b/src/Umbraco.Web.UI.Client/src/core/modal/stories/story-modal-service-example.element.ts similarity index 71% rename from src/Umbraco.Web.UI.Client/src/core/modal/modal.stories.ts rename to src/Umbraco.Web.UI.Client/src/core/modal/stories/story-modal-service-example.element.ts index 0454bcf94e..c2f39bc7d6 100644 --- a/src/Umbraco.Web.UI.Client/src/core/modal/modal.stories.ts +++ b/src/Umbraco.Web.UI.Client/src/core/modal/stories/story-modal-service-example.element.ts @@ -1,20 +1,8 @@ -import { Meta, Story } from '@storybook/web-components'; import { html } from 'lit-html'; import { customElement, property, state } from 'lit/decorators.js'; - -import { UmbModalService, UMB_MODAL_SERVICE_CONTEXT_TOKEN } from '.'; +import { UmbModalService, UMB_MODAL_SERVICE_CONTEXT_TOKEN } from '..'; import { UmbLitElement } from '@umbraco-cms/element'; -export default { - title: 'API/Modals', - id: 'umb-modal-service', - argTypes: { - modalLayout: { - control: 'select', - options: ['Confirm', 'Content Picker', 'Property Editor UI Picker', 'Icon Picker'], - }, - }, -} as Meta; @customElement('story-modal-service-example') export class StoryModalServiceExampleElement extends UmbLitElement { @@ -61,9 +49,3 @@ export class StoryModalServiceExampleElement extends UmbLitElement { `; } } - -const Template: Story = (props) => { - return html` `; -}; - -export const Overview = Template.bind({}); 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 b045b61a0c..d91f137aea 100644 --- a/src/Umbraco.Web.UI.Client/src/vite-env.d.ts +++ b/src/Umbraco.Web.UI.Client/src/vite-env.d.ts @@ -5,4 +5,5 @@ interface ImportMetaEnv { VITE_UMBRACO_API_URL: string; VITE_UMBRACO_USE_MSW: 'on' | 'off'; VITE_MSW_QUIET: 'on' | 'off'; + VITE_UMBRACO_EXTENSION_MOCKS: 'on' | 'off'; } diff --git a/src/Umbraco.Web.UI.Client/tsconfig.json b/src/Umbraco.Web.UI.Client/tsconfig.json index 0d7a68995c..1e55e986af 100644 --- a/src/Umbraco.Web.UI.Client/tsconfig.json +++ b/src/Umbraco.Web.UI.Client/tsconfig.json @@ -32,6 +32,8 @@ "@umbraco-cms/notification": ["libs/notification"], "@umbraco-cms/observable-api": ["libs/observable-api"], "@umbraco-cms/events": ["libs/events"], + "@umbraco-cms/entity-action": ["libs/entity-action"], + "@umbraco-cms/workspace": ["libs/workspace"], "@umbraco-cms/utils": ["libs/utils"], "@umbraco-cms/router": ["libs/router"], "@umbraco-cms/test-utils": ["libs/test-utils"], diff --git a/src/Umbraco.Web.UI.Client/web-test-runner.config.mjs b/src/Umbraco.Web.UI.Client/web-test-runner.config.mjs index e053faf97a..bcdbcb895c 100644 --- a/src/Umbraco.Web.UI.Client/web-test-runner.config.mjs +++ b/src/Umbraco.Web.UI.Client/web-test-runner.config.mjs @@ -49,6 +49,8 @@ export default { '@umbraco-cms/notification': './libs/notification/index.ts', '@umbraco-cms/observable-api': './libs/observable-api/index.ts', '@umbraco-cms/events': './libs/events/index.ts', + '@umbraco-cms/entity-action': './libs/entity-action/index.ts', + '@umbraco-cms/workspace': './libs/workspace/index.ts', '@umbraco-cms/store': './libs/store/index.ts', '@umbraco-cms/utils': './libs/utils/index.ts', '@umbraco-cms/test-utils': './libs/test-utils/index.ts',