diff --git a/src/Umbraco.Web.UI.Client/.github/CONTRIBUTING.md b/src/Umbraco.Web.UI.Client/.github/CONTRIBUTING.md index 63d79f6cf7..e0b09f17a9 100644 --- a/src/Umbraco.Web.UI.Client/.github/CONTRIBUTING.md +++ b/src/Umbraco.Web.UI.Client/.github/CONTRIBUTING.md @@ -132,7 +132,7 @@ Let’s go through each of these properties… - section - examples include: `Content`, `Media` - dashboard - a view within a section. Examples include: the welcome dashboard - - propertyEditorUI + - propertyEditorUi - editorView - propertyAction - tree diff --git a/src/Umbraco.Web.UI.Client/.github/workflows/npm-publish-github-packages.yml b/src/Umbraco.Web.UI.Client/.github/workflows/npm-publish-github-packages.yml index bab658e4b9..77f8e0791f 100644 --- a/src/Umbraco.Web.UI.Client/.github/workflows/npm-publish-github-packages.yml +++ b/src/Umbraco.Web.UI.Client/.github/workflows/npm-publish-github-packages.yml @@ -37,14 +37,11 @@ jobs: scope: '@umbraco-cms' - run: npm ci - run: npm run build:for:npm - - run: npm run generate:jsonschema:dist - - run: npm run wc-analyze - - run: npm run wc-analyze:vscode - name: Version and publish run: | SHA_SHORT=$(echo $GITHUB_SHA | cut -c1-8) npm whoami - npm version 1.0.0-next.$SHA_SHORT --allow-same-version --no-git-tag-version - npm publish --tag latest --access public + npm version 14.0.0-$SHA_SHORT --allow-same-version --no-git-tag-version + npm publish --tag next --access public env: NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} diff --git a/src/Umbraco.Web.UI.Client/.storybook/main.ts b/src/Umbraco.Web.UI.Client/.storybook/main.ts index 1649d80b77..34370039cd 100644 --- a/src/Umbraco.Web.UI.Client/.storybook/main.ts +++ b/src/Umbraco.Web.UI.Client/.storybook/main.ts @@ -36,5 +36,11 @@ const config: StorybookConfig = { ]; return configType === 'PRODUCTION' ? `${injections.join('')}${head}` : head; }, + refs: { + uui: { + title: 'Umbraco UI Library (1.3.0)', + url: 'https://e662ac3--62189360eeb21b003ab2f4ad.chromatic.com/', + }, + }, }; export default config; diff --git a/src/Umbraco.Web.UI.Client/devops/publish/cleanse-pkg.js b/src/Umbraco.Web.UI.Client/devops/publish/cleanse-pkg.js index 4380c48e3c..d5f6415fa2 100644 --- a/src/Umbraco.Web.UI.Client/devops/publish/cleanse-pkg.js +++ b/src/Umbraco.Web.UI.Client/devops/publish/cleanse-pkg.js @@ -13,8 +13,8 @@ delete packageJson.dependencies['router-slot']; // Remove all DevDependencies delete packageJson.devDependencies; -// Rename dependencies to peerDependencies -packageJson.peerDependencies = packageJson.dependencies; +// Rename dependencies to optionalDependencies +packageJson.optionalDependencies = { ...packageJson.dependencies }; delete packageJson.dependencies; // Write the package.json back to disk diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json index af23894dd9..f2a604b2ba 100644 --- a/src/Umbraco.Web.UI.Client/package-lock.json +++ b/src/Umbraco.Web.UI.Client/package-lock.json @@ -1,13 +1,12 @@ { "name": "@umbraco-cms/backoffice", - "version": "0.0.0", + "version": "14.0.0--preview001", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@umbraco-cms/backoffice", - "version": "0.0.0", - "hasInstallScript": true, + "version": "14.0.0--preview001", "license": "MIT", "dependencies": { "@openid/appauth": "^1.3.1", @@ -30,7 +29,7 @@ "@playwright/test": "^1.30.0", "@rollup/plugin-commonjs": "^25.0.0", "@rollup/plugin-json": "^6.0.0", - "@rollup/plugin-node-resolve": "^15.0.1", + "@rollup/plugin-node-resolve": "^15.1.0", "@storybook/addon-a11y": "7.0.20", "@storybook/addon-actions": "7.0.20", "@storybook/addon-essentials": "7.0.20", @@ -45,7 +44,7 @@ "@typescript-eslint/eslint-plugin": "^5.59.9", "@typescript-eslint/parser": "^5.59.9", "@web/dev-server-esbuild": "^0.3.3", - "@web/dev-server-import-maps": "^0.0.7", + "@web/dev-server-import-maps": "^0.1.1", "@web/dev-server-rollup": "^0.3.21", "@web/test-runner": "^0.16.1", "@web/test-runner-playwright": "^0.10.0", @@ -3819,9 +3818,9 @@ } }, "node_modules/@rollup/plugin-node-resolve": { - "version": "15.0.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.0.2.tgz", - "integrity": "sha512-Y35fRGUjC3FaurG722uhUuG8YHOJRJQbI6/CkbRkdPotSpDj9NtIN85z1zrcyDcCQIW4qp5mgG72U+gJ0TAFEg==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.1.0.tgz", + "integrity": "sha512-xeZHCgsiZ9pzYVgAo9580eCGqwh/XCEUM9q6iQfGNocjgkufHAqC3exA+45URvhiYV8sBF9RlBai650eNs7AsA==", "dev": true, "dependencies": { "@rollup/pluginutils": "^5.0.1", @@ -7637,49 +7636,62 @@ } }, "node_modules/@web/dev-server-import-maps": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/@web/dev-server-import-maps/-/dev-server-import-maps-0.0.7.tgz", - "integrity": "sha512-uq8SFRkh3Zic71boDP/GeNwc7BtOWFWLDam3JJF3G0L9gMZVm7WteeDxxn9ppdbGxRhvlJtxqBlSOvf3pl75qw==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@web/dev-server-import-maps/-/dev-server-import-maps-0.1.1.tgz", + "integrity": "sha512-Et/uswWE2K9tFLM2xNArsvoDtFmBPyFrwJRm5O5ls5u0F3ZNE8vXk4kUONakillQ/041uSE30wIfesljl1ZKsg==", "dev": true, "dependencies": { "@import-maps/resolve": "^1.0.1", "@types/parse5": "^6.0.1", - "@web/dev-server-core": "^0.3.19", - "@web/parse5-utils": "^1.3.0", + "@web/dev-server-core": "^0.5.1", + "@web/parse5-utils": "^2.0.0", "parse5": "^6.0.1", "picomatch": "^2.2.2" }, "engines": { - "node": ">=10.0.0" + "node": ">=16.0.0" } }, "node_modules/@web/dev-server-import-maps/node_modules/@web/dev-server-core": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/@web/dev-server-core/-/dev-server-core-0.3.19.tgz", - "integrity": "sha512-Q/Xt4RMVebLWvALofz1C0KvP8qHbzU1EmdIA2Y1WMPJwiFJFhPxdr75p9YxK32P2t0hGs6aqqS5zE0HW9wYzYA==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@web/dev-server-core/-/dev-server-core-0.5.1.tgz", + "integrity": "sha512-pXgb4bjDmPIaIQT9luixTSqTvRQxttUEzSKOZqLNl6pVgrl4n47ZtmZte936G2tM7nHmpT+oaMDDtCM0CgbQNQ==", "dev": true, "dependencies": { "@types/koa": "^2.11.6", "@types/ws": "^7.4.0", - "@web/parse5-utils": "^1.2.0", + "@web/parse5-utils": "^2.0.0", "chokidar": "^3.4.3", "clone": "^2.1.2", "es-module-lexer": "^1.0.0", "get-stream": "^6.0.0", "is-stream": "^2.0.0", - "isbinaryfile": "^4.0.6", + "isbinaryfile": "^5.0.0", "koa": "^2.13.0", "koa-etag": "^4.0.0", "koa-send": "^5.0.1", "koa-static": "^5.0.0", - "lru-cache": "^6.0.0", + "lru-cache": "^8.0.4", "mime-types": "^2.1.27", "parse5": "^6.0.1", "picomatch": "^2.2.2", "ws": "^7.4.2" }, "engines": { - "node": ">=10.0.0" + "node": ">=16.0.0" + } + }, + "node_modules/@web/dev-server-import-maps/node_modules/@web/parse5-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@web/parse5-utils/-/parse5-utils-2.0.0.tgz", + "integrity": "sha512-9pxjAg1k0Ie3t4gTQr/nmoTrvq6wmP40MNPwaetaN+jPc328MpO+WzmEApvJOW65v7lamjlvYFDsdvG8Lrd87Q==", + "dev": true, + "dependencies": { + "@types/parse5": "^6.0.1", + "parse5": "^6.0.1" + }, + "engines": { + "node": ">=16.0.0" } }, "node_modules/@web/dev-server-import-maps/node_modules/es-module-lexer": { @@ -7688,28 +7700,13 @@ "integrity": "sha512-9978wrXM50Y4rTMmW5kXIC09ZdXQZqkE4mxhwkd8VbzsGkXGPgV4zWuqQJgCEzYngdo2dYDa0l8xhX4fkSwJSg==", "dev": true }, - "node_modules/@web/dev-server-import-maps/node_modules/isbinaryfile": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", - "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", - "dev": true, - "engines": { - "node": ">= 8.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/gjtorikian/" - } - }, "node_modules/@web/dev-server-import-maps/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-8.0.5.tgz", + "integrity": "sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==", "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, "engines": { - "node": ">=10" + "node": ">=16.14" } }, "node_modules/@web/dev-server-import-maps/node_modules/ws": { @@ -7733,12 +7730,6 @@ } } }, - "node_modules/@web/dev-server-import-maps/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/@web/dev-server-rollup": { "version": "0.3.21", "resolved": "https://registry.npmjs.org/@web/dev-server-rollup/-/dev-server-rollup-0.3.21.tgz", diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index 047b5288b5..45ad1630ba 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -1,7 +1,7 @@ { "name": "@umbraco-cms/backoffice", "license": "MIT", - "version": "0.0.0", + "version": "14.0.0--preview001", "type": "module", "exports": { ".": null, @@ -52,6 +52,7 @@ "./package": "./dist-cms/packages/packages/package/index.ts", "./data-type": "./dist-cms/packages/settings/data-types/index.ts", "./language": "./dist-cms/packages/settings/languages/index.ts", + "./logviewer": "./dist-cms/packages/settings/logviewer/index.js", "./relation-type": "./dist-cms/packages/settings/relation-types/index.ts", "./themes": "./dist-cms/packages/settings/themes/index.ts", "./tags": "./dist-cms/packages/tags/index.ts", @@ -87,7 +88,7 @@ "build:vite": "tsc && vite build --mode staging", "build:for:static": "vite build", "build:for:cms": "npm run build && node ./devops/build/copy-to-cms.js", - "build:for:npm": "npm run build && tsc-alias -f -p src/tsconfig.json", + "build:for:npm": "npm run build && tsc-alias -f -p src/tsconfig.json && npm run generate:jsonschema:dist && npm run wc-analyze && npm run wc-analyze:vscode", "preview": "vite preview --open", "test": "web-test-runner --coverage", "test:watch": "web-test-runner --watch", @@ -141,7 +142,7 @@ "@playwright/test": "^1.30.0", "@rollup/plugin-commonjs": "^25.0.0", "@rollup/plugin-json": "^6.0.0", - "@rollup/plugin-node-resolve": "^15.0.1", + "@rollup/plugin-node-resolve": "^15.1.0", "@storybook/addon-a11y": "7.0.20", "@storybook/addon-actions": "7.0.20", "@storybook/addon-essentials": "7.0.20", @@ -156,7 +157,7 @@ "@typescript-eslint/eslint-plugin": "^5.59.9", "@typescript-eslint/parser": "^5.59.9", "@web/dev-server-esbuild": "^0.3.3", - "@web/dev-server-import-maps": "^0.0.7", + "@web/dev-server-import-maps": "^0.1.1", "@web/dev-server-rollup": "^0.3.21", "@web/test-runner": "^0.16.1", "@web/test-runner-playwright": "^0.10.0", diff --git a/src/Umbraco.Web.UI.Client/src/apps/app/app.element.ts b/src/Umbraco.Web.UI.Client/src/apps/app/app.element.ts index 4e0e8a11fb..b07b5e9b5f 100644 --- a/src/Umbraco.Web.UI.Client/src/apps/app/app.element.ts +++ b/src/Umbraco.Web.UI.Client/src/apps/app/app.element.ts @@ -1,5 +1,5 @@ import type { UmbAppErrorElement } from './app-error.element.js'; -import { UMB_AUTH, UmbAuthFlow } from '@umbraco-cms/backoffice/auth'; +import { UMB_AUTH, UmbAuthFlow, UmbAuthContext } from '@umbraco-cms/backoffice/auth'; import { UMB_APP, UmbAppContext } from '@umbraco-cms/backoffice/context'; import { css, html, customElement, property } from '@umbraco-cms/backoffice/external/lit'; import { UUIIconRegistryEssential } from '@umbraco-cms/backoffice/external/uui'; @@ -81,7 +81,9 @@ export class UmbAppElement extends UmbLitElement { this.#authFlow = new UmbAuthFlow(this.serverUrl, redirectUrl); - this.provideContext(UMB_AUTH, this.#authFlow); + const authContext = new UmbAuthContext(this, this.#authFlow); + + this.provideContext(UMB_AUTH, authContext); this.provideContext(UMB_APP, new UmbAppContext({ backofficePath: this.backofficePath, serverUrl: this.serverUrl })); @@ -99,6 +101,8 @@ export class UmbAppElement extends UmbLitElement { OpenAPI.WITH_CREDENTIALS = true; } + authContext.isLoggedIn.next(true); + // Initialise the router this.#redirect(); } catch (error) { diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/TemplateItemResponseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/TemplateItemResponseModel.ts index 023262e3b2..4495353e0e 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/TemplateItemResponseModel.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/TemplateItemResponseModel.ts @@ -4,5 +4,7 @@ import type { ItemResponseModelBaseModel } from './ItemResponseModelBaseModel'; -export type TemplateItemResponseModel = ItemResponseModelBaseModel; +export type TemplateItemResponseModel = (ItemResponseModelBaseModel & { + alias?: string; +}); diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/TemplateResponseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/TemplateResponseModel.ts index 4163616f8f..596b2be0c2 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/TemplateResponseModel.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/TemplateResponseModel.ts @@ -7,5 +7,6 @@ import type { TemplateModelBaseModel } from './TemplateModelBaseModel'; export type TemplateResponseModel = (TemplateModelBaseModel & { $type: string; id?: string; + masterTemplateId?: string | null; }); diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/DataTypeResource.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/DataTypeResource.ts index 1ce6ab2cae..3a4bd4ed78 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/DataTypeResource.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/DataTypeResource.ts @@ -306,6 +306,24 @@ export class DataTypeResource { }); } + /** + * @returns any Success + * @throws ApiError + */ + public static getDataTypeItemByAlias({ + alias, + }: { + alias: string, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/umbraco/management/api/v1/data-type/item/{alias}', + path: { + 'alias': alias, + }, + }); + } + /** * @returns PagedFolderTreeItemResponseModel Success * @throws ApiError diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/DocumentTypeResource.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/DocumentTypeResource.ts index 775098175e..8f120b22ea 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/DocumentTypeResource.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/DocumentTypeResource.ts @@ -27,10 +27,8 @@ export class DocumentTypeResource { url: '/umbraco/management/api/v1/document-type', body: requestBody, mediaType: 'application/json', - responseHeader: 'location', errors: { 400: `Bad Request`, - 404: `Not Found`, }, }); } diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/TemplateResource.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/TemplateResource.ts index b7568d4a24..8a8f258f73 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/TemplateResource.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/TemplateResource.ts @@ -158,10 +158,17 @@ export class TemplateResource { * @returns any Success * @throws ApiError */ - public static getTemplateScaffold(): CancelablePromise { + public static getTemplateScaffold({ + masterTemplateId, + }: { + masterTemplateId?: string, + }): CancelablePromise { return __request(OpenAPI, { method: 'GET', url: '/umbraco/management/api/v1/template/scaffold', + query: { + 'masterTemplateId': masterTemplateId, + }, errors: { 404: `Not Found`, }, diff --git a/src/Umbraco.Web.UI.Client/src/libs/extension-api/entry-point-extension-initializer.ts b/src/Umbraco.Web.UI.Client/src/libs/extension-api/entry-point-extension-initializer.ts index fe5bbfa414..613f404790 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/extension-api/entry-point-extension-initializer.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/extension-api/entry-point-extension-initializer.ts @@ -2,14 +2,14 @@ import type { ManifestEntryPoint } from './types.js'; import { hasInitExport } from './has-init-export.function.js'; import { loadExtension } from './load-extension.function.js'; import { UmbExtensionRegistry } from './registry/extension.registry.js'; -import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; +import { UmbElementMixinInterface } from '@umbraco-cms/backoffice/element-api'; export class UmbEntryPointExtensionInitializer { #host; #extensionRegistry; #entryPointMap = new Map(); - constructor(host: UmbControllerHostElement, extensionRegistry: UmbExtensionRegistry) { + constructor(host: UmbElementMixinInterface, extensionRegistry: UmbExtensionRegistry) { this.#host = host; this.#extensionRegistry = extensionRegistry; extensionRegistry.extensionsOfType('entryPoint').subscribe((entryPoints) => { diff --git a/src/Umbraco.Web.UI.Client/src/libs/extension-api/umb-lifecycle.interface.ts b/src/Umbraco.Web.UI.Client/src/libs/extension-api/umb-lifecycle.interface.ts index 2057abf5f6..3d7d8ef66c 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/extension-api/umb-lifecycle.interface.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/extension-api/umb-lifecycle.interface.ts @@ -1,9 +1,9 @@ import type { UmbExtensionRegistry } from './registry/extension.registry.js'; import { ManifestBase } from './types.js'; -import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; +import type { UmbElementMixinInterface } from '@umbraco-cms/backoffice/element-api'; export type UmbEntryPointOnInit = ( - host: UmbControllerHostElement, + host: UmbElementMixinInterface, extensionRegistry: UmbExtensionRegistry ) => void; diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/users.data.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/users.data.ts index b55f498667..beda25493a 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/data/users.data.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/data/users.data.ts @@ -1,3 +1,4 @@ +import { UmbLoggedInUser } from '@umbraco-cms/backoffice/auth'; import { UmbData } from './data.js'; import { PagedUserResponseModel, UserResponseModel, UserStateModel } from '@umbraco-cms/backoffice/backend-api'; @@ -18,6 +19,25 @@ class UmbUsersData extends UmbData { return this.data.find((user) => user.id === id); } + getCurrentUser(): UmbLoggedInUser { + const firstUser = this.data[0]; + + return { + $type: 'CurrentUserResponseModel', + id: firstUser.id, + name: firstUser.name, + email: firstUser.email, + userName: firstUser.email, + avatarUrls: [], + hasAccessToAllLanguages: true, + languageIsoCode: firstUser.languageIsoCode, + languages: [], + contentStartNodeIds: firstUser.contentStartNodeIds, + mediaStartNodeIds: firstUser.mediaStartNodeIds, + permissions: [], + }; + } + save(id: string, saveItem: UserResponseModel) { const foundIndex = this.data.findIndex((item) => item.id === id); if (foundIndex !== -1) { @@ -96,9 +116,9 @@ export const data: Array = [ $type: 'UserResponseModel', contentStartNodeIds: [], mediaStartNodeIds: [], - name: 'Erny Baptista', - email: 'ebaptista1@csmonitor.com', - languageIsoCode: 'Kannada', + name: 'Umbraco User', + email: 'noreply@umbraco.com', + languageIsoCode: 'en-US', state: UserStateModel.ACTIVE, lastLoginDate: '9/10/2022', lastLockoutDate: '11/23/2021', diff --git a/src/Umbraco.Web.UI.Client/src/mocks/handlers/user.handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/handlers/user.handlers.ts index 3d9ceee1b0..9da37812be 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/handlers/user.handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/handlers/user.handlers.ts @@ -3,18 +3,31 @@ const { rest } = window.MockServiceWorker; import { umbUsersData } from '../data/users.data.js'; import { umbracoPath } from '@umbraco-cms/backoffice/utils'; -let isAuthenticated = true; const slug = '/user'; export const handlers = [ - rest.get(umbracoPath(`${slug}`), (req, res, ctx) => { + rest.get(umbracoPath(`${slug}/filter`), (req, res, ctx) => { + //TODO: Implementer filter const response = umbUsersData.getAll(); return res(ctx.status(200), ctx.json(response)); }), - rest.get(umbracoPath(`${slug}/filter`), (req, res, ctx) => { - //TODO: Implementer filter + rest.get(umbracoPath(`${slug}/current`), (_req, res, ctx) => { + const loggedInUser = umbUsersData.getCurrentUser(); + return res(ctx.status(200), ctx.json(loggedInUser)); + }), + + rest.get(umbracoPath(`${slug}/sections`), (_req, res, ctx) => { + return res( + ctx.status(200), + ctx.json({ + sections: ['Umb.Section.Content', 'Umb.Section.Media', 'Umb.Section.Settings', 'My.Section.Custom'], + }) + ); + }), + + rest.get(umbracoPath(`${slug}`), (req, res, ctx) => { const response = umbUsersData.getAll(); return res(ctx.status(200), ctx.json(response)); @@ -40,51 +53,4 @@ export const handlers = [ return res(ctx.status(200), ctx.json(saved)); }), - rest.post(umbracoPath('/user/login'), (_req, res, ctx) => { - // Persist user's authentication in the session - isAuthenticated = true; - return res( - // Respond with a 200 status code - ctx.status(201) - ); - }), - - rest.post(umbracoPath('/user/logout'), (_req, res, ctx) => { - // Persist user's authentication in the session - isAuthenticated = false; - return res( - // Respond with a 200 status code - ctx.status(201) - ); - }), - - rest.get(umbracoPath('/user'), (_req, res, ctx) => { - // Check if the user is authenticated in this session - if (!isAuthenticated) { - // If not authenticated, respond with a 403 error - return res( - ctx.status(403), - ctx.json({ - errorMessage: 'Not authorized', - }) - ); - } - // If authenticated, return a mocked user details - return res( - ctx.status(200), - ctx.json({ - username: 'admin', - role: 'administrator', - }) - ); - }), - - rest.get(umbracoPath('/user/sections'), (_req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - sections: ['Umb.Section.Content', 'Umb.Section.Media', 'Umb.Section.Settings', 'My.Section.Custom'], - }) - ); - }), ]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/components/date-input/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/components/date-input/index.ts deleted file mode 100644 index 152cb2f39b..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/core/components/date-input/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './date-input.element.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/components/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/components/index.ts index e9aeaa4b26..9c5addfe1c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/components/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/components/index.ts @@ -6,7 +6,7 @@ export * from './body-layout/body-layout.element.js'; export * from './button-with-dropdown/button-with-dropdown.element.js'; // TODO: delete this and change usage to umb-dropdown // export * from './code-block.js'; export * from './data-type/index.js'; -export * from './date-input/index.js'; +export * from './input-date/index.js'; export * from './dropdown/index.js'; export * from './empty-state/index.js'; export * from './entity-actions-bundle/index.js'; @@ -15,7 +15,7 @@ export * from './footer-layout/index.js'; export * from './header-app/index.js'; export * from './history/index.js'; export * from './input-checkbox-list/index.js'; -export * from './input-color-picker/index.js'; +export * from './input-color/index.js'; export * from './input-eye-dropper/index.js'; export * from './input-list-base/index.js'; export * from './input-multi-url/index.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/components/input-color-picker/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-color-picker/index.ts deleted file mode 100644 index 3ab655ba9f..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/core/components/input-color-picker/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './input-color-picker.element.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/components/input-color/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-color/index.ts new file mode 100644 index 0000000000..724140b2c6 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-color/index.ts @@ -0,0 +1 @@ +export * from './input-color.element.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/components/input-color-picker/input-color-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-color/input-color.element.ts similarity index 81% rename from src/Umbraco.Web.UI.Client/src/packages/core/components/input-color-picker/input-color-picker.element.ts rename to src/Umbraco.Web.UI.Client/src/packages/core/components/input-color/input-color.element.ts index d8ce9cb7b2..7977381e49 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/components/input-color-picker/input-color-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-color/input-color.element.ts @@ -5,14 +5,14 @@ import type { UmbSwatchDetails } from '@umbraco-cms/backoffice/models'; /* * This wraps the UUI library uui-color-swatches component - * @element umb-input-color-picker + * @element umb-input-color */ -@customElement('umb-input-color-picker') -export class UmbInputColorPickerElement extends FormControlMixin(UmbLitElement) { +@customElement('umb-input-color') +export class UmbInputColorElement extends FormControlMixin(UmbLitElement) { @property({ type: Boolean }) showLabels = false; - @property() + @property({ type: Array }) swatches?: UmbSwatchDetails[]; constructor() { @@ -47,10 +47,10 @@ export class UmbInputColorPickerElement extends FormControlMixin(UmbLitElement) static styles = [UUITextStyles]; } -export default UmbInputColorPickerElement; +export default UmbInputColorElement; declare global { interface HTMLElementTagNameMap { - 'umb-input-color-picker': UmbInputColorPickerElement; + 'umb-input-color': UmbInputColorElement; } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/components/input-color-picker/input-color-picker.mdx b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-color/input-color.mdx similarity index 56% rename from src/Umbraco.Web.UI.Client/src/packages/core/components/input-color-picker/input-color-picker.mdx rename to src/Umbraco.Web.UI.Client/src/packages/core/components/input-color/input-color.mdx index d86f8308d8..f24e138b0c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/components/input-color-picker/input-color-picker.mdx +++ b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-color/input-color.mdx @@ -1,7 +1,7 @@ import { Meta, Title, Primary, Controls, Story, Source } from '@storybook/blocks'; -import * as ColorPickerStories from './input-color-picker.stories'; +import * as ColorStories from './input-color.stories'; - + This color picker allows you to select a color from a palette. @@ -12,14 +12,14 @@ This shows how we can override the autogen docs from StoryBook to document a com ### Primary -<Story of={ColorPickerStories.Overview} /> -<Source of={ColorPickerStories.Overview} /> +<Story of={ColorStories.Overview} /> +<Source of={ColorStories.Overview} /> ## Properties -<Controls of={ColorPickerStories.Overview} /> +<Controls of={ColorStories.Overview} /> ### Without Labels -<Story of={ColorPickerStories.WithoutLabels} /> -<Source of={ColorPickerStories.WithoutLabels} dark /> +<Story of={ColorStories.WithoutLabels} /> +<Source of={ColorStories.WithoutLabels} dark /> diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/components/input-color-picker/input-color-picker.stories.ts b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-color/input-color.stories.ts similarity index 72% rename from src/Umbraco.Web.UI.Client/src/packages/core/components/input-color-picker/input-color-picker.stories.ts rename to src/Umbraco.Web.UI.Client/src/packages/core/components/input-color/input-color.stories.ts index 3614ef75c8..2962c6c728 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/components/input-color-picker/input-color-picker.stories.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-color/input-color.stories.ts @@ -1,14 +1,14 @@ import { Meta, StoryObj } from '@storybook/web-components'; -import './input-color-picker.element.js'; -import type { UmbInputColorPickerElement } from './input-color-picker.element.js'; +import './input-color.element.js'; +import type { UmbInputColorElement } from './input-color.element.js'; -const meta: Meta<UmbInputColorPickerElement> = { - title: 'Components/Inputs/Color Picker', - component: 'umb-input-color-picker', +const meta: Meta<UmbInputColorElement> = { + title: 'Components/Inputs/Color', + component: 'umb-input-color', }; export default meta; -type Story = StoryObj<UmbInputColorPickerElement>; +type Story = StoryObj<UmbInputColorElement>; export const Overview: Story = { args: { @@ -46,6 +46,7 @@ export const WithoutLabels: Story = { // Perhaps a BUG ? export const WithValueLabels: Story = { args: { + value: '#00ff00', showLabels: true, swatches: [ { @@ -57,6 +58,5 @@ export const WithValueLabels: Story = { value: '#00ff00', }, ], - value: '#00ff00', }, }; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media-picker/input-media-picker.test.ts b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-color/input-color.test.ts similarity index 51% rename from src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media-picker/input-media-picker.test.ts rename to src/Umbraco.Web.UI.Client/src/packages/core/components/input-color/input-color.test.ts index deaf1d7be3..c9b3a55d70 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media-picker/input-media-picker.test.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-color/input-color.test.ts @@ -1,15 +1,15 @@ import { expect, fixture, html } from '@open-wc/testing'; -import { UmbInputMediaPickerElement } from './input-media-picker.element.js'; +import { UmbInputColorElement } from './input-color.element.js'; import { defaultA11yConfig } from '@umbraco-cms/internal/test-utils'; -describe('UmbInputMediaPickerElement', () => { - let element: UmbInputMediaPickerElement; +describe('UmbInputColorElement', () => { + let element: UmbInputColorElement; beforeEach(async () => { - element = await fixture(html` <umb-input-media-picker></umb-input-media-picker> `); + element = await fixture(html` <umb-input-color></umb-input-color> `); }); it('is defined with its own instance', () => { - expect(element).to.be.instanceOf(UmbInputMediaPickerElement); + expect(element).to.be.instanceOf(UmbInputColorElement); }); it('passes the a11y audit', async () => { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/components/input-date/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-date/index.ts new file mode 100644 index 0000000000..2347a2f0fb --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-date/index.ts @@ -0,0 +1 @@ +export * from './input-date.element.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/components/date-input/date-input.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-date/input-date.element.ts similarity index 94% rename from src/Umbraco.Web.UI.Client/src/packages/core/components/date-input/date-input.element.ts rename to src/Umbraco.Web.UI.Client/src/packages/core/components/input-date/input-date.element.ts index 7d645530d8..de1c904429 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/components/date-input/date-input.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-date/input-date.element.ts @@ -3,8 +3,8 @@ import { css, html, ifDefined, customElement, property, state } from '@umbraco-c import { UUITextStyles, FormControlMixin, UUIInputEvent } from '@umbraco-cms/backoffice/external/uui'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; -@customElement('umb-date-input') -export class UmbDateInputElement extends FormControlMixin(UmbLitElement) { +@customElement('umb-input-date') +export class UmbInputDateElement extends FormControlMixin(UmbLitElement) { protected getFormElement() { return undefined; } @@ -136,8 +136,8 @@ export class UmbDateInputElement extends FormControlMixin(UmbLitElement) { label="Pick a date or time" .type="${this.type}" @change="${this.#onChange}" - .min="${ifDefined(this.min)}" - .max="${ifDefined(this.max)}" + min="${ifDefined(this.min)}" + max="${ifDefined(this.max)}" .step="${this.step}" .value="${this.displayValue?.replace('Z', '')}"> </uui-input>`; @@ -146,10 +146,10 @@ export class UmbDateInputElement extends FormControlMixin(UmbLitElement) { static styles = [UUITextStyles, css``]; } -export default UmbDateInputElement; +export default UmbInputDateElement; declare global { interface HTMLElementTagNameMap { - 'umb-date-input': UmbDateInputElement; + 'umb-input-date': UmbInputDateElement; } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/components/date-input/date-input.stories.ts b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-date/input-date.stories.ts similarity index 73% rename from src/Umbraco.Web.UI.Client/src/packages/core/components/date-input/date-input.stories.ts rename to src/Umbraco.Web.UI.Client/src/packages/core/components/input-date/input-date.stories.ts index cbfd368c35..c2eec6dffa 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/components/date-input/date-input.stories.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-date/input-date.stories.ts @@ -1,15 +1,15 @@ import { Meta, StoryObj } from '@storybook/web-components'; +import type { UmbInputDateElement } from './input-date.element.js'; import { html } from '@umbraco-cms/backoffice/external/lit'; -import './date-input.element.js'; -import type { UmbDateInputElement } from './date-input.element.js'; +import './input-date.element.js'; -const meta: Meta<UmbDateInputElement> = { +const meta: Meta<UmbInputDateElement> = { title: 'Components/Inputs/Date', - component: 'umb-date-input', + component: 'umb-input-date', }; export default meta; -type Story = StoryObj<UmbDateInputElement>; +type Story = StoryObj<UmbInputDateElement>; export const Overview: Story = { args: { @@ -43,11 +43,11 @@ export const DatetimelocalOffset: Story = { displayValue: '', }, render: (args) => - html`<umb-date-input + html`<umb-input-date .type="${args.type}" .value="${args.value}" .offsetTime="${args.offsetTime}" - .displayValue="${args.displayValue}"></umb-date-input>`, + .displayValue="${args.displayValue}"></umb-input-date>`, }; export const Datetimelocal: Story = { @@ -58,9 +58,9 @@ export const Datetimelocal: Story = { displayValue: '', }, render: (args) => - html`<umb-date-input + html`<umb-input-date .type="${args.type}" .value="${args.value}" .offsetTime="${args.offsetTime}" - .displayValue="${args.displayValue}"></umb-date-input>`, + .displayValue="${args.displayValue}"></umb-input-date>`, }; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/components/date-input/date-input.test.ts b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-date/input-date.test.ts similarity index 57% rename from src/Umbraco.Web.UI.Client/src/packages/core/components/date-input/date-input.test.ts rename to src/Umbraco.Web.UI.Client/src/packages/core/components/input-date/input-date.test.ts index 45ddf3121c..af3fa7afa4 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/components/date-input/date-input.test.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-date/input-date.test.ts @@ -1,15 +1,15 @@ import { expect, fixture, html } from '@open-wc/testing'; -import { UmbDateInputElement } from './date-input.element.js'; +import { UmbInputDateElement } from './input-date.element.js'; import { defaultA11yConfig } from '@umbraco-cms/internal/test-utils'; -describe('UmbDateInputElement', () => { - let element: UmbDateInputElement; +describe('UmbInputDateElement', () => { + let element: UmbInputDateElement; beforeEach(async () => { - element = await fixture(html` <umb-date-input></umb-date-input> `); + element = await fixture(html` <umb-input-date></umb-input-date> `); }); it('is defined with its own instance', () => { - expect(element).to.be.instanceOf(UmbDateInputElement); + expect(element).to.be.instanceOf(UmbInputDateElement); }); it('passes the a11y audit', async () => { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/umbraco-package.ts b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/umbraco-package.ts index bc2d9b4a5c..efa8ca584d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/umbraco-package.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/umbraco-package.ts @@ -3,11 +3,17 @@ import type { ManifestTypes } from './models/index.js'; /** * Umbraco package manifest JSON */ -export class UmbracoPackage { +export interface UmbracoPackage { + /** + * @title The unique identifier of the Umbraco package + */ + id?: string; + /** * @title The name of the Umbraco package + * @required */ - name?: string; + name: string; /** * @title The version of the Umbraco package in the style of semver @@ -23,6 +29,7 @@ export class UmbracoPackage { /** * @title An array of Umbraco package manifest types that will be installed + * @required */ - extensions?: ManifestTypes[]; + extensions: ManifestTypes[]; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/property-editors/uis/color-picker/property-editor-ui-color-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/property-editors/uis/color-picker/property-editor-ui-color-picker.element.ts index 668a74f60d..24c630ca8a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/property-editors/uis/color-picker/property-editor-ui-color-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/property-editors/uis/color-picker/property-editor-ui-color-picker.element.ts @@ -33,10 +33,10 @@ export class UmbPropertyEditorUIColorPickerElement extends UmbLitElement impleme } render() { - return html`<umb-input-color-picker + return html`<umb-input-color @change="${this._onChange}" .swatches="${this._swatches}" - .showLabels="${this._showLabels}"></umb-input-color-picker>`; + .showLabels="${this._showLabels}"></umb-input-color>`; } static styles = [UUITextStyles]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/property-editors/uis/date-picker/property-editor-ui-date-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/property-editors/uis/date-picker/property-editor-ui-date-picker.element.ts index 9ac2c4ab3c..5000ed07a2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/property-editors/uis/date-picker/property-editor-ui-date-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/property-editors/uis/date-picker/property-editor-ui-date-picker.element.ts @@ -82,7 +82,7 @@ export class UmbPropertyEditorUIDatePickerElement extends UmbLitElement implemen } render() { - return html`<umb-date-input + return html`<umb-input-date .type=${this._inputType} @input=${this._onInput} .datetime=${this._valueString} @@ -90,7 +90,7 @@ export class UmbPropertyEditorUIDatePickerElement extends UmbLitElement implemen .max=${this._max} .step=${this._step} .offsetTime=${this._offsetTime} - label="Pick a date or time"></umb-date-input>`; + label="Pick a date or time"></umb-input-date>`; } static styles = [UUITextStyles]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/property-editors/uis/date-picker/property-editor-ui-date-picker.test.ts b/src/Umbraco.Web.UI.Client/src/packages/core/property-editors/uis/date-picker/property-editor-ui-date-picker.test.ts index c4f172831b..dd4a637fc2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/property-editors/uis/date-picker/property-editor-ui-date-picker.test.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/property-editors/uis/date-picker/property-editor-ui-date-picker.test.ts @@ -1,16 +1,16 @@ import { expect, fixture, html } from '@open-wc/testing'; -import { UmbDateInputElement } from '../../../components/date-input/date-input.element.js'; +import { UmbInputDateElement } from '../../../components/input-date/input-date.element.js'; import { UmbPropertyEditorUIDatePickerElement } from './property-editor-ui-date-picker.element.js'; import { defaultA11yConfig } from '@umbraco-cms/internal/test-utils'; import { UmbDataTypePropertyCollection } from '@umbraco-cms/backoffice/components'; describe('UmbPropertyEditorUIDatePickerElement', () => { let element: UmbPropertyEditorUIDatePickerElement; - let inputElement: UmbDateInputElement; + let inputElement: UmbInputDateElement; beforeEach(async () => { element = await fixture(html` <umb-property-editor-ui-date-picker></umb-property-editor-ui-date-picker> `); - inputElement = element.shadowRoot?.querySelector('umb-date-input') as UmbDateInputElement; + inputElement = element.shadowRoot?.querySelector('umb-input-date') as UmbInputDateElement; }); it('is defined with its own instance', () => { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/property-editors/uis/media-picker/property-editor-ui-media-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/property-editors/uis/media-picker/property-editor-ui-media-picker.element.ts index 37e46b0d08..04004388f8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/property-editors/uis/media-picker/property-editor-ui-media-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/property-editors/uis/media-picker/property-editor-ui-media-picker.element.ts @@ -1,4 +1,4 @@ -import { UmbInputMediaPickerElement } from '../../../../media/media/components/input-media-picker/input-media-picker.element.js'; +import { UmbInputMediaElement } from '../../../../media/media/components/input-media/input-media.element.js'; import { html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit'; import type { UmbDataTypePropertyCollection } from '@umbraco-cms/backoffice/components'; import { UmbPropertyEditorExtensionElement } from '@umbraco-cms/backoffice/extension-registry'; @@ -36,18 +36,18 @@ export class UmbPropertyEditorUIMediaPickerElement extends UmbLitElement impleme private _limitMax?: number; private _onChange(event: CustomEvent) { - this.value = (event.target as UmbInputMediaPickerElement).selectedIds; + this.value = (event.target as UmbInputMediaElement).selectedIds; this.dispatchEvent(new CustomEvent('property-value-change')); } render() { return html` - <umb-input-media-picker + <umb-input-media @change=${this._onChange} .selectedIds=${this._value} .min=${this._limitMin} .max=${this._limitMax} - >Add</umb-input-media-picker + >Add</umb-input-media > `; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/components/index.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/components/index.ts index 7f50f2e118..be24cd45e5 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/components/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/components/index.ts @@ -1 +1 @@ -import './input-document-type-picker/input-document-type-picker.element.js'; +import './input-document-type/input-document-type.element.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/components/input-document-type-picker/input-document-type-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/components/input-document-type/input-document-type.element.ts similarity index 94% rename from src/Umbraco.Web.UI.Client/src/packages/documents/document-types/components/input-document-type-picker/input-document-type-picker.element.ts rename to src/Umbraco.Web.UI.Client/src/packages/documents/document-types/components/input-document-type/input-document-type.element.ts index 3753a17089..bdbdeabd1d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/components/input-document-type-picker/input-document-type-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/components/input-document-type/input-document-type.element.ts @@ -14,8 +14,8 @@ import { import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; import { UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; -@customElement('umb-input-document-type-picker') -export class UmbInputDocumentTypePickerElement extends FormControlMixin(UmbLitElement) { +@customElement('umb-input-document-type') +export class UmbInputDocumentTypeElement extends FormControlMixin(UmbLitElement) { // TODO: do we need both selectedIds and value? If we just use value we follow the same pattern as native form controls. private _selectedIds: Array<string> = []; @property({ type: Array }) @@ -130,10 +130,10 @@ export class UmbInputDocumentTypePickerElement extends FormControlMixin(UmbLitEl ]; } -export default UmbInputDocumentTypePickerElement; +export default UmbInputDocumentTypeElement; declare global { interface HTMLElementTagNameMap { - 'umb-input-document-type-picker': UmbInputDocumentTypePickerElement; + 'umb-input-document-type': UmbInputDocumentTypeElement; } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/structure/document-type-workspace-view-structure.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/structure/document-type-workspace-view-structure.element.ts index c92d162035..66abc25720 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/structure/document-type-workspace-view-structure.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/structure/document-type-workspace-view-structure.element.ts @@ -1,5 +1,5 @@ import { UmbDocumentTypeWorkspaceContext } from '../../document-type-workspace.context.js'; -import type { UmbInputDocumentTypePickerElement } from '../../../components/input-document-type-picker/input-document-type-picker.element.js'; +import type { UmbInputDocumentTypeElement } from '../../../components/input-document-type/input-document-type.element.js'; import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit'; import { UUITextStyles } from '@umbraco-cms/backoffice/external/uui'; import type { UUIToggleElement } from '@umbraco-cms/backoffice/external/uui'; @@ -62,10 +62,10 @@ export class UmbDocumentTypeWorkspaceViewStructureElement </div> <div slot="editor"> <!-- TODO: maybe we want to somehow display the hierarchy, but not necessary in the same way as old backoffice? --> - <umb-input-document-type-picker + <umb-input-document-type .selectedIds=${this._allowedContentTypeIDs} @change="${(e: CustomEvent) => { - const sortedContentTypesList = (e.target as UmbInputDocumentTypePickerElement).selectedIds.map( + const sortedContentTypesList = (e.target as UmbInputDocumentTypeElement).selectedIds.map( (id, index) => ({ id: id, sortOrder: index, @@ -73,7 +73,7 @@ export class UmbDocumentTypeWorkspaceViewStructureElement ); this.#workspaceContext?.setAllowedContentTypes(sortedContentTypesList); }}"> - </umb-input-document-type-picker> + </umb-input-document-type> </div> </umb-workspace-property-layout> </uui-box> diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/index.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/index.ts index 82c1e96c4f..339d030d1d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/index.ts @@ -1 +1 @@ -export * from './input-document-picker/input-document-picker.element.js'; +export * from './input-document/input-document.element.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document-picker/input-document-picker.stories.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document-picker/input-document-picker.stories.ts deleted file mode 100644 index 925fe717a4..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document-picker/input-document-picker.stories.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Meta, StoryObj } from '@storybook/web-components'; -import './input-document-picker.element.js'; -import type { UmbInputDocumentPickerElement } from './input-document-picker.element.js'; - -const meta: Meta<UmbInputDocumentPickerElement> = { - title: 'Components/Inputs/Document Picker', - component: 'umb-input-document-picker', -}; - -export default meta; -type Story = StoryObj<UmbInputDocumentPickerElement>; - -export const Overview: Story = { - args: {}, -}; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document-picker/input-document-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts similarity index 95% rename from src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document-picker/input-document-picker.element.ts rename to src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts index 50b1ae9836..5467763560 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document-picker/input-document-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts @@ -12,8 +12,8 @@ import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; import type { DocumentTreeItemResponseModel, EntityTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; import type { UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; -@customElement('umb-input-document-picker') -export class UmbInputDocumentPickerElement extends FormControlMixin(UmbLitElement) { +@customElement('umb-input-document') +export class UmbInputDocumentElement extends FormControlMixin(UmbLitElement) { /** * This is a minimum amount of selected items in this input. * @type {number} @@ -174,10 +174,10 @@ export class UmbInputDocumentPickerElement extends FormControlMixin(UmbLitElemen ]; } -export default UmbInputDocumentPickerElement; +export default UmbInputDocumentElement; declare global { interface HTMLElementTagNameMap { - 'umb-input-document-picker': UmbInputDocumentPickerElement; + 'umb-input-document': UmbInputDocumentElement; } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.stories.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.stories.ts new file mode 100644 index 0000000000..fecf4787e4 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.stories.ts @@ -0,0 +1,14 @@ +import { Meta, StoryObj } from '@storybook/web-components'; +import './input-document.element.js'; +import type { UmbInputDocumentElement } from './input-document.element.js'; + +const meta: Meta<UmbInputDocumentElement> = { + title: 'Components/Inputs/Document', + component: 'umb-input-document', +}; + +export default meta; +type Story = StoryObj<UmbInputDocumentElement>; +export const Overview: Story = { + args: {}, +}; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/components/input-color-picker/input-color-picker.test.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.test.ts similarity index 51% rename from src/Umbraco.Web.UI.Client/src/packages/core/components/input-color-picker/input-color-picker.test.ts rename to src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.test.ts index cb6e2c004a..de1bd824d5 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/components/input-color-picker/input-color-picker.test.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.test.ts @@ -1,15 +1,15 @@ import { expect, fixture, html } from '@open-wc/testing'; -import { UmbInputColorPickerElement } from './input-color-picker.element.js'; +import { UmbInputDocumentElement } from './input-document.element.js'; import { defaultA11yConfig } from '@umbraco-cms/internal/test-utils'; -describe('UmbInputColorPickerElement', () => { - let element: UmbInputColorPickerElement; +describe('UmbInputDocumentElement', () => { + let element: UmbInputDocumentElement; beforeEach(async () => { - element = await fixture(html` <umb-input-color-picker></umb-input-color-picker> `); + element = await fixture(html` <umb-input-document></umb-input-document> `); }); it('is defined with its own instance', () => { - expect(element).to.be.instanceOf(UmbInputColorPickerElement); + expect(element).to.be.instanceOf(UmbInputDocumentElement); }); it('passes the a11y audit', async () => { diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts index 4f57b17cc2..3c810524f2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/property-editors/document-picker/property-editor-ui-document-picker.element.ts @@ -1,4 +1,4 @@ -import type { UmbInputDocumentPickerElement } from '../../components/input-document-picker/input-document-picker.element.js'; +import type { UmbInputDocumentElement } from '../../components/input-document/input-document.element.js'; import { html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit'; import { UmbPropertyEditorExtensionElement } from '@umbraco-cms/backoffice/extension-registry'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; @@ -33,19 +33,19 @@ export class UmbPropertyEditorUIContentPickerElement private _limitMax?: number; private _onChange(event: CustomEvent) { - this.value = (event.target as UmbInputDocumentPickerElement).selectedIds; + this.value = (event.target as UmbInputDocumentElement).selectedIds; this.dispatchEvent(new CustomEvent('property-value-change')); } // TODO: Implement mandatory? render() { return html` - <umb-input-document-picker + <umb-input-document @change=${this._onChange} .selectedIds=${this._value} .min=${this._limitMin} .max=${this._limitMax} - >Add</umb-input-document-picker + >Add</umb-input-document > `; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/index.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/index.ts index 4c82520e7c..f744600b4e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/index.ts @@ -1 +1 @@ -import './input-media-picker/input-media-picker.element.js'; +import './input-media/input-media.element.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media-picker/input-media-picker.stories.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media-picker/input-media-picker.stories.ts deleted file mode 100644 index e4874e9c26..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media-picker/input-media-picker.stories.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Meta, StoryObj } from '@storybook/web-components'; -import './input-media-picker.element.js'; -import type { UmbInputMediaPickerElement } from './input-media-picker.element.js'; - -const meta: Meta<UmbInputMediaPickerElement> = { - title: 'Components/Inputs/Media Picker', - component: 'umb-input-media-picker', -}; - -export default meta; -type Story = StoryObj<UmbInputMediaPickerElement>; - -export const Overview: Story = { - args: {}, -}; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media-picker/input-media-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.element.ts similarity index 96% rename from src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media-picker/input-media-picker.element.ts rename to src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.element.ts index a7e10234b7..df77875f5b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media-picker/input-media-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.element.ts @@ -11,8 +11,8 @@ import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; import type { EntityTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; import type { UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; -@customElement('umb-input-media-picker') -export class UmbInputMediaPickerElement extends FormControlMixin(UmbLitElement) { +@customElement('umb-input-media') +export class UmbInputMediaElement extends FormControlMixin(UmbLitElement) { /** * This is a minimum amount of selected items in this input. * @type {number} @@ -201,10 +201,10 @@ export class UmbInputMediaPickerElement extends FormControlMixin(UmbLitElement) ]; } -export default UmbInputMediaPickerElement; +export default UmbInputMediaElement; declare global { interface HTMLElementTagNameMap { - 'umb-input-media-picker': UmbInputMediaPickerElement; + 'umb-input-media': UmbInputMediaElement; } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.stories.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.stories.ts new file mode 100644 index 0000000000..821dc7c993 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.stories.ts @@ -0,0 +1,15 @@ +import { Meta, StoryObj } from '@storybook/web-components'; +import './input-media.element.js'; +import type { UmbInputMediaElement } from './input-media.element.js'; + +const meta: Meta<UmbInputMediaElement> = { + title: 'Components/Inputs/Media', + component: 'umb-input-media', +}; + +export default meta; +type Story = StoryObj<UmbInputMediaElement>; + +export const Overview: Story = { + args: {}, +}; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document-picker/input-document-picker.test.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.test.ts similarity index 50% rename from src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document-picker/input-document-picker.test.ts rename to src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.test.ts index 38792739e8..9d0e4f8ea9 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document-picker/input-document-picker.test.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.test.ts @@ -1,15 +1,15 @@ import { expect, fixture, html } from '@open-wc/testing'; -import { UmbInputDocumentPickerElement } from './input-document-picker.element.js'; +import { UmbInputMediaElement } from './input-media.element.js'; import { defaultA11yConfig } from '@umbraco-cms/internal/test-utils'; -describe('UmbInputDocumentPickerElement', () => { - let element: UmbInputDocumentPickerElement; +describe('UmbInputMediaElement', () => { + let element: UmbInputMediaElement; beforeEach(async () => { - element = await fixture(html` <umb-input-document-picker></umb-input-document-picker> `); + element = await fixture(html` <umb-input-media></umb-input-media> `); }); it('is defined with its own instance', () => { - expect(element).to.be.instanceOf(UmbInputDocumentPickerElement); + expect(element).to.be.instanceOf(UmbInputMediaElement); }); it('passes the a11y audit', async () => { diff --git a/src/Umbraco.Web.UI.Client/src/packages/packages/package-builder/workspace/workspace-package-builder.element.ts b/src/Umbraco.Web.UI.Client/src/packages/packages/package-builder/workspace/workspace-package-builder.element.ts index 2205d81b0e..c17e0a7580 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/packages/package-builder/workspace/workspace-package-builder.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/packages/package-builder/workspace/workspace-package-builder.element.ts @@ -1,5 +1,5 @@ -import type { UmbInputDocumentPickerElement } from '../../../documents/documents/components/input-document-picker/input-document-picker.element.js'; -import type { UmbInputMediaPickerElement } from '../../../media/media/components/input-media-picker/input-media-picker.element.js'; +import type { UmbInputDocumentElement } from '../../../documents/documents/components/input-document/input-document.element.js'; +import type { UmbInputMediaElement } from '../../../media/media/components/input-media/input-media.element.js'; import type { UmbInputLanguagePickerElement } from '../../../settings/languages/components/input-language-picker/input-language-picker.element.js'; import { UUITextStyles, @@ -184,12 +184,12 @@ export class UmbWorkspacePackageBuilderElement extends UmbLitElement { #renderContentSection() { return html` <div slot="editor"> - <umb-input-document-picker + <umb-input-document .value=${this._package.contentNodeId ?? ''} max="1" @change="${(e: CustomEvent) => - (this._package.contentNodeId = (e.target as UmbInputDocumentPickerElement).selectedIds[0])}"> - </umb-input-document-picker> + (this._package.contentNodeId = (e.target as UmbInputDocumentElement).selectedIds[0])}"> + </umb-input-document> <uui-checkbox label="Include child nodes" .checked="${this._package.contentLoadChildNodes ?? false}" @@ -203,10 +203,10 @@ export class UmbWorkspacePackageBuilderElement extends UmbLitElement { #renderMediaSection() { return html` <div slot="editor"> - <umb-input-media-picker + <umb-input-media .selectedIds=${this._package.mediaIds ?? []} @change="${(e: CustomEvent) => - (this._package.mediaIds = (e.target as UmbInputMediaPickerElement).selectedIds)}"></umb-input-media-picker> + (this._package.mediaIds = (e.target as UmbInputMediaElement).selectedIds)}"></umb-input-media> <uui-checkbox label="Include child nodes" .checked="${this._package.mediaLoadChildNodes ?? false}" diff --git a/src/Umbraco.Web.UI.Client/src/packages/settings/logviewer/index.ts b/src/Umbraco.Web.UI.Client/src/packages/settings/logviewer/index.ts new file mode 100644 index 0000000000..3d76f338dd --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/settings/logviewer/index.ts @@ -0,0 +1 @@ +export * from './repository/index.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/settings/logviewer/repository/index.ts b/src/Umbraco.Web.UI.Client/src/packages/settings/logviewer/repository/index.ts new file mode 100644 index 0000000000..4b5d8f967c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/settings/logviewer/repository/index.ts @@ -0,0 +1,2 @@ +export * from './log-viewer.repository.js'; +export * from './sources/index.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/templates/repository/sources/template.detail.server.data.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/templates/repository/sources/template.detail.server.data.ts index 22f25b3496..e49907cae0 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/templates/repository/sources/template.detail.server.data.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/templates/repository/sources/template.detail.server.data.ts @@ -56,8 +56,11 @@ export class UmbTemplateDetailServerDataSource * @return {*} * @memberof UmbTemplateDetailServerDataSource */ - async createScaffold() { - return await tryExecuteAndNotify(this.#host, TemplateResource.getTemplateScaffold()); + async createScaffold(masterTemplateId: string | null) { + return await tryExecuteAndNotify( + this.#host, + TemplateResource.getTemplateScaffold({ masterTemplateId: masterTemplateId ?? undefined }) + ); } /** diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/templates/repository/template.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/templates/repository/template.repository.ts index 6b68cf7219..ca7b933e8d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/templates/repository/template.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/templates/repository/template.repository.ts @@ -138,9 +138,9 @@ export class UmbTemplateRepository //#region DETAILS: - async createScaffold() { + async createScaffold(parentId: string | null) { await this.#init; - return this.#detailDataSource.createScaffold(); + return this.#detailDataSource.createScaffold(parentId); } async requestById(id: string) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/templates/workspace/template-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/templates/workspace/template-workspace.context.ts index 7dc7df9b88..4773a6af8f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/templates/workspace/template-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/templates/workspace/template-workspace.context.ts @@ -129,7 +129,7 @@ export class UmbTemplateWorkspaceContext extends UmbWorkspaceContext<UmbTemplate } async create(parentId: string | null = null) { - const { data } = await this.repository.createScaffold(); + const { data } = await this.repository.createScaffold(parentId); if (!data) return; this.setIsNew(true); this.#data.next({ ...data, id: '', name: '', alias: '', $type: 'TemplateResponseModel' }); diff --git a/src/Umbraco.Web.UI.Client/src/packages/umbraco-news/umbraco-news-dashboard.element.ts b/src/Umbraco.Web.UI.Client/src/packages/umbraco-news/umbraco-news-dashboard.element.ts index 9596b05cf3..ae5609b1fb 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/umbraco-news/umbraco-news-dashboard.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/umbraco-news/umbraco-news-dashboard.element.ts @@ -1,12 +1,40 @@ -import { css, html, LitElement, customElement } from '@umbraco-cms/backoffice/external/lit'; +import { UMB_AUTH } from '@umbraco-cms/backoffice/auth'; +import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit'; +import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; @customElement('umb-umbraco-news-dashboard') -export class UmbUmbracoNewsDashboardElement extends LitElement { +export class UmbUmbracoNewsDashboardElement extends UmbLitElement { + #auth?: typeof UMB_AUTH.TYPE; + + @state() + private name = ''; + + constructor() { + super(); + this.consumeContext(UMB_AUTH, (instance) => { + this.#auth = instance; + this.#observeCurrentUser(); + }); + } + + #observeCurrentUser(): void { + if (!this.#auth) return; + this.observe(this.#auth.currentUser, (user) => { + this.name = user?.name ?? ''; + }); + } + render() { return html` <uui-box> - <h1>Welcome</h1> - <p>You can find details about the POC in the readme.md file.</p> + <h1>Welcome, ${this.name}</h1> + <p>This is a preview version of Umbraco, where you can have a first-hand look at the new Backoffice.</p> + <p>There is currently very limited functionality.</p> + <p> + Please refer to the + <a target="_blank" href="http://docs.umbraco.com/umbraco-backoffice/">documentation</a> to learn more about + what is possible. + </p> </uui-box> `; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/users/current-user/current-user-header-app.element.ts b/src/Umbraco.Web.UI.Client/src/packages/users/current-user/current-user-header-app.element.ts index 44ed9f9c36..860e011f32 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/users/current-user/current-user-header-app.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/users/current-user/current-user-header-app.element.ts @@ -1,5 +1,3 @@ -import type { UmbLoggedInUser } from './types.js'; -import { UmbCurrentUserStore, UMB_CURRENT_USER_STORE_CONTEXT_TOKEN } from './current-user.store.js'; import { UUITextStyles } from '@umbraco-cms/backoffice/external/uui'; import { css, CSSResultGroup, html, customElement, state } from '@umbraco-cms/backoffice/external/lit'; import { @@ -8,13 +6,14 @@ import { UMB_CURRENT_USER_MODAL, } from '@umbraco-cms/backoffice/modal'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; +import { UMB_AUTH, type UmbLoggedInUser } from '@umbraco-cms/backoffice/auth'; @customElement('umb-current-user-header-app') export class UmbCurrentUserHeaderAppElement extends UmbLitElement { @state() private _currentUser?: UmbLoggedInUser; - private _currentUserStore?: UmbCurrentUserStore; + private _auth?: typeof UMB_AUTH.TYPE; private _modalContext?: UmbModalManagerContext; constructor() { @@ -24,16 +23,16 @@ export class UmbCurrentUserHeaderAppElement extends UmbLitElement { this._modalContext = instance; }); - this.consumeContext(UMB_CURRENT_USER_STORE_CONTEXT_TOKEN, (instance) => { - this._currentUserStore = instance; + this.consumeContext(UMB_AUTH, (instance) => { + this._auth = instance; this._observeCurrentUser(); }); } private async _observeCurrentUser() { - if (!this._currentUserStore) return; + if (!this._auth) return; - this.observe(this._currentUserStore.currentUser, (currentUser) => { + this.observe(this._auth.currentUser, (currentUser) => { this._currentUser = currentUser; }); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/users/current-user/current-user.store.ts b/src/Umbraco.Web.UI.Client/src/packages/users/current-user/current-user.store.ts deleted file mode 100644 index d188a75ba4..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/users/current-user/current-user.store.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { UmbLoggedInUser } from './types.js'; -import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; -import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api'; - -export const UMB_CURRENT_USER_STORE_CONTEXT_TOKEN = new UmbContextToken<UmbCurrentUserStore>('UmbCurrentUserStore'); - -export class UmbCurrentUserStore { - #currentUser = new UmbObjectState<UmbLoggedInUser | undefined>(undefined); - public readonly currentUser = this.#currentUser.asObservable(); -} diff --git a/src/Umbraco.Web.UI.Client/src/packages/users/current-user/index.ts b/src/Umbraco.Web.UI.Client/src/packages/users/current-user/index.ts index 30f15ab9c5..0b68da794d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/users/current-user/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/users/current-user/index.ts @@ -1,4 +1,2 @@ -export * from './types.js'; // TODO:Do not export store, but instead export future repository -export * from './current-user.store.js'; export * from './current-user-history.store.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/users/current-user/modals/current-user/current-user-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/users/current-user/modals/current-user/current-user-modal.element.ts index 83e31e00aa..eb2012cd16 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/users/current-user/modals/current-user/current-user-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/users/current-user/modals/current-user/current-user-modal.element.ts @@ -1,6 +1,4 @@ -import { UmbCurrentUserStore, UMB_CURRENT_USER_STORE_CONTEXT_TOKEN } from '../../current-user.store.js'; -import type { UmbLoggedInUser } from '../../types.js'; -import { UMB_AUTH } from '@umbraco-cms/backoffice/auth'; +import { UMB_AUTH, type UmbLoggedInUser } from '@umbraco-cms/backoffice/auth'; import { UMB_APP } from '@umbraco-cms/backoffice/context'; import { UUITextStyles } from '@umbraco-cms/backoffice/external/uui'; import { css, CSSResultGroup, html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit'; @@ -15,8 +13,6 @@ export class UmbCurrentUserModalElement extends UmbLitElement { @state() private _currentUser?: UmbLoggedInUser; - private _currentUserStore?: UmbCurrentUserStore; - #auth?: typeof UMB_AUTH.TYPE; #appContext?: typeof UMB_APP.TYPE; @@ -24,8 +20,8 @@ export class UmbCurrentUserModalElement extends UmbLitElement { constructor() { super(); - this.consumeContext(UMB_CURRENT_USER_STORE_CONTEXT_TOKEN, (instance) => { - this._currentUserStore = instance; + this.consumeContext(UMB_AUTH, (instance) => { + this.#auth = instance; this._observeCurrentUser(); }); @@ -41,9 +37,9 @@ export class UmbCurrentUserModalElement extends UmbLitElement { } private async _observeCurrentUser() { - if (!this._currentUserStore) return; + if (!this.#auth) return; - this.observe(this._currentUserStore.currentUser, (currentUser) => { + this.observe(this.#auth.currentUser, (currentUser) => { this._currentUser = currentUser; }); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/users/current-user/types.ts b/src/Umbraco.Web.UI.Client/src/packages/users/current-user/types.ts deleted file mode 100644 index adfe453bf4..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/users/current-user/types.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { UmbEntityBase } from '@umbraco-cms/backoffice/models'; - -export interface UserEntity extends UmbEntityBase { - type: 'user'; -} - -export type UserStatus = 'enabled' | 'inactive' | 'invited' | 'disabled'; - -export interface UmbLoggedInUser extends UserEntity { - email: string; - status: UserStatus; - language: string; - lastLoginDate?: string; - lastLockoutDate?: string; - lastPasswordChangeDate?: string; - updateDate: string; - createDate: string; - failedLoginAttempts: number; - userGroups: Array<string>; - contentStartNodes: Array<string>; - mediaStartNodes: Array<string>; -} diff --git a/src/Umbraco.Web.UI.Client/src/packages/users/current-user/user-profile-apps/user-profile-app-profile.element.ts b/src/Umbraco.Web.UI.Client/src/packages/users/current-user/user-profile-apps/user-profile-app-profile.element.ts index e449d86358..7bc4c986fc 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/users/current-user/user-profile-apps/user-profile-app-profile.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/users/current-user/user-profile-apps/user-profile-app-profile.element.ts @@ -1,5 +1,3 @@ -import { UmbCurrentUserStore, UMB_CURRENT_USER_STORE_CONTEXT_TOKEN } from '../current-user.store.js'; -import type { UmbLoggedInUser } from '../types.js'; import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit'; import { UUITextStyles } from '@umbraco-cms/backoffice/external/uui'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; @@ -8,6 +6,7 @@ import { UMB_CHANGE_PASSWORD_MODAL, UMB_MODAL_MANAGER_CONTEXT_TOKEN, } from '@umbraco-cms/backoffice/modal'; +import { UMB_AUTH, type UmbLoggedInUser } from '@umbraco-cms/backoffice/auth'; @customElement('umb-user-profile-app-profile') export class UmbUserProfileAppProfileElement extends UmbLitElement { @@ -15,7 +14,7 @@ export class UmbUserProfileAppProfileElement extends UmbLitElement { private _currentUser?: UmbLoggedInUser; private _modalContext?: UmbModalManagerContext; - private _currentUserStore?: UmbCurrentUserStore; + private _auth?: typeof UMB_AUTH.TYPE; constructor() { super(); @@ -24,8 +23,8 @@ export class UmbUserProfileAppProfileElement extends UmbLitElement { this._modalContext = instance; }); - this.consumeContext(UMB_CURRENT_USER_STORE_CONTEXT_TOKEN, (instance) => { - this._currentUserStore = instance; + this.consumeContext(UMB_AUTH, (instance) => { + this._auth = instance; this._observeCurrentUser(); }); @@ -33,9 +32,9 @@ export class UmbUserProfileAppProfileElement extends UmbLitElement { } private async _observeCurrentUser() { - if (!this._currentUserStore) return; + if (!this._auth) return; - this.observe(this._currentUserStore.currentUser, (currentUser) => { + this.observe(this._auth.currentUser, (currentUser) => { this._currentUser = currentUser; }); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/users/index.ts b/src/Umbraco.Web.UI.Client/src/packages/users/index.ts index 2fe1593f81..eb363b6357 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/users/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/users/index.ts @@ -3,7 +3,6 @@ import { manifests as userManifests } from './users/manifests.js'; import { manifests as userSectionManifests } from './user-section/manifests.js'; import { manifests as currentUserManifests } from './current-user/manifests.js'; -import { UmbCurrentUserStore, UMB_CURRENT_USER_STORE_CONTEXT_TOKEN } from './current-user/current-user.store.js'; import { UmbCurrentUserHistoryStore, UMB_CURRENT_USER_HISTORY_STORE_CONTEXT_TOKEN, @@ -21,7 +20,6 @@ export const manifests = [...userGroupManifests, ...userManifests, ...userSectio export const onInit: UmbEntryPointOnInit = (host, extensionRegistry) => { extensionRegistry.registerMany(manifests); - new UmbContextProviderController(host, UMB_CURRENT_USER_STORE_CONTEXT_TOKEN, new UmbCurrentUserStore()); new UmbUserItemStore(host); new UmbUserGroupItemStore(host); new UmbContextProviderController( diff --git a/src/Umbraco.Web.UI.Client/src/packages/users/users/workspace/user-workspace-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/users/users/workspace/user-workspace-editor.element.ts index 1ec1477af1..1fb55ddaac 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/users/users/workspace/user-workspace-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/users/users/workspace/user-workspace-editor.element.ts @@ -1,4 +1,3 @@ -import { UmbCurrentUserStore, UMB_CURRENT_USER_STORE_CONTEXT_TOKEN } from '../../current-user/current-user.store.js'; import { getLookAndColorFromUserStatus } from '../../utils.js'; import { UmbUserRepository } from '../repository/user.repository.js'; import { UmbUserGroupInputElement } from '../../user-groups/components/input-user-group/user-group-input.element.js'; @@ -24,16 +23,17 @@ import { UserResponseModel, UserStateModel } from '@umbraco-cms/backoffice/backe import { createExtensionClass } from '@umbraco-cms/backoffice/extension-api'; import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; import { UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; +import { UMB_AUTH, UmbLoggedInUser } from '@umbraco-cms/backoffice/auth'; @customElement('umb-user-workspace-editor') export class UmbUserWorkspaceEditorElement extends UmbLitElement { @state() - private _currentUser?: any; + private _currentUser?: UmbLoggedInUser; @state() private _user?: UserResponseModel; - #currentUserStore?: UmbCurrentUserStore; + #auth?: typeof UMB_AUTH.TYPE; #modalContext?: UmbModalManagerContext; #languages = []; //TODO Add languages #workspaceContext?: UmbUserWorkspaceContext; @@ -43,8 +43,8 @@ export class UmbUserWorkspaceEditorElement extends UmbLitElement { constructor() { super(); - this.consumeContext(UMB_CURRENT_USER_STORE_CONTEXT_TOKEN, (store) => { - this.#currentUserStore = store; + this.consumeContext(UMB_AUTH, (instance) => { + this.#auth = instance; this.#observeCurrentUser(); }); @@ -76,8 +76,8 @@ export class UmbUserWorkspaceEditorElement extends UmbLitElement { } #observeCurrentUser() { - if (!this.#currentUserStore) return; - this.observe(this.#currentUserStore.currentUser, (currentUser) => (this._currentUser = currentUser)); + if (!this.#auth) return; + this.observe(this.#auth.currentUser, (currentUser) => (this._currentUser = currentUser)); } #onUserStatusChange() { diff --git a/src/Umbraco.Web.UI.Client/src/shared/auth/auth-flow.ts b/src/Umbraco.Web.UI.Client/src/shared/auth/auth-flow.ts index 1820234ff6..251bdea185 100644 --- a/src/Umbraco.Web.UI.Client/src/shared/auth/auth-flow.ts +++ b/src/Umbraco.Web.UI.Client/src/shared/auth/auth-flow.ts @@ -13,7 +13,6 @@ * License for the specific language governing permissions and limitations under * the License. */ -import type { IUmbAuth } from './auth.interface.js'; import { BaseTokenRequestHandler, BasicQueryStringUtils, @@ -81,7 +80,7 @@ class UmbNoHashQueryStringUtils extends BasicQueryStringUtils { * a. This will redirect the user to the authorization endpoint of the server * 4. After login, get the latest token before each request to the server by calling the `performWithFreshTokens` method */ -export class UmbAuthFlow implements IUmbAuth { +export class UmbAuthFlow { // handlers readonly #notifier: AuthorizationNotifier; readonly #authorizationHandler: RedirectRequestHandler; @@ -164,7 +163,6 @@ export class UmbAuthFlow implements IUmbAuth { if (response.isValid()) { this.#accessTokenResponse = response; this.#refreshToken = this.#accessTokenResponse.refreshToken; - return; } } @@ -225,7 +223,7 @@ export class UmbAuthFlow implements IUmbAuth { } /** - * This method will check if the user is logged in by validting the timestamp of the stored token. + * This method will check if the user is logged in by validating the timestamp of the stored token. * If no token is stored, it will return false. * * @returns true if the user is logged in, false otherwise. diff --git a/src/Umbraco.Web.UI.Client/src/shared/auth/auth.context.ts b/src/Umbraco.Web.UI.Client/src/shared/auth/auth.context.ts new file mode 100644 index 0000000000..ce31ca56cc --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/shared/auth/auth.context.ts @@ -0,0 +1,46 @@ +import { IUmbAuth } from './auth.interface.js'; +import { UmbAuthFlow } from './auth-flow.js'; +import { UmbLoggedInUser } from './types.js'; +import { UserResource } from '@umbraco-cms/backoffice/backend-api'; +import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; +import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api'; +import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; +import { ReplaySubject } from '@umbraco-cms/backoffice/external/rxjs'; + +export class UmbAuthContext implements IUmbAuth { + #currentUser = new UmbObjectState<UmbLoggedInUser | undefined>(undefined); + readonly currentUser = this.#currentUser.asObservable(); + readonly isLoggedIn = new ReplaySubject<boolean>(1); + + #host; + #authFlow; + + constructor(host: UmbControllerHostElement, authFlow: UmbAuthFlow) { + this.#host = host; + this.#authFlow = authFlow; + + this.isLoggedIn.subscribe((isLoggedIn) => { + if (isLoggedIn) { + this.fetchCurrentUser(); + } + }); + } + + async fetchCurrentUser(): Promise<UmbLoggedInUser | undefined> { + const { data } = await tryExecuteAndNotify(this.#host, UserResource.getUserCurrent()); + + if (!data) return; + + this.#currentUser.next(data); + + return data; + } + + performWithFreshTokens(): Promise<string> { + return this.#authFlow.performWithFreshTokens(); + } + + signOut(): Promise<void> { + return this.#authFlow.signOut(); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/shared/auth/auth.interface.ts b/src/Umbraco.Web.UI.Client/src/shared/auth/auth.interface.ts index a71be30e2f..6a90a3dc0d 100644 --- a/src/Umbraco.Web.UI.Client/src/shared/auth/auth.interface.ts +++ b/src/Umbraco.Web.UI.Client/src/shared/auth/auth.interface.ts @@ -1,3 +1,6 @@ +import type { UmbLoggedInUser } from './types.js'; +import type { Observable } from '@umbraco-cms/backoffice/external/rxjs'; + export interface IUmbAuth { /** * Get the current user's access token. @@ -10,6 +13,16 @@ export interface IUmbAuth { */ performWithFreshTokens(): Promise<string>; + /** + * Get the current user model of the current user. + */ + get currentUser(): Observable<UmbLoggedInUser | undefined>; + + /** + * Make a server request for the current user and save the state + */ + fetchCurrentUser(): Promise<UmbLoggedInUser | undefined>; + /** * Sign out the current user. */ diff --git a/src/Umbraco.Web.UI.Client/src/shared/auth/auth.token.ts b/src/Umbraco.Web.UI.Client/src/shared/auth/auth.token.ts new file mode 100644 index 0000000000..36a5862575 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/shared/auth/auth.token.ts @@ -0,0 +1,7 @@ +import { IUmbAuth } from './auth.interface.js'; +import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; + +export const UMB_AUTH = new UmbContextToken<IUmbAuth>( + 'UmbAuth', + 'An instance of UmbAuthFlow that should be shared across the app.' +); diff --git a/src/Umbraco.Web.UI.Client/src/shared/auth/index.ts b/src/Umbraco.Web.UI.Client/src/shared/auth/index.ts index 391382b79c..e32f1d152b 100644 --- a/src/Umbraco.Web.UI.Client/src/shared/auth/index.ts +++ b/src/Umbraco.Web.UI.Client/src/shared/auth/index.ts @@ -1,10 +1,6 @@ -import { IUmbAuth } from './auth.interface.js'; -import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; - export type { IUmbAuth } from './auth.interface.js'; export { UmbAuthFlow } from './auth-flow.js'; +export { UmbAuthContext } from './auth.context.js'; -export const UMB_AUTH = new UmbContextToken<IUmbAuth>( - 'UmbAuth', - 'An instance of UmbAuthFlow that should be shared across the app.' -); +export * from './types.js'; +export * from './auth.token.js'; diff --git a/src/Umbraco.Web.UI.Client/src/shared/auth/types.ts b/src/Umbraco.Web.UI.Client/src/shared/auth/types.ts new file mode 100644 index 0000000000..3b481a3c47 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/shared/auth/types.ts @@ -0,0 +1 @@ +export type { CurrentUserResponseModel as UmbLoggedInUser } from '@umbraco-cms/backoffice/backend-api'; diff --git a/src/Umbraco.Web.UI.Client/storybook/stories/extending/property-editors.mdx b/src/Umbraco.Web.UI.Client/storybook/stories/extending/property-editors.mdx index d12816ef8d..a4ce9e22a6 100644 --- a/src/Umbraco.Web.UI.Client/storybook/stories/extending/property-editors.mdx +++ b/src/Umbraco.Web.UI.Client/storybook/stories/extending/property-editors.mdx @@ -36,7 +36,7 @@ import { Meta } from '@storybook/addon-docs'; ```json { - "type": "propertyEditorUI", + "type": "propertyEditorUi", "alias": "Umb.PropertyEditorUi.TextBox", "name": "Text Box Property Editor UI", "elementName": "my-text-box", @@ -64,7 +64,7 @@ If no Property Editor is specified in the manifest, the Propety Editor will use ```json { - "type": "propertyEditorUI", + "type": "propertyEditorUi", "alias": "My.PropertyEditorUI.TextArea", //... more "meta": { @@ -75,7 +75,7 @@ If no Property Editor is specified in the manifest, the Propety Editor will use "alias": "rows", "label": "Number of rows", "description": "If empty - 10 rows would be set as the default value", - "propertyEditorUI": "Umb.PropertyEditorUi.Number", + "propertyEditorUi": "Umb.PropertyEditorUi.Number", }, ], "defaultData": [ diff --git a/src/Umbraco.Web.UI.Client/tsconfig.json b/src/Umbraco.Web.UI.Client/tsconfig.json index 9eb72e5574..92e5cf7661 100644 --- a/src/Umbraco.Web.UI.Client/tsconfig.json +++ b/src/Umbraco.Web.UI.Client/tsconfig.json @@ -81,6 +81,7 @@ "@umbraco-cms/backoffice/data-type": ["./src/packages/settings/data-types/index.ts"], "@umbraco-cms/backoffice/language": ["./src/packages/settings/languages/index.ts"], + "@umbraco-cms/backoffice/logviewer":["./src/packages/settings/logviewer/index.ts"], "@umbraco-cms/backoffice/relation-type": ["./src/packages/settings/relation-types/index.ts"], "@umbraco-cms/backoffice/themes": ["./src/packages/settings/themes/index.ts"], "@umbraco-cms/backoffice/tags": ["./src/packages/tags/index.ts"], 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 0436560e6c..60be185c72 100644 --- a/src/Umbraco.Web.UI.Client/web-test-runner.config.mjs +++ b/src/Umbraco.Web.UI.Client/web-test-runner.config.mjs @@ -96,6 +96,7 @@ export default { '@umbraco-cms/backoffice/data-type': './src/packages/settings/data-types/index.ts', '@umbraco-cms/backoffice/language': './src/packages/settings/languages/index.ts', + '@umbraco-cms/backoffice/logviewer': './src/packages/settings/logviewer/index.ts', '@umbraco-cms/backoffice/relation-type': './src/packages/settings/relation-types/index.ts', '@umbraco-cms/backoffice/themes': './src/packages/settings/themes/index.ts', '@umbraco-cms/backoffice/tags': './src/packages/tags/index.ts',