Merge branch 'main' into feature/media-types-repo
This commit is contained in:
@@ -45,6 +45,12 @@
|
||||
"local-rules/umb-class-prefix": "error",
|
||||
"local-rules/prefer-static-styles-last": "warn",
|
||||
"local-rules/ensure-relative-import-use-js-extension": "error",
|
||||
"local-rules/enforce-umbraco-external-imports": [
|
||||
"error",
|
||||
{
|
||||
"exceptions": ["@umbraco-cms", "@open-wc/testing", "@storybook", "msw", "."]
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
"@typescript-eslint/no-explicit-any": "warn",
|
||||
"@typescript-eslint/no-unused-vars": "warn"
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
name: Azure Static Web Apps CI/CD
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
# pull_request:
|
||||
# types: [opened, synchronize, reopened, closed]
|
||||
# branches:
|
||||
# - main
|
||||
|
||||
env:
|
||||
NODE_OPTIONS: --max_old_space_size=16384
|
||||
|
||||
jobs:
|
||||
build_and_deploy_job:
|
||||
if: false && github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
|
||||
runs-on: ubuntu-latest
|
||||
name: Build and Deploy Job
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Build And Deploy
|
||||
id: builddeploy
|
||||
uses: Azure/static-web-apps-deploy@v1
|
||||
with:
|
||||
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_ASHY_BAY_09F36A803 }}
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments)
|
||||
action: 'upload'
|
||||
###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
|
||||
# For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
|
||||
app_location: '/' # App source code path
|
||||
api_location: 'api' # Api source code path - optional
|
||||
output_location: 'dist-cms' # Built app content directory - optional
|
||||
###### End of Repository/Build Configurations ######
|
||||
|
||||
close_pull_request_job:
|
||||
if: github.event_name == 'pull_request' && github.event.action == 'closed'
|
||||
runs-on: ubuntu-latest
|
||||
name: Close Pull Request Job
|
||||
steps:
|
||||
- name: Close Pull Request
|
||||
id: closepullrequest
|
||||
uses: Azure/static-web-apps-deploy@v1
|
||||
with:
|
||||
app_location: '/'
|
||||
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_ASHY_BAY_09F36A803 }}
|
||||
action: 'close'
|
||||
@@ -5,9 +5,9 @@ name: Build and test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
branches: [main]
|
||||
|
||||
# Allows GitHub to use this workflow to validate the merge queue
|
||||
merge_group:
|
||||
@@ -20,33 +20,32 @@ env:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [18.x]
|
||||
node-version: [20]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: 'npm'
|
||||
- run: npm ci --no-audit --no-fund --prefer-offline
|
||||
- run: npm run lint
|
||||
- run: npm run build
|
||||
- run: npm run generate:jsonschema:dist
|
||||
- run: sudo npx playwright install-deps
|
||||
- run: npm test
|
||||
- name: Upload Code Coverage reports
|
||||
uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: code-coverage
|
||||
path: coverage/
|
||||
retention-days: 30
|
||||
- uses: actions/checkout@v4
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: 'npm'
|
||||
- run: npm ci --no-audit --no-fund --prefer-offline
|
||||
- run: npm run lint
|
||||
- run: npm run build
|
||||
- run: npm run generate:jsonschema:dist
|
||||
- run: sudo npx playwright install-deps
|
||||
- run: npm test
|
||||
- name: Upload Code Coverage reports
|
||||
uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: code-coverage
|
||||
path: coverage/
|
||||
retention-days: 30
|
||||
# Commented out since it is outdated and is quite spammy
|
||||
# - name: Report code coverage
|
||||
# uses: zgosalvez/github-actions-report-lcov@v2
|
||||
|
||||
@@ -47,7 +47,7 @@ jobs:
|
||||
ref: ${{ inputs.ref }}
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
node-version: 20
|
||||
cache: 'npm'
|
||||
registry-url: https://registry.npmjs.org/
|
||||
scope: '@umbraco-cms'
|
||||
|
||||
@@ -1 +1 @@
|
||||
18.16
|
||||
20.9
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#root-inner {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
body {
|
||||
padding: 0px !important;
|
||||
}
|
||||
@@ -23,7 +23,7 @@
|
||||
line-height: 1.3em;
|
||||
}
|
||||
</style>
|
||||
<script src="https://cdn.jsdelivr.net/npm/msw/lib/iife/index.js"></script>
|
||||
<script src="umbraco/backoffice/msw/index.js"></script>
|
||||
<script>
|
||||
(function () {
|
||||
window.addEventListener('load', () => {
|
||||
|
||||
@@ -338,4 +338,52 @@ module.exports = {
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule}*/
|
||||
'enforce-umbraco-external-imports': {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Ensures that the application strictly uses node_modules imports from `@umbraco-cms/backoffice/external`. This is needed to run the application in the browser.',
|
||||
recommended: true,
|
||||
},
|
||||
fixable: 'code',
|
||||
schema: {
|
||||
type: "array",
|
||||
minItems: 0,
|
||||
maxItems: 1,
|
||||
items: [
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
exceptions: { type: "array" }
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
create: (context) => {
|
||||
return {
|
||||
ImportDeclaration: (node) => {
|
||||
const { source } = node;
|
||||
const { value } = source;
|
||||
|
||||
const options = context.options[0] || {};
|
||||
const exceptions = options.exceptions || [];
|
||||
|
||||
// If import starts with any of the following, then it's allowed
|
||||
if (exceptions.some(v => value.startsWith(v))) {
|
||||
return;
|
||||
}
|
||||
|
||||
context.report({
|
||||
node,
|
||||
message: 'node_modules imports should be proxied through `@umbraco-cms/backoffice/external`. Please create it if it does not exist.',
|
||||
fix: (fixer) => fixer.replaceText(source, `'@umbraco-cms/backoffice/external${value.startsWith('/') ? '' : '/'}${value}'`),
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
978
src/Umbraco.Web.UI.Client/package-lock.json
generated
978
src/Umbraco.Web.UI.Client/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -101,7 +101,7 @@
|
||||
"auth:test:e2e": "npx playwright test --config apps/auth/",
|
||||
"backoffice:test:e2e": "npx playwright test",
|
||||
"test:e2e": "npm run auth:test:e2e && npm run backoffice:test:e2e",
|
||||
"lint": "eslint src apps e2e",
|
||||
"lint": "eslint src",
|
||||
"lint:errors": "npm run lint -- --quiet",
|
||||
"lint:fix": "npm run lint -- --fix",
|
||||
"format": "prettier 'src/**/*.ts' -- check",
|
||||
@@ -122,8 +122,8 @@
|
||||
"prepublishOnly": "node ./devops/publish/cleanse-pkg.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.14 <19",
|
||||
"npm": ">=9.5 < 10"
|
||||
"node": ">=20.9 <21",
|
||||
"npm": ">=10.1 < 11"
|
||||
},
|
||||
"dependencies": {
|
||||
"@openid/appauth": "^1.3.1",
|
||||
@@ -148,15 +148,15 @@
|
||||
"@open-wc/testing": "^3.2.0",
|
||||
"@playwright/test": "^1.37.1",
|
||||
"@rollup/plugin-commonjs": "^25.0.4",
|
||||
"@rollup/plugin-json": "^6.0.0",
|
||||
"@rollup/plugin-json": "^6.0.1",
|
||||
"@rollup/plugin-node-resolve": "^15.2.1",
|
||||
"@storybook/addon-a11y": "7.4.5",
|
||||
"@storybook/addon-actions": "7.4.5",
|
||||
"@storybook/addon-essentials": "7.4.5",
|
||||
"@storybook/addon-links": "7.4.5",
|
||||
"@storybook/addon-a11y": "7.5.2",
|
||||
"@storybook/addon-actions": "7.5.2",
|
||||
"@storybook/addon-essentials": "7.5.2",
|
||||
"@storybook/addon-links": "7.5.2",
|
||||
"@storybook/mdx2-csf": "^1.1.0",
|
||||
"@storybook/web-components": "7.4.5",
|
||||
"@storybook/web-components-vite": "7.4.5",
|
||||
"@storybook/web-components": "7.5.2",
|
||||
"@storybook/web-components-vite": "7.5.2",
|
||||
"@types/chai": "^4.3.5",
|
||||
"@types/lodash-es": "^4.17.8",
|
||||
"@types/mocha": "^10.0.1",
|
||||
@@ -171,16 +171,16 @@
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-import-resolver-typescript": "^3.6.0",
|
||||
"eslint-plugin-import": "^2.28.0",
|
||||
"eslint-plugin-lit": "^1.8.3",
|
||||
"eslint-plugin-lit": "^1.10.1",
|
||||
"eslint-plugin-lit-a11y": "^4.1.0",
|
||||
"eslint-plugin-local-rules": "^1.3.2",
|
||||
"eslint-plugin-storybook": "^0.6.14",
|
||||
"eslint-plugin-storybook": "^0.6.15",
|
||||
"eslint-plugin-wc": "^1.5.0",
|
||||
"msw": "^1.2.3",
|
||||
"openapi-typescript-codegen": "^0.25.0",
|
||||
"playwright-msw": "^2.2.1",
|
||||
"plop": "^3.1.2",
|
||||
"prettier": "3.0.1",
|
||||
"prettier": "3.0.3",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"remark-gfm": "^3.0.1",
|
||||
@@ -189,7 +189,7 @@
|
||||
"rollup-plugin-esbuild": "^5.0.0",
|
||||
"rollup-plugin-import-css": "^3.3.4",
|
||||
"rollup-plugin-web-worker-loader": "^1.6.1",
|
||||
"storybook": "7.4.5",
|
||||
"storybook": "7.5.2",
|
||||
"tiny-glob": "^0.2.9",
|
||||
"tsc-alias": "^1.8.7",
|
||||
"typescript": "^5.1.6",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { UmbAppErrorElement } from './app-error.element.js';
|
||||
import { UMB_APP, UmbAppContext } from './app.context.js';
|
||||
import { umbLocalizationRegistry } from '@umbraco-cms/backoffice/localization';
|
||||
import { UMB_AUTH, UmbAuthContext } from '@umbraco-cms/backoffice/auth';
|
||||
import { UMB_AUTH_CONTEXT, UmbAuthContext } from '@umbraco-cms/backoffice/auth';
|
||||
import { css, html, customElement, property } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UUIIconRegistryEssential } from '@umbraco-cms/backoffice/external/uui';
|
||||
import { UmbIconRegistry } from '@umbraco-cms/backoffice/icon';
|
||||
@@ -111,7 +111,7 @@ export class UmbAppElement extends UmbLitElement {
|
||||
|
||||
this.#authContext = new UmbAuthContext(this, this.serverUrl, redirectUrl);
|
||||
|
||||
this.provideContext(UMB_AUTH, this.#authContext);
|
||||
this.provideContext(UMB_AUTH_CONTEXT, this.#authContext);
|
||||
|
||||
this.provideContext(UMB_APP, new UmbAppContext({ backofficePath: this.backofficePath, serverUrl: this.serverUrl }));
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
export * from './app-context-config.interface.js';
|
||||
export * from './app-error.element.js';
|
||||
export * from './app.element.js';
|
||||
export * from './app.context.js';
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint local-rules/enforce-umbraco-external-imports: 0 */
|
||||
import styles from 'monaco-editor/min/vs/editor/editor.main.css';
|
||||
//eslint-disable-next-line
|
||||
import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker.js?worker';
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint local-rules/enforce-umbraco-external-imports: 0 */
|
||||
import DOMPurify from 'dompurify';
|
||||
|
||||
const sanitizeHtml = DOMPurify.sanitize;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint local-rules/enforce-umbraco-external-imports: 0 */
|
||||
/**
|
||||
* TinyMce is a CommonJS module, but in order to make @web/test-runner happy
|
||||
* we need to load it as a module and then manually register it in the browser
|
||||
|
||||
@@ -3,14 +3,8 @@ import type { UmbControllerAlias } from './controller-alias.type.js';
|
||||
import { UmbControllerHostBaseMixin } from './controller-host-base.mixin.js';
|
||||
import type { UmbControllerHost } from './controller-host.interface.js';
|
||||
import type { UmbController } from './controller.interface.js';
|
||||
import type { UmbLocalizeController } from '@umbraco-cms/backoffice/localization-api';
|
||||
|
||||
export declare class UmbControllerHostElement extends HTMLElement implements UmbControllerHost {
|
||||
/**
|
||||
* Use the UmbLocalizeController to localize your element.
|
||||
* @see UmbLocalizeController
|
||||
*/
|
||||
localize: UmbLocalizeController;
|
||||
hasController(controller: UmbController): boolean;
|
||||
getControllers(filterMethod: (ctrl: UmbController) => boolean): UmbController[];
|
||||
addController(controller: UmbController): void;
|
||||
|
||||
@@ -33,6 +33,11 @@ export declare class UmbElement extends UmbControllerHostElement {
|
||||
alias: string | UmbContextToken<BaseType, ResultType>,
|
||||
callback: UmbContextCallback<ResultType>
|
||||
): UmbContextConsumerController<BaseType, ResultType>;
|
||||
/**
|
||||
* Use the UmbLocalizeController to localize your element.
|
||||
* @see UmbLocalizeController
|
||||
*/
|
||||
localize: UmbLocalizeController;
|
||||
}
|
||||
|
||||
export const UmbElementMixin = <T extends HTMLElementConstructor>(superClass: T) => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { expect } from '@open-wc/testing';
|
||||
import { customElement } from 'lit/decorators.js';
|
||||
import { ManifestElement, ManifestElementAndApi } from '../types.js';
|
||||
import { createExtensionElement } from './create-extension-element.function.js';
|
||||
import { customElement } from '@umbraco-cms/backoffice/external/lit';
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import * as manifestsHandlers from './handlers/manifests.handlers.js';
|
||||
import { handlers as publishedStatusHandlers } from './handlers/published-status.handlers.js';
|
||||
import * as serverHandlers from './handlers/server.handlers.js';
|
||||
import { handlers as upgradeHandlers } from './handlers/upgrade.handlers.js';
|
||||
import { handlers as userHandlers } from './handlers/user.handlers.js';
|
||||
import { handlers as userHandlers } from './handlers/user/index.js';
|
||||
import { handlers as telemetryHandlers } from './handlers/telemetry.handlers.js';
|
||||
import { handlers as userGroupsHandlers } from './handlers/user-group/index.js';
|
||||
import { handlers as examineManagementHandlers } from './handlers/examine-management.handlers.js';
|
||||
|
||||
@@ -514,7 +514,7 @@ export const data: Array<DataTypeResponseModel | FolderTreeItemResponseModel> =
|
||||
name: 'Rich Text Editor',
|
||||
id: 'dt-richTextEditor',
|
||||
parentId: null,
|
||||
propertyEditorAlias: 'Umbraco.TinyMCE',
|
||||
propertyEditorAlias: 'Umbraco.RichText',
|
||||
propertyEditorUiAlias: 'Umb.PropertyEditorUi.TinyMCE',
|
||||
values: [
|
||||
{
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import { UmbId } from '@umbraco-cms/backoffice/id';
|
||||
import { UmbEntityData } from './entity.data.js';
|
||||
import { umbUserGroupData } from './user-group.data.js';
|
||||
import { UmbLoggedInUser } from '@umbraco-cms/backoffice/auth';
|
||||
import {
|
||||
CreateUserRequestModel,
|
||||
CreateUserResponseModel,
|
||||
InviteUserRequestModel,
|
||||
UpdateUserGroupsOnUserRequestModel,
|
||||
UserItemResponseModel,
|
||||
UserResponseModel,
|
||||
@@ -21,11 +25,52 @@ class UmbUserData extends UmbEntityData<UserResponseModel> {
|
||||
super(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create user
|
||||
* @param {CreateUserRequestModel} data
|
||||
* @memberof UmbUserData
|
||||
*/
|
||||
createUser = (data: CreateUserRequestModel): CreateUserResponseModel => {
|
||||
const userId = UmbId.new();
|
||||
const initialPassword = 'mocked-initial-password';
|
||||
|
||||
const user: UserResponseModel = {
|
||||
id: userId,
|
||||
languageIsoCode: null,
|
||||
contentStartNodeIds: [],
|
||||
mediaStartNodeIds: [],
|
||||
avatarUrls: [],
|
||||
state: UserStateModel.INACTIVE,
|
||||
failedLoginAttempts: 0,
|
||||
createDate: new Date().toUTCString(),
|
||||
updateDate: new Date().toUTCString(),
|
||||
lastLoginDate: null,
|
||||
lastLockoutDate: null,
|
||||
lastPasswordChangeDate: null,
|
||||
...data,
|
||||
};
|
||||
|
||||
this.insert(user);
|
||||
|
||||
return { userId, initialPassword };
|
||||
};
|
||||
|
||||
/**
|
||||
* Get user items
|
||||
* @param {Array<string>} ids
|
||||
* @return {*} {Array<UserItemResponseModel>}
|
||||
* @memberof UmbUserData
|
||||
*/
|
||||
getItems(ids: Array<string>): Array<UserItemResponseModel> {
|
||||
const items = this.data.filter((item) => ids.includes(item.id ?? ''));
|
||||
return items.map((item) => createUserItem(item));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set user groups
|
||||
* @param {UpdateUserGroupsOnUserRequestModel} data
|
||||
* @memberof UmbUserData
|
||||
*/
|
||||
setUserGroups(data: UpdateUserGroupsOnUserRequestModel): void {
|
||||
const users = this.data.filter((user) => data.userIds?.includes(user.id ?? ''));
|
||||
users.forEach((user) => {
|
||||
@@ -33,6 +78,11 @@ class UmbUserData extends UmbEntityData<UserResponseModel> {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current user
|
||||
* @return {*} {UmbLoggedInUser}
|
||||
* @memberof UmbUserData
|
||||
*/
|
||||
getCurrentUser(): UmbLoggedInUser {
|
||||
const firstUser = this.data[0];
|
||||
const permissions = firstUser.userGroupIds?.length ? umbUserGroupData.getPermissions(firstUser.userGroupIds) : [];
|
||||
@@ -51,6 +101,52 @@ class UmbUserData extends UmbEntityData<UserResponseModel> {
|
||||
permissions,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable users
|
||||
* @param {Array<string>} ids
|
||||
* @memberof UmbUserData
|
||||
*/
|
||||
disable(ids: Array<string>): void {
|
||||
const users = this.data.filter((user) => ids.includes(user.id ?? ''));
|
||||
users.forEach((user) => {
|
||||
user.state = UserStateModel.DISABLED;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable users
|
||||
* @param {Array<string>} ids
|
||||
* @memberof UmbUserData
|
||||
*/
|
||||
enable(ids: Array<string>): void {
|
||||
const users = this.data.filter((user) => ids.includes(user.id ?? ''));
|
||||
users.forEach((user) => {
|
||||
user.state = UserStateModel.ACTIVE;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock users
|
||||
* @param {Array<string>} ids
|
||||
* @memberof UmbUserData
|
||||
*/
|
||||
unlock(ids: Array<string>): void {
|
||||
const users = this.data.filter((user) => ids.includes(user.id ?? ''));
|
||||
users.forEach((user) => {
|
||||
user.failedLoginAttempts = 0;
|
||||
user.state = UserStateModel.ACTIVE;
|
||||
});
|
||||
}
|
||||
|
||||
invite(data: InviteUserRequestModel): void {
|
||||
const invitedUser = {
|
||||
status: UserStateModel.INVITED,
|
||||
...data,
|
||||
};
|
||||
|
||||
this.createUser(invitedUser);
|
||||
}
|
||||
}
|
||||
|
||||
export const data: Array<UserResponseModel & { type: string }> = [
|
||||
@@ -78,17 +174,17 @@ export const data: Array<UserResponseModel & { type: string }> = [
|
||||
{
|
||||
id: '82e11d3d-b91d-43c9-9071-34d28e62e81d',
|
||||
type: 'user',
|
||||
contentStartNodeIds: [],
|
||||
mediaStartNodeIds: [],
|
||||
contentStartNodeIds: ['simple-document-id'],
|
||||
mediaStartNodeIds: ['f2f81a40-c989-4b6b-84e2-057cecd3adc1'],
|
||||
name: 'Amelie Walker',
|
||||
email: 'awalker1@domain.com',
|
||||
languageIsoCode: 'Japanese',
|
||||
state: UserStateModel.INACTIVE,
|
||||
lastLoginDate: '4/12/2023',
|
||||
lastLockoutDate: '',
|
||||
lastPasswordChangeDate: '4/1/2023',
|
||||
updateDate: '4/12/2023',
|
||||
createDate: '4/12/2023',
|
||||
lastLoginDate: '2023-10-12T18:30:32.879Z',
|
||||
lastLockoutDate: null,
|
||||
lastPasswordChangeDate: '2023-10-12T18:30:32.879Z',
|
||||
updateDate: '2023-10-12T18:30:32.879Z',
|
||||
createDate: '2023-10-12T18:30:32.879Z',
|
||||
failedLoginAttempts: 0,
|
||||
userGroupIds: ['c630d49e-4e7b-42ea-b2bc-edc0edacb6b1'],
|
||||
},
|
||||
@@ -101,11 +197,11 @@ export const data: Array<UserResponseModel & { type: string }> = [
|
||||
email: 'okim1@domain.com',
|
||||
languageIsoCode: 'Russian',
|
||||
state: UserStateModel.ACTIVE,
|
||||
lastLoginDate: '4/11/2023',
|
||||
lastLockoutDate: '',
|
||||
lastPasswordChangeDate: '4/5/2023',
|
||||
updateDate: '4/11/2023',
|
||||
createDate: '4/11/2023',
|
||||
lastLoginDate: '2023-10-12T18:30:32.879Z',
|
||||
lastLockoutDate: null,
|
||||
lastPasswordChangeDate: '2023-10-12T18:30:32.879Z',
|
||||
updateDate: '2023-10-12T18:30:32.879Z',
|
||||
createDate: '2023-10-12T18:30:32.879Z',
|
||||
failedLoginAttempts: 0,
|
||||
userGroupIds: ['c630d49e-4e7b-42ea-b2bc-edc0edacb6b1'],
|
||||
},
|
||||
@@ -118,11 +214,11 @@ export const data: Array<UserResponseModel & { type: string }> = [
|
||||
email: 'enieves1@domain.com',
|
||||
languageIsoCode: 'Spanish',
|
||||
state: UserStateModel.INVITED,
|
||||
lastLoginDate: '4/10/2023',
|
||||
lastLockoutDate: '',
|
||||
lastPasswordChangeDate: '4/6/2023',
|
||||
updateDate: '4/10/2023',
|
||||
createDate: '4/10/2023',
|
||||
lastLoginDate: '2023-10-12T18:30:32.879Z',
|
||||
lastLockoutDate: null,
|
||||
lastPasswordChangeDate: null,
|
||||
updateDate: '2023-10-12T18:30:32.879Z',
|
||||
createDate: '2023-10-12T18:30:32.879Z',
|
||||
failedLoginAttempts: 0,
|
||||
userGroupIds: ['c630d49e-4e7b-42ea-b2bc-edc0edacb6b1'],
|
||||
},
|
||||
@@ -134,13 +230,13 @@ export const data: Array<UserResponseModel & { type: string }> = [
|
||||
name: 'Jasmine Patel',
|
||||
email: 'jpatel1@domain.com',
|
||||
languageIsoCode: 'Hindi',
|
||||
state: UserStateModel.DISABLED,
|
||||
lastLoginDate: '4/9/2023',
|
||||
lastLockoutDate: '',
|
||||
lastPasswordChangeDate: '4/7/2023',
|
||||
updateDate: '4/9/2023',
|
||||
createDate: '4/9/2023',
|
||||
failedLoginAttempts: 0,
|
||||
state: UserStateModel.LOCKED_OUT,
|
||||
lastLoginDate: '2023-10-12T18:30:32.879Z',
|
||||
lastLockoutDate: '2023-10-12T18:30:32.879Z',
|
||||
lastPasswordChangeDate: null,
|
||||
updateDate: '2023-10-12T18:30:32.879Z',
|
||||
createDate: '2023-10-12T18:30:32.879Z',
|
||||
failedLoginAttempts: 25,
|
||||
userGroupIds: ['c630d49e-4e7b-42ea-b2bc-edc0edacb6b1'],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -5,7 +5,7 @@ import * as manifestsHandlers from './handlers/manifests.handlers.js';
|
||||
import { handlers as publishedStatusHandlers } from './handlers/published-status.handlers.js';
|
||||
import * as serverHandlers from './handlers/server.handlers.js';
|
||||
import { handlers as upgradeHandlers } from './handlers/upgrade.handlers.js';
|
||||
import { handlers as userHandlers } from './handlers/user.handlers.js';
|
||||
import { handlers as userHandlers } from './handlers/user/index.js';
|
||||
import { handlers as telemetryHandlers } from './handlers/telemetry.handlers.js';
|
||||
import { handlers as examineManagementHandlers } from './handlers/examine-management.handlers.js';
|
||||
import { handlers as modelsBuilderHandlers } from './handlers/modelsbuilder.handlers.js';
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
const { rest } = window.MockServiceWorker;
|
||||
|
||||
import { umbUsersData } from '../data/user.data.js';
|
||||
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
|
||||
|
||||
const slug = '/user';
|
||||
|
||||
export const handlers = [
|
||||
rest.get(umbracoPath(`${slug}/item`), (req, res, ctx) => {
|
||||
const ids = req.url.searchParams.getAll('id');
|
||||
if (!ids) return;
|
||||
const items = umbUsersData.getItems(ids);
|
||||
|
||||
return res(ctx.status(200), ctx.json(items));
|
||||
}),
|
||||
|
||||
rest.post(umbracoPath(`${slug}/set-user-groups`), async (req, res, ctx) => {
|
||||
const data = await req.json();
|
||||
if (!data) return;
|
||||
|
||||
umbUsersData.setUserGroups(data);
|
||||
|
||||
return res(ctx.status(200));
|
||||
}),
|
||||
|
||||
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}/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));
|
||||
}),
|
||||
|
||||
rest.get(umbracoPath(`${slug}/:id`), (req, res, ctx) => {
|
||||
const id = req.params.id as string;
|
||||
if (!id) return;
|
||||
const user = umbUsersData.getById(id);
|
||||
|
||||
if (!user) return res(ctx.status(404));
|
||||
|
||||
return res(ctx.status(200), ctx.json(user));
|
||||
}),
|
||||
|
||||
rest.put(umbracoPath(`${slug}/:id`), async (req, res, ctx) => {
|
||||
const id = req.params.id as string;
|
||||
if (!id) return;
|
||||
const data = await req.json();
|
||||
if (!data) return;
|
||||
|
||||
const saved = umbUsersData.save(id, data);
|
||||
|
||||
return res(ctx.status(200), ctx.json(saved));
|
||||
}),
|
||||
];
|
||||
@@ -0,0 +1,16 @@
|
||||
const { rest } = window.MockServiceWorker;
|
||||
import { slug } from './slug.js';
|
||||
import { ChangePasswordUserRequestModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
|
||||
|
||||
export const handlers = [
|
||||
rest.post<ChangePasswordUserRequestModel>(umbracoPath(`${slug}/change-password/:id`), async (req, res, ctx) => {
|
||||
const data = await req.json();
|
||||
if (!data) return;
|
||||
if (!data.newPassword) return;
|
||||
|
||||
/* we don't have to update any mock data when a password is changed
|
||||
so we just return a 200 */
|
||||
return res(ctx.status(200));
|
||||
}),
|
||||
];
|
||||
@@ -0,0 +1,11 @@
|
||||
const { rest } = window.MockServiceWorker;
|
||||
import { umbUsersData } from '../../data/user.data.js';
|
||||
import { slug } from './slug.js';
|
||||
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
|
||||
|
||||
export const handlers = [
|
||||
rest.get(umbracoPath(`${slug}/current`), (_req, res, ctx) => {
|
||||
const loggedInUser = umbUsersData.getCurrentUser();
|
||||
return res(ctx.status(200), ctx.json(loggedInUser));
|
||||
}),
|
||||
];
|
||||
@@ -0,0 +1,56 @@
|
||||
const { rest } = window.MockServiceWorker;
|
||||
import { umbUsersData } from '../../data/user.data.js';
|
||||
import { slug } from './slug.js';
|
||||
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
|
||||
|
||||
export const handlers = [
|
||||
rest.post(umbracoPath(`${slug}`), async (req, res, ctx) => {
|
||||
const data = await req.json();
|
||||
if (!data) return;
|
||||
|
||||
const response = umbUsersData.createUser(data);
|
||||
|
||||
return res(ctx.status(200), ctx.json(response));
|
||||
}),
|
||||
|
||||
rest.get(umbracoPath(`${slug}`), (req, res, ctx) => {
|
||||
const response = umbUsersData.getAll();
|
||||
return res(ctx.status(200), ctx.json(response));
|
||||
}),
|
||||
|
||||
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}/:id`), (req, res, ctx) => {
|
||||
const id = req.params.id as string;
|
||||
if (!id) return;
|
||||
|
||||
const item = umbUsersData.getById(id);
|
||||
|
||||
return res(ctx.status(200), ctx.json(item));
|
||||
}),
|
||||
|
||||
rest.put(umbracoPath(`${slug}/:id`), async (req, res, ctx) => {
|
||||
const id = req.params.id as string;
|
||||
if (!id) return;
|
||||
const data = await req.json();
|
||||
if (!data) return;
|
||||
|
||||
umbUsersData.save(id, data);
|
||||
|
||||
return res(ctx.status(200));
|
||||
}),
|
||||
|
||||
rest.delete<string>(umbracoPath(`${slug}/:id`), async (req, res, ctx) => {
|
||||
const id = req.params.id as string;
|
||||
if (!id) return;
|
||||
|
||||
umbUsersData.delete([id]);
|
||||
|
||||
return res(ctx.status(200));
|
||||
}),
|
||||
];
|
||||
@@ -0,0 +1,17 @@
|
||||
const { rest } = window.MockServiceWorker;
|
||||
import { umbUsersData } from '../../data/user.data.js';
|
||||
import { slug } from './slug.js';
|
||||
import { DisableUserRequestModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
|
||||
|
||||
export const handlers = [
|
||||
rest.post<DisableUserRequestModel>(umbracoPath(`${slug}/disable`), async (req, res, ctx) => {
|
||||
const data = await req.json();
|
||||
if (!data) return;
|
||||
if (!data.userIds) return;
|
||||
|
||||
umbUsersData.disable(data.userIds);
|
||||
|
||||
return res(ctx.status(200));
|
||||
}),
|
||||
];
|
||||
@@ -0,0 +1,17 @@
|
||||
const { rest } = window.MockServiceWorker;
|
||||
import { umbUsersData } from '../../data/user.data.js';
|
||||
import { slug } from './slug.js';
|
||||
import { EnableUserRequestModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
|
||||
|
||||
export const handlers = [
|
||||
rest.post<EnableUserRequestModel>(umbracoPath(`${slug}/enable`), async (req, res, ctx) => {
|
||||
const data = await req.json();
|
||||
if (!data) return;
|
||||
if (!data.userIds) return;
|
||||
|
||||
umbUsersData.enable(data.userIds);
|
||||
|
||||
return res(ctx.status(200));
|
||||
}),
|
||||
];
|
||||
21
src/Umbraco.Web.UI.Client/src/mocks/handlers/user/index.ts
Normal file
21
src/Umbraco.Web.UI.Client/src/mocks/handlers/user/index.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { handlers as detailHandlers } from './detail.handlers.js';
|
||||
import { handlers as itemHandlers } from './item.handlers.js';
|
||||
import { handlers as currentHandlers } from './current.handlers.js';
|
||||
import { handlers as setUserGroupsHandlers } from './set-user-groups.handlers.js';
|
||||
import { handlers as enableHandlers } from './enable.handlers.js';
|
||||
import { handlers as disableHandlers } from './disable.handlers.js';
|
||||
import { handlers as changePasswordHandlers } from './change-password.handlers.js';
|
||||
import { handlers as unlockHandlers } from './unlock.handlers.js';
|
||||
import { handlers as inviteHandlers } from './invite.handlers.js';
|
||||
|
||||
export const handlers = [
|
||||
...itemHandlers,
|
||||
...currentHandlers,
|
||||
...enableHandlers,
|
||||
...disableHandlers,
|
||||
...setUserGroupsHandlers,
|
||||
...changePasswordHandlers,
|
||||
...unlockHandlers,
|
||||
...detailHandlers,
|
||||
...inviteHandlers,
|
||||
];
|
||||
@@ -0,0 +1,23 @@
|
||||
const { rest } = window.MockServiceWorker;
|
||||
import { umbUsersData } from '../../data/user.data.js';
|
||||
import { slug } from './slug.js';
|
||||
import { InviteUserRequestModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
|
||||
|
||||
export const handlers = [
|
||||
rest.post<InviteUserRequestModel>(umbracoPath(`${slug}/invite`), async (req, res, ctx) => {
|
||||
const data = await req.json();
|
||||
if (!data) return;
|
||||
|
||||
umbUsersData.invite(data);
|
||||
|
||||
return res(ctx.status(200));
|
||||
}),
|
||||
|
||||
rest.post<any>(umbracoPath(`${slug}/invite/resend`), async (req, res, ctx) => {
|
||||
const data = await req.json();
|
||||
if (!data) return;
|
||||
|
||||
return res(ctx.status(200));
|
||||
}),
|
||||
];
|
||||
@@ -0,0 +1,13 @@
|
||||
const { rest } = window.MockServiceWorker;
|
||||
import { umbUsersData } from '../../data/user.data.js';
|
||||
import { slug } from './slug.js';
|
||||
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
|
||||
|
||||
export const handlers = [
|
||||
rest.get(umbracoPath(`${slug}/item`), (req, res, ctx) => {
|
||||
const ids = req.url.searchParams.getAll('id');
|
||||
if (!ids) return;
|
||||
const items = umbUsersData.getItems(ids);
|
||||
return res(ctx.status(200), ctx.json(items));
|
||||
}),
|
||||
];
|
||||
@@ -0,0 +1,15 @@
|
||||
const { rest } = window.MockServiceWorker;
|
||||
import { umbUsersData } from '../../data/user.data.js';
|
||||
import { slug } from './slug.js';
|
||||
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
|
||||
|
||||
export const handlers = [
|
||||
rest.post(umbracoPath(`${slug}/set-user-groups`), async (req, res, ctx) => {
|
||||
const data = await req.json();
|
||||
if (!data) return;
|
||||
|
||||
umbUsersData.setUserGroups(data);
|
||||
|
||||
return res(ctx.status(200));
|
||||
}),
|
||||
];
|
||||
@@ -0,0 +1 @@
|
||||
export const slug = '/user';
|
||||
@@ -0,0 +1,17 @@
|
||||
const { rest } = window.MockServiceWorker;
|
||||
import { umbUsersData } from '../../data/user.data.js';
|
||||
import { slug } from './slug.js';
|
||||
import { UnlockUsersRequestModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
|
||||
|
||||
export const handlers = [
|
||||
rest.post<UnlockUsersRequestModel>(umbracoPath(`${slug}/unlock`), async (req, res, ctx) => {
|
||||
const data = await req.json();
|
||||
if (!data) return;
|
||||
if (!data.userIds) return;
|
||||
|
||||
umbUsersData.unlock(data.userIds);
|
||||
|
||||
return res(ctx.status(200));
|
||||
}),
|
||||
];
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
import { UMB_COLLECTION_CONTEXT } from './collection.context.js';
|
||||
import { UmbBaseController } from '@umbraco-cms/backoffice/controller-api';
|
||||
import {
|
||||
|
||||
@@ -1,22 +1,20 @@
|
||||
import { UmbCollectionRepository } from '@umbraco-cms/backoffice/repository';
|
||||
import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbBaseController, type UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
import {
|
||||
UmbArrayState,
|
||||
UmbNumberState,
|
||||
UmbObjectState,
|
||||
UmbObserverController,
|
||||
} from '@umbraco-cms/backoffice/observable-api';
|
||||
import { createExtensionApi } from '@umbraco-cms/backoffice/extension-api';
|
||||
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import { ManifestCollectionView, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import type { UmbCollectionFilterModel } from '@umbraco-cms/backoffice/collection';
|
||||
import { map } from '@umbraco-cms/backoffice/external/rxjs';
|
||||
import { UmbSelectionManager } from '@umbraco-cms/backoffice/utils';
|
||||
|
||||
// TODO: Clean up the need for store as Media has switched to use Repositories(repository).
|
||||
export class UmbCollectionContext<ItemType, FilterModelType extends UmbCollectionFilterModel> {
|
||||
private _host: UmbControllerHostElement;
|
||||
private _entityType: string;
|
||||
|
||||
protected _dataObserver?: UmbObserverController<ItemType[]>;
|
||||
export class UmbCollectionContext<ItemType, FilterModelType extends UmbCollectionFilterModel> extends UmbBaseController {
|
||||
protected entityType: string;
|
||||
protected init;
|
||||
|
||||
#items = new UmbArrayState<ItemType>([]);
|
||||
public readonly items = this.#items.asObservable();
|
||||
@@ -24,113 +22,125 @@ export class UmbCollectionContext<ItemType, FilterModelType extends UmbCollectio
|
||||
#total = new UmbNumberState(0);
|
||||
public readonly total = this.#total.asObservable();
|
||||
|
||||
#selection = new UmbArrayState<string>([]);
|
||||
public readonly selection = this.#selection.asObservable();
|
||||
#selectionManager = new UmbSelectionManager();
|
||||
public readonly selection = this.#selectionManager.selection;
|
||||
|
||||
#filter = new UmbObjectState<FilterModelType | object>({});
|
||||
public readonly filter = this.#filter.asObservable();
|
||||
|
||||
repository?: UmbCollectionRepository;
|
||||
#views = new UmbArrayState<ManifestCollectionView>([]);
|
||||
public readonly views = this.#views.asObservable();
|
||||
|
||||
/*
|
||||
TODO:
|
||||
private _search = new StringState('');
|
||||
public readonly search = this._search.asObservable();
|
||||
*/
|
||||
#currentView = new UmbObjectState<ManifestCollectionView | undefined>(undefined);
|
||||
public readonly currentView = this.#currentView.asObservable();
|
||||
|
||||
repository?: UmbCollectionRepository;
|
||||
collectionRootPathname: string;
|
||||
|
||||
constructor(host: UmbControllerHostElement, entityType: string, repositoryAlias: string) {
|
||||
this._entityType = entityType;
|
||||
this._host = host;
|
||||
super(host);
|
||||
this.entityType = entityType;
|
||||
|
||||
new UmbObserverController(
|
||||
this._host,
|
||||
umbExtensionsRegistry.getByTypeAndAlias('repository', repositoryAlias),
|
||||
async (repositoryManifest) => {
|
||||
if (repositoryManifest) {
|
||||
const result = await createExtensionApi(repositoryManifest, [this._host]);
|
||||
this.repository = result as UmbCollectionRepository;
|
||||
this._onRepositoryReady();
|
||||
}
|
||||
}
|
||||
);
|
||||
this.#selectionManager.setMultiple(true);
|
||||
|
||||
const currentUrl = new URL(window.location.href);
|
||||
this.collectionRootPathname = currentUrl.pathname.substring(0, currentUrl.pathname.lastIndexOf('/'));
|
||||
|
||||
this.init = Promise.all([
|
||||
this.observe(
|
||||
umbExtensionsRegistry.getByTypeAndAlias('repository', repositoryAlias),
|
||||
async (repositoryManifest) => {
|
||||
if (repositoryManifest) {
|
||||
const result = await createExtensionApi(repositoryManifest, [this._host]);
|
||||
this.repository = result as UmbCollectionRepository;
|
||||
this.requestCollection();
|
||||
}
|
||||
},
|
||||
'umbCollectionRepositoryObserver'
|
||||
).asPromise(),
|
||||
|
||||
this.observe(umbExtensionsRegistry.extensionsOfType('collectionView').pipe(
|
||||
map((extensions) => {
|
||||
return extensions.filter((extension) => extension.conditions.entityType === this.getEntityType());
|
||||
}),
|
||||
),
|
||||
(views) => {
|
||||
this.#views.next(views);
|
||||
this.#setCurrentView();
|
||||
}, 'umbCollectionViewsObserver').asPromise(),
|
||||
]);
|
||||
|
||||
this.provideContext(UMB_COLLECTION_CONTEXT, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given id is selected.
|
||||
* @param {string} id
|
||||
* @return {Boolean}
|
||||
* @memberof UmbCollectionContext
|
||||
*/
|
||||
public isSelected(id: string) {
|
||||
return this.#selection.getValue().includes(id);
|
||||
return this.#selectionManager.isSelected(id);
|
||||
}
|
||||
|
||||
public setSelection(value: Array<string>) {
|
||||
if (!value) return;
|
||||
this.#selection.next(value);
|
||||
/**
|
||||
* Sets the current selection.
|
||||
* @param {Array<string>} selection
|
||||
* @memberof UmbCollectionContext
|
||||
*/
|
||||
public setSelection(selection: Array<string>) {
|
||||
this.#selectionManager.setSelection(selection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current selection.
|
||||
* @return {Array<string>}
|
||||
* @memberof UmbCollectionContext
|
||||
*/
|
||||
public getSelection() {
|
||||
this.#selection.getValue();
|
||||
this.#selectionManager.getSelection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the current selection.
|
||||
* @memberof UmbCollectionContext
|
||||
*/
|
||||
public clearSelection() {
|
||||
this.#selection.next([]);
|
||||
this.#selectionManager.clearSelection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the given id to the current selection.
|
||||
* @param {string} id
|
||||
* @memberof UmbCollectionContext
|
||||
*/
|
||||
public select(id: string) {
|
||||
this.#selection.appendOne(id);
|
||||
this.#selectionManager.select(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given id from the current selection.
|
||||
* @param {string} id
|
||||
* @memberof UmbCollectionContext
|
||||
*/
|
||||
public deselect(id: string) {
|
||||
this.#selection.filter((k) => k !== id);
|
||||
}
|
||||
|
||||
// TODO: how can we make sure to call this.
|
||||
public destroy(): void {
|
||||
this.#items.unsubscribe();
|
||||
this.#selectionManager.deselect(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the collection entity type
|
||||
* @return {string}
|
||||
* @memberof UmbCollectionContext
|
||||
*/
|
||||
public getEntityType() {
|
||||
return this._entityType;
|
||||
}
|
||||
|
||||
/*
|
||||
public getData() {
|
||||
return this.#data.getValue();
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
public update(data: Partial<DataType>) {
|
||||
this._data.next({ ...this.getData(), ...data });
|
||||
}
|
||||
*/
|
||||
|
||||
// protected _onStoreSubscription(): void {
|
||||
// if (!this._store) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// this._dataObserver?.destroy();
|
||||
|
||||
// if (this._entityId) {
|
||||
// this._dataObserver = new UmbObserverController(
|
||||
// this._host,
|
||||
// this._store.getTreeItemChildren(this._entityId),
|
||||
// (nodes) => {
|
||||
// if (nodes) {
|
||||
// this.#data.next(nodes);
|
||||
// }
|
||||
// }
|
||||
// );
|
||||
// } else {
|
||||
// this._dataObserver = new UmbObserverController(this._host, this._store.getTreeRoot(), (nodes) => {
|
||||
// if (nodes) {
|
||||
// this.#data.next(nodes);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
|
||||
protected async _onRepositoryReady() {
|
||||
if (!this.repository) return;
|
||||
this.requestCollection();
|
||||
return this.entityType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests the collection from the repository.
|
||||
* @return {*}
|
||||
* @memberof UmbCollectionContext
|
||||
*/
|
||||
public async requestCollection() {
|
||||
if (!this.repository) return;
|
||||
|
||||
@@ -143,11 +153,48 @@ export class UmbCollectionContext<ItemType, FilterModelType extends UmbCollectio
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: find better name
|
||||
setFilter(filter: Partial<FilterModelType>) {
|
||||
/**
|
||||
* Sets the filter for the collection and refreshes the collection.
|
||||
* @param {Partial<FilterModelType>} filter
|
||||
* @memberof UmbCollectionContext
|
||||
*/
|
||||
public setFilter(filter: Partial<FilterModelType>) {
|
||||
this.#filter.next({ ...this.#filter.getValue(), ...filter });
|
||||
this.requestCollection();
|
||||
}
|
||||
|
||||
// Views
|
||||
/**
|
||||
* Sets the current view.
|
||||
* @param {ManifestCollectionView} view
|
||||
* @memberof UmbCollectionContext
|
||||
*/
|
||||
public setCurrentView(view: ManifestCollectionView) {
|
||||
this.#currentView.next(view);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current view.
|
||||
* @return {ManifestCollectionView}
|
||||
* @memberof UmbCollectionContext
|
||||
*/
|
||||
public getCurrentView() {
|
||||
return this.#currentView.getValue();
|
||||
}
|
||||
|
||||
#setCurrentView() {
|
||||
const currentUrl = new URL(window.location.href);
|
||||
const lastPathSegment = currentUrl.pathname.split('/').pop();
|
||||
const views = this.#views.getValue();
|
||||
const viewMatch = views.find((view) => view.meta.pathName === lastPathSegment);
|
||||
|
||||
/* TODO: Find a way to figure out which layout it starts with and set _currentLayout to that instead of [0]. eg. '/table'
|
||||
For document, media and members this will come as part of a data type configuration, but in other cases "users" we should find another way.
|
||||
This should only happen if the current layout is not set in the URL.
|
||||
*/
|
||||
const currentView = viewMatch || views[0];
|
||||
this.setCurrentView(currentView);
|
||||
}
|
||||
}
|
||||
|
||||
export const UMB_COLLECTION_CONTEXT = new UmbContextToken<UmbCollectionContext<any, any>>('UmbCollectionContext');
|
||||
|
||||
@@ -1,26 +1,16 @@
|
||||
import { UmbTextStyles } from "@umbraco-cms/backoffice/style";
|
||||
import { css, html, nothing, customElement, state, property } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { map } from '@umbraco-cms/backoffice/external/rxjs';
|
||||
import { UmbCollectionContext, UMB_COLLECTION_CONTEXT } from '@umbraco-cms/backoffice/collection';
|
||||
import { UMB_COLLECTION_CONTEXT, UmbCollectionContext } from './collection.context.js';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { css, html, customElement, state, property } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { createExtensionElement } from '@umbraco-cms/backoffice/extension-api';
|
||||
import { ManifestCollectionView, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import { ManifestCollectionView } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
import type { UmbObserverController } from '@umbraco-cms/backoffice/observable-api';
|
||||
import type { UmbRoute } from '@umbraco-cms/backoffice/router';
|
||||
|
||||
import './collection-selection-actions.element.js';
|
||||
import './collection-toolbar.element.js';
|
||||
|
||||
@customElement('umb-collection')
|
||||
export class UmbCollectionElement extends UmbLitElement {
|
||||
@state()
|
||||
private _routes: Array<UmbRoute> = [];
|
||||
|
||||
@state()
|
||||
private _selection?: Array<string> | null;
|
||||
|
||||
private _collectionContext?: UmbCollectionContext<any, any>;
|
||||
|
||||
private _entityType!: string;
|
||||
@property({ type: String, attribute: 'entity-type' })
|
||||
public get entityType(): string {
|
||||
@@ -28,41 +18,24 @@ export class UmbCollectionElement extends UmbLitElement {
|
||||
}
|
||||
public set entityType(value: string) {
|
||||
this._entityType = value;
|
||||
this._observeCollectionViews();
|
||||
}
|
||||
|
||||
private _collectionViewUnsubscribe?: UmbObserverController<Array<ManifestCollectionView>>;
|
||||
protected collectionContext?: UmbCollectionContext<any, any>;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.consumeContext(UMB_COLLECTION_CONTEXT, (instance) => {
|
||||
this._collectionContext = instance;
|
||||
this._observeCollectionContext();
|
||||
this.consumeContext(UMB_COLLECTION_CONTEXT, (context) => {
|
||||
this.collectionContext = context;
|
||||
this.#observeCollectionViews();
|
||||
});
|
||||
}
|
||||
|
||||
private _observeCollectionContext() {
|
||||
if (!this._collectionContext) return;
|
||||
|
||||
this.observe(this._collectionContext.selection, (selection) => {
|
||||
this._selection = selection;
|
||||
});
|
||||
}
|
||||
|
||||
private _observeCollectionViews() {
|
||||
this._collectionViewUnsubscribe?.destroy();
|
||||
this._collectionViewUnsubscribe = this.observe(
|
||||
// TODO: could we make some helper methods for this scenario:
|
||||
umbExtensionsRegistry?.extensionsOfType('collectionView').pipe(
|
||||
map((extensions) => {
|
||||
return extensions.filter((extension) => extension.conditions.entityType === this._entityType);
|
||||
})
|
||||
),
|
||||
(views) => {
|
||||
this._createRoutes(views);
|
||||
}
|
||||
);
|
||||
#observeCollectionViews() {
|
||||
this.observe(this.collectionContext!.views, (views) => {
|
||||
this._createRoutes(views);
|
||||
}),
|
||||
'umbCollectionViewsObserver';
|
||||
}
|
||||
|
||||
private _createRoutes(views: ManifestCollectionView[] | null) {
|
||||
@@ -85,16 +58,22 @@ export class UmbCollectionElement extends UmbLitElement {
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<umb-body-layout>
|
||||
<umb-collection-toolbar slot="header"></umb-collection-toolbar>
|
||||
<umb-body-layout header-transparent>
|
||||
${this.renderToolbar()}
|
||||
<umb-router-slot id="router-slot" .routes="${this._routes}"></umb-router-slot>
|
||||
${this._selection && this._selection.length > 0
|
||||
? html`<umb-collection-selection-actions slot="footer-info"></umb-collection-selection-actions>`
|
||||
: nothing}
|
||||
${this.renderSelectionActions()}
|
||||
</umb-body-layout>
|
||||
`;
|
||||
}
|
||||
|
||||
protected renderToolbar() {
|
||||
return html`<umb-collection-toolbar slot="header"></umb-collection-toolbar>`;
|
||||
}
|
||||
|
||||
protected renderSelectionActions() {
|
||||
return html`<umb-collection-selection-actions slot="footer-info"></umb-collection-selection-actions>`;
|
||||
}
|
||||
|
||||
static styles = [
|
||||
UmbTextStyles,
|
||||
css`
|
||||
|
||||
@@ -15,7 +15,7 @@ export class UmbCollectionSelectionActionsElement extends UmbLitElement {
|
||||
@state()
|
||||
private _extensionProps = {};
|
||||
|
||||
private _selection: Array<string> = [];
|
||||
private _selection: Array<string | null> = [];
|
||||
|
||||
private _collectionContext?: UmbCollectionContext<any, any>;
|
||||
|
||||
@@ -46,7 +46,7 @@ export class UmbCollectionSelectionActionsElement extends UmbLitElement {
|
||||
(mediaItems) => {
|
||||
this._nodesLength = mediaItems.length;
|
||||
},
|
||||
'observeItem',
|
||||
'umbItemsLengthObserver',
|
||||
);
|
||||
|
||||
this.observe(
|
||||
@@ -56,7 +56,7 @@ export class UmbCollectionSelectionActionsElement extends UmbLitElement {
|
||||
this._selection = selection;
|
||||
this._extensionProps = { selection: this._selection };
|
||||
},
|
||||
'observeSelection',
|
||||
'umbSelectionObserver',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { TooltipMenuItem } from '../components/tooltip-menu/index.js';
|
||||
import type { TooltipMenuItem } from '../../components/tooltip-menu/index.js';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { css, html, nothing, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { map } from '@umbraco-cms/backoffice/external/rxjs';
|
||||
@@ -43,46 +43,19 @@ export class UmbCollectionToolbarElement extends UmbLitElement {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._observeCollectionViews();
|
||||
}
|
||||
|
||||
private _observeCollectionViews() {
|
||||
this.observe<ManifestCollectionView[]>(
|
||||
umbExtensionsRegistry.extensionsOfType('collectionView').pipe(
|
||||
map((extensions) => {
|
||||
return extensions.filter((extension) => extension.conditions.entityType === 'media');
|
||||
})
|
||||
),
|
||||
(layouts) => {
|
||||
this._layouts = layouts;
|
||||
|
||||
if (!this._currentLayout) {
|
||||
//TODO: Find a way to figure out which layout it starts with and set _currentLayout to that instead of [0]. eg. '/table'
|
||||
this._currentLayout = layouts[0];
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private _changeLayout(path: string) {
|
||||
history.pushState(null, '', 'section/media/dashboard/media-management/' + path);
|
||||
}
|
||||
|
||||
private _toggleViewType() {
|
||||
if (!this._currentLayout) return;
|
||||
|
||||
const index = this._layouts.indexOf(this._currentLayout);
|
||||
this._currentLayout = this._layouts[(index + 1) % this._layouts.length];
|
||||
this._changeLayout(this._currentLayout.meta.pathName);
|
||||
}
|
||||
|
||||
private _updateSearch(e: InputEvent) {
|
||||
this._search = (e.target as HTMLInputElement).value;
|
||||
|
||||
this.dispatchEvent(
|
||||
new CustomEvent('search', {
|
||||
detail: this._search,
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -104,43 +77,11 @@ export class UmbCollectionToolbarElement extends UmbLitElement {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
private _renderLayoutButton() {
|
||||
if (!this._currentLayout) return;
|
||||
|
||||
if (this._layouts.length < 2 || !this._currentLayout.meta.icon) return nothing;
|
||||
|
||||
if (this._layouts.length === 2) {
|
||||
return html`<uui-button @click=${this._toggleViewType} look="outline" compact>
|
||||
<uui-icon .name=${this._currentLayout.meta.icon}></uui-icon>
|
||||
</uui-button>`;
|
||||
}
|
||||
if (this._layouts.length > 2) {
|
||||
return html`<uui-popover margin="8" .open=${this._viewTypesOpen} @close=${() => (this._viewTypesOpen = false)}>
|
||||
<uui-button @click=${() => (this._viewTypesOpen = !this._viewTypesOpen)} slot="trigger" look="outline" compact>
|
||||
<uui-icon .name=${this._currentLayout.meta.icon}></uui-icon>
|
||||
</uui-button>
|
||||
<umb-tooltip-menu
|
||||
icon-only
|
||||
slot="popover"
|
||||
.items=${this._layouts.map((layout) => ({
|
||||
label: layout.meta.label,
|
||||
icon: layout.meta.icon,
|
||||
action: () => {
|
||||
this._changeLayout(layout.meta.pathName);
|
||||
this._viewTypesOpen = false;
|
||||
},
|
||||
}))}></umb-tooltip-menu>
|
||||
</uui-popover>`;
|
||||
}
|
||||
|
||||
return nothing;
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
${this._renderCreateButton()}
|
||||
<uui-input id="search" @input=${this._updateSearch}></uui-input>
|
||||
${this._renderLayoutButton()}
|
||||
<umb-collection-view-bundle></umb-collection-view-bundle>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
import { UMB_COLLECTION_CONTEXT, UmbCollectionContext } from '../collection.context.js';
|
||||
import { ManifestCollectionView } from '../../extension-registry/models/collection-view.model.js';
|
||||
import { css, html, customElement, state, nothing } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
|
||||
@customElement('umb-collection-view-bundle')
|
||||
export class UmbCollectionViewBundleElement extends UmbLitElement {
|
||||
@state()
|
||||
_views: Array<ManifestCollectionView> = [];
|
||||
|
||||
@state()
|
||||
_currentView?: ManifestCollectionView;
|
||||
|
||||
@state()
|
||||
private _isOpen = false;
|
||||
|
||||
@state()
|
||||
private _collectionRootPathname = '';
|
||||
|
||||
#collectionContext?: UmbCollectionContext<any, any>;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.consumeContext(UMB_COLLECTION_CONTEXT, (context) => {
|
||||
this.#collectionContext = context;
|
||||
if (!this.#collectionContext) return;
|
||||
this._collectionRootPathname = this.#collectionContext.collectionRootPathname;
|
||||
this.#observeViews();
|
||||
this.#observeCurrentView();
|
||||
});
|
||||
}
|
||||
|
||||
#observeCurrentView() {
|
||||
this.observe(this.#collectionContext!.currentView, (view) => {
|
||||
this._currentView = view;
|
||||
}, 'umbCurrentCollectionViewObserver');
|
||||
}
|
||||
|
||||
#observeViews() {
|
||||
this.observe(this.#collectionContext!.views, (views) => {
|
||||
this._views = views;
|
||||
}, 'umbCollectionViewsObserver');
|
||||
}
|
||||
|
||||
#toggleDropdown() {
|
||||
this._isOpen = !this._isOpen;
|
||||
}
|
||||
|
||||
#closeDropdown() {
|
||||
this._isOpen = false;
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`${this.#renderLayoutButton()}`;
|
||||
}
|
||||
|
||||
#renderLayoutButton() {
|
||||
if (!this._currentView) return nothing;
|
||||
|
||||
return html` <umb-dropdown .open="${this._isOpen}" @close=${this.#closeDropdown}>
|
||||
<uui-button slot="trigger" label="status" @click=${this.#toggleDropdown}
|
||||
>${this.#renderItemDisplay(this._currentView)}</uui-button
|
||||
>
|
||||
<div slot="dropdown" class="filter-dropdown">${this._views.map((view) => this.#renderItem(view))}</div>
|
||||
</umb-dropdown>`;
|
||||
}
|
||||
|
||||
#renderItem(view: ManifestCollectionView) {
|
||||
return html`<a href="${this._collectionRootPathname}/${view.meta.pathName}">${this.#renderItemDisplay(view)}</a>`;
|
||||
}
|
||||
|
||||
#renderItemDisplay(view: ManifestCollectionView) {
|
||||
return html`<span class="item"><uui-icon name=${view.meta.icon}></uui-icon> ${view.meta.label}</span>`;
|
||||
}
|
||||
|
||||
static styles = [
|
||||
UmbTextStyles,
|
||||
css`
|
||||
.item {
|
||||
}
|
||||
|
||||
a {
|
||||
display: block;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'umb-collection-view-bundle': UmbCollectionViewBundleElement;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import './collection-selection-actions.element.js';
|
||||
import './collection-toolbar.element.js';
|
||||
import './collection-view-bundle.element.js';
|
||||
|
||||
export * from './collection-selection-actions.element.js';
|
||||
export * from './collection-toolbar.element.js';
|
||||
export * from './collection-view-bundle.element.js';
|
||||
@@ -1,11 +1,9 @@
|
||||
import { css, html, customElement, state, ifDefined } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UMB_COLLECTION_CONTEXT, UmbCollectionContext } from '@umbraco-cms/backoffice/collection';
|
||||
import type { ManifestDashboardCollection } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import type { FolderTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
|
||||
import '../collection.element.js';
|
||||
|
||||
@customElement('umb-dashboard-collection')
|
||||
export class UmbDashboardCollectionElement extends UmbLitElement {
|
||||
// TODO: Use the right type here:
|
||||
@@ -28,7 +26,7 @@ export class UmbDashboardCollectionElement extends UmbLitElement {
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`<umb-collection entity-type=${ifDefined(this._entityType)}></umb-collection>`;
|
||||
return html`<umb-collection></umb-collection>`;
|
||||
}
|
||||
|
||||
static styles = [
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import './collection.element.js';
|
||||
import './components/index.js';
|
||||
|
||||
export * from './collection.element.js';
|
||||
export * from './components/index.js';
|
||||
|
||||
export * from './collection.context.js';
|
||||
export * from './collection-filter-model.interface.js';
|
||||
export * from './collection-selection-actions.element.js';
|
||||
export { type CollectionEntityTypeConditionConfig } from './collection-entity-type.condition.js';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { UmbTextStyles } from "@umbraco-cms/backoffice/style";
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { css, html, nothing, customElement, property } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
|
||||
@@ -10,7 +10,7 @@ export class UmbDropdownElement extends UmbLitElement {
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<uui-popover id="container" .open=${this.open}>
|
||||
<uui-popover id="container" .open=${this.open} @close=${() => (this.open = false)}>
|
||||
<slot name="trigger" slot="trigger"></slot>
|
||||
${this.open ? this.#renderDropdown() : nothing}
|
||||
</uui-popover>
|
||||
|
||||
@@ -48,7 +48,7 @@ export class UmbEntityActionsBundleElement extends UmbLitElement {
|
||||
(actions) => {
|
||||
this._hasActions = actions.length > 0;
|
||||
},
|
||||
'observeEntityAction'
|
||||
'umbEntityActionsObserver'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { availableLanguages } from './input-tiny-mce.languages.js';
|
||||
import { uriAttributeSanitizer } from './input-tiny-mce.sanitizer.js';
|
||||
import { FormControlMixin } from '@umbraco-cms/backoffice/external/uui';
|
||||
import { renderEditor, type tinymce } from '@umbraco-cms/backoffice/external/tinymce';
|
||||
import { UMB_AUTH, UmbLoggedInUser } from '@umbraco-cms/backoffice/auth';
|
||||
import { UMB_AUTH_CONTEXT, UmbLoggedInUser } from '@umbraco-cms/backoffice/auth';
|
||||
import { TinyMcePluginArguments, UmbTinyMcePluginBase } from '@umbraco-cms/backoffice/components';
|
||||
import { ClassConstructor, hasDefaultExport, loadExtension } from '@umbraco-cms/backoffice/extension-api';
|
||||
import { ManifestTinyMcePlugin, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
|
||||
@@ -21,6 +21,8 @@ import { firstValueFrom } from '@umbraco-cms/backoffice/external/rxjs';
|
||||
import { UmbMediaHelper } from '@umbraco-cms/backoffice/utils';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
import { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
|
||||
import { UMB_APP } from '@umbraco-cms/backoffice/app';
|
||||
import { UmbStylesheetRepository } from '@umbraco-cms/backoffice/stylesheet';
|
||||
|
||||
// TODO => integrate macro picker, update stylesheet fetch when backend CLI exists (ref tinymce.service.js in existing backoffice)
|
||||
@customElement('umb-input-tiny-mce')
|
||||
@@ -33,9 +35,11 @@ export class UmbInputTinyMceElement extends FormControlMixin(UmbLitElement) {
|
||||
|
||||
#mediaHelper = new UmbMediaHelper();
|
||||
#currentUser?: UmbLoggedInUser;
|
||||
#auth?: typeof UMB_AUTH.TYPE;
|
||||
#auth?: typeof UMB_AUTH_CONTEXT.TYPE;
|
||||
#plugins: Array<new (args: TinyMcePluginArguments) => UmbTinyMcePluginBase> = [];
|
||||
#editorRef?: tinymce.Editor | null = null;
|
||||
#stylesheetRepository?: UmbStylesheetRepository;
|
||||
#serverUrl?: string;
|
||||
|
||||
protected getFormElement() {
|
||||
return this._editorElement?.querySelector('iframe') ?? undefined;
|
||||
@@ -47,6 +51,12 @@ export class UmbInputTinyMceElement extends FormControlMixin(UmbLitElement) {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.consumeContext(UMB_APP, (instance) => {
|
||||
this.#serverUrl = instance.getServerUrl();
|
||||
});
|
||||
|
||||
this.#stylesheetRepository = new UmbStylesheetRepository(this);
|
||||
|
||||
// TODO => this breaks tests, removing for now will ignore user language
|
||||
// and fall back to tinymce default language
|
||||
// this.consumeContext(UMB_AUTH, (instance) => {
|
||||
@@ -94,6 +104,61 @@ export class UmbInputTinyMceElement extends FormControlMixin(UmbLitElement) {
|
||||
}
|
||||
}
|
||||
|
||||
async getFormatStyles(stylesheetPath: Array<string>) {
|
||||
const rules: any[] = [];
|
||||
|
||||
stylesheetPath.forEach((path) => {
|
||||
//TODO => Legacy path?
|
||||
/**
|
||||
* if (val.indexOf(Umbraco.Sys.ServerVariables.umbracoSettings.cssPath + "/") === 0) {
|
||||
// current format (full path to stylesheet)
|
||||
stylesheets.push(val);
|
||||
}
|
||||
else {
|
||||
// legacy format (stylesheet name only) - must prefix with stylesheet folder and postfix with ".css"
|
||||
stylesheets.push(Umbraco.Sys.ServerVariables.umbracoSettings.cssPath + "/" + val + ".css");
|
||||
}
|
||||
*/
|
||||
this.#stylesheetRepository?.getStylesheetRules(path).then(({ data }) => {
|
||||
data?.rules?.forEach((rule) => {
|
||||
const r: {
|
||||
title?: string;
|
||||
inline?: string;
|
||||
classes?: string;
|
||||
attributes?: Record<string, string>;
|
||||
block?: string;
|
||||
} = {
|
||||
title: rule.name,
|
||||
};
|
||||
|
||||
if (!rule.selector) return;
|
||||
|
||||
if (rule.selector.startsWith('.')) {
|
||||
r.inline = 'span';
|
||||
r.classes = rule.selector.substring(1);
|
||||
} else if (rule.selector.startsWith('#')) {
|
||||
r.inline = 'span';
|
||||
r.attributes = { id: rule.selector.substring(1) };
|
||||
} else if (rule.selector.includes('.')) {
|
||||
const [block, ...classes] = rule.selector.split('.');
|
||||
r.block = block;
|
||||
r.classes = classes.join(' ').replace(/\./g, ' ');
|
||||
} else if (rule.selector.includes('#')) {
|
||||
const [block, id] = rule.selector.split('#');
|
||||
r.block = block;
|
||||
r.classes = id;
|
||||
} else {
|
||||
r.block = rule.selector;
|
||||
}
|
||||
|
||||
rules.push(r);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return rules;
|
||||
}
|
||||
|
||||
async #setTinyConfig() {
|
||||
// create an object by merging the configuration onto the fallback config
|
||||
// TODO: Seems like a too tight coupling between DataTypeConfigCollection and TinyMceConfig, I would love it begin more explicit what we take from DataTypeConfigCollection and parse on, but I understand that this gives some flexibility. Is this flexibility on purpose?
|
||||
@@ -102,6 +167,12 @@ export class UmbInputTinyMceElement extends FormControlMixin(UmbLitElement) {
|
||||
...(this.configuration ? this.configuration?.toObject() : {}),
|
||||
};
|
||||
|
||||
// Map the stylesheets with server url
|
||||
const stylesheets = configurationOptions.stylesheets.map(
|
||||
(stylesheetPath: string) => `${this.#serverUrl}/css/${stylesheetPath.replace(/\\/g, '/')}`,
|
||||
);
|
||||
const styleFormats = await this.getFormatStyles(configurationOptions.stylesheets);
|
||||
|
||||
// no auto resize when a fixed height is set
|
||||
if (!configurationOptions.dimensions?.height) {
|
||||
configurationOptions.plugins ??= [];
|
||||
@@ -129,13 +200,13 @@ export class UmbInputTinyMceElement extends FormControlMixin(UmbLitElement) {
|
||||
// extend with configuration values
|
||||
this._tinyConfig = {
|
||||
...this._tinyConfig,
|
||||
content_css: configurationOptions.stylesheets.join(','),
|
||||
content_css: stylesheets,
|
||||
style_formats: styleFormats || defaultStyleFormats,
|
||||
extended_valid_elements: defaultExtendedValidElements,
|
||||
height: configurationOptions.height ?? 500,
|
||||
invalid_elements: configurationOptions.invalidElements,
|
||||
plugins: configurationOptions.plugins.map((x: any) => x.name),
|
||||
toolbar: configurationOptions.toolbar.join(' '),
|
||||
style_formats: defaultStyleFormats,
|
||||
valid_elements: configurationOptions.validElements,
|
||||
width: configurationOptions.width,
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { UserPermissionConditionConfig } from '@umbraco-cms/backoffice/user-permission';
|
||||
import type { SectionAliasConditionConfig } from './section-alias.condition.js';
|
||||
import type { SwitchConditionConfig } from './switch.condition.js';
|
||||
import type { UserPermissionConditionConfig } from '@umbraco-cms/backoffice/user-permission';
|
||||
import type {
|
||||
WorkspaceAliasConditionConfig,
|
||||
WorkspaceEntityTypeConditionConfig,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Meta, StoryObj } from '@storybook/web-components';
|
||||
import { html } from 'lit';
|
||||
import type { UmbLocalizeElement } from '../localize.element.js';
|
||||
import { html } from '@umbraco-cms/backoffice/external/lit';
|
||||
import '../localize.element.js';
|
||||
|
||||
const meta: Meta<UmbLocalizeElement> = {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { UmbTreeElement } from '../../../tree/tree.element.js';
|
||||
import { css, html, nothing, customElement, query, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { css, html, nothing, customElement, query, state, styleMap } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UUIBooleanInputEvent, UUIInputElement } from '@umbraco-cms/backoffice/external/uui';
|
||||
import {
|
||||
UmbLinkPickerConfig,
|
||||
@@ -36,6 +36,12 @@ export class UmbLinkPickerModalElement extends UmbModalBaseElement<UmbLinkPicker
|
||||
ignoreUserStartNodes: false,
|
||||
};
|
||||
|
||||
@state()
|
||||
documentExpand = false;
|
||||
|
||||
@state()
|
||||
mediaExpanded = false;
|
||||
|
||||
@query('#link-input')
|
||||
private _linkInput!: UUIInputElement;
|
||||
|
||||
@@ -59,9 +65,17 @@ export class UmbLinkPickerModalElement extends UmbModalBaseElement<UmbLinkPicker
|
||||
private _handleQueryString() {
|
||||
if (!this._linkQueryInput) return;
|
||||
const query = this._linkQueryInput.value as string;
|
||||
//TODO: Handle query strings (add # etc)
|
||||
|
||||
this._link.queryString = query;
|
||||
if (query.startsWith('#') || query.startsWith('?')) {
|
||||
this._link.queryString = query;
|
||||
return;
|
||||
}
|
||||
|
||||
if (query.includes('=')) {
|
||||
this._link.queryString = `?${query}`;
|
||||
} else {
|
||||
this._link.queryString = `#${query}`;
|
||||
}
|
||||
}
|
||||
|
||||
private _handleSelectionChange(e: CustomEvent, entityType: string) {
|
||||
@@ -69,13 +83,20 @@ export class UmbLinkPickerModalElement extends UmbModalBaseElement<UmbLinkPicker
|
||||
e.stopPropagation();
|
||||
const element = e.target as UmbTreeElement;
|
||||
const selectedKey = element.selection[element.selection.length - 1];
|
||||
if (!selectedKey) return;
|
||||
|
||||
if (!selectedKey) {
|
||||
this._link.url = '';
|
||||
this._link.udi = undefined;
|
||||
this._selectedKey = undefined;
|
||||
this.requestUpdate();
|
||||
return;
|
||||
}
|
||||
|
||||
const udi = buildUdi(entityType, selectedKey);
|
||||
|
||||
this._selectedKey = selectedKey;
|
||||
this._link.udi = udi;
|
||||
this._link.url = udi; // TODO
|
||||
this._link.url = udi;
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
@@ -93,22 +114,22 @@ export class UmbLinkPickerModalElement extends UmbModalBaseElement<UmbLinkPicker
|
||||
<uui-box>
|
||||
<div class="url-link">${this._renderLinkUrlInput()} ${this._renderAnchorInput()}</div>
|
||||
|
||||
<uui-label for="link-title-input">Link Title</uui-label>
|
||||
<uui-label for="link-title-input">${this.localize.term('defaultdialogs_nodeNameLinkPicker')}</uui-label>
|
||||
<uui-input
|
||||
id="link-title-input"
|
||||
placeholder="Enter a title"
|
||||
label="link title"
|
||||
placeholder=${this.localize.term('defaultdialogs_nodeNameLinkPicker')}
|
||||
label=${this.localize.term('defaultdialogs_nodeNameLinkPicker')}
|
||||
@input=${() => (this._link.name = this._linkTitleInput.value as string)}
|
||||
.value="${this._link.name ?? ''}"></uui-input>
|
||||
|
||||
<uui-label>Target</uui-label>
|
||||
<uui-label>${this.localize.term('content_target')}</uui-label>
|
||||
<uui-toggle
|
||||
id="#target-toggle"
|
||||
label="Toggle if link should open in a new tab"
|
||||
label=${this.localize.term('defaultdialogs_openInNewWindow')}
|
||||
.checked="${this._link.target === '_blank' ? true : false}"
|
||||
@change="${(e: UUIBooleanInputEvent) =>
|
||||
e.target.checked ? (this._link.target = '_blank') : (this._link.target = '')}">
|
||||
Open the link in a new tab
|
||||
${this.localize.term('defaultdialogs_openInNewWindow')}
|
||||
</uui-toggle>
|
||||
|
||||
<hr />
|
||||
@@ -116,8 +137,12 @@ export class UmbLinkPickerModalElement extends UmbModalBaseElement<UmbLinkPicker
|
||||
${this._renderTrees()}
|
||||
</uui-box>
|
||||
<div slot="actions">
|
||||
<uui-button label="Close" @click=${this._close}></uui-button>
|
||||
<uui-button label="Submit" look="primary" color="positive" @click=${this._submit}></uui-button>
|
||||
<uui-button label=${this.localize.term('general_close')} @click=${this._close}></uui-button>
|
||||
<uui-button
|
||||
label=${this.localize.term('general_submit')}
|
||||
look="primary"
|
||||
color="positive"
|
||||
@click=${this._submit}></uui-button>
|
||||
</div>
|
||||
</umb-body-layout>
|
||||
`;
|
||||
@@ -125,50 +150,67 @@ export class UmbLinkPickerModalElement extends UmbModalBaseElement<UmbLinkPicker
|
||||
|
||||
private _renderLinkUrlInput() {
|
||||
return html`<span>
|
||||
<uui-label for="link-input">Link</uui-label>
|
||||
<uui-label for="link-input">${this.localize.term('defaultdialogs_link')}</uui-label>
|
||||
<uui-input
|
||||
id="link-input"
|
||||
placeholder="URL"
|
||||
label="URL"
|
||||
placeholder=${this.localize.term('general_url')}
|
||||
label=${this.localize.term('general_url')}
|
||||
.value="${this._link.udi ?? this._link.url ?? ''}"
|
||||
@input=${() => (this._link.url = this._linkInput.value as string)}
|
||||
.disabled="${this._link.udi ? true : false}"></uui-input>
|
||||
?disabled="${this._link.udi ? true : false}"></uui-input>
|
||||
</span>`;
|
||||
}
|
||||
|
||||
private _renderAnchorInput() {
|
||||
if (this._layout.hideAnchor) return nothing;
|
||||
return html`<span>
|
||||
<uui-label for="anchor-input">Anchor / querystring</uui-label>
|
||||
<uui-label for="anchor-input">${this.localize.term('defaultdialogs_anchorLinkPicker')}</uui-label>
|
||||
<uui-input
|
||||
id="anchor-input"
|
||||
placeholder="#value or ?key=value"
|
||||
label="#value or ?key=value"
|
||||
placeholder=${this.localize.term('placeholders_anchor')}
|
||||
label=${this.localize.term('placeholders_anchor')}
|
||||
@input=${this._handleQueryString}
|
||||
.value="${this._link.queryString ?? ''}"></uui-input>
|
||||
</span>`;
|
||||
}
|
||||
|
||||
private _renderTrees() {
|
||||
return html`<uui-label for="search-input">Link to page</uui-label>
|
||||
<uui-input id="search-input" placeholder="Type to search" label="Type to search"></uui-input>
|
||||
<umb-tree
|
||||
?multiple=${false}
|
||||
alias="Umb.Tree.Documents"
|
||||
@selection-change=${(event: CustomEvent) => this._handleSelectionChange(event, 'document')}
|
||||
.selection=${[this._selectedKey ?? '']}
|
||||
selectable></umb-tree>
|
||||
|
||||
//TODO: Make search work
|
||||
return html`
|
||||
<uui-symbol-expand
|
||||
id="document-expand"
|
||||
@click=${() => (this.documentExpand = !this.documentExpand)}
|
||||
.open=${!this.documentExpand}></uui-symbol-expand>
|
||||
<uui-label for="document-expand">${this.localize.term('defaultdialogs_linkToPage')}</uui-label>
|
||||
<div style="${styleMap({ display: !this.documentExpand ? 'block' : 'none' })}">
|
||||
<uui-input
|
||||
id="search-input"
|
||||
placeholder=${this.localize.term('placeholders_search')}
|
||||
label=${this.localize.term('placeholders_search')}></uui-input>
|
||||
<umb-tree
|
||||
?hide-tree-root=${true}
|
||||
?multiple=${false}
|
||||
alias="Umb.Tree.Documents"
|
||||
@selection-change=${(event: CustomEvent) => this._handleSelectionChange(event, 'document')}
|
||||
.selection=${[this._selectedKey ?? '']}
|
||||
selectable></umb-tree>
|
||||
</div>
|
||||
<hr />
|
||||
|
||||
<uui-label>Link to media</uui-label>
|
||||
|
||||
<umb-tree
|
||||
?multiple=${false}
|
||||
alias="Umb.Tree.Media"
|
||||
@selection-change=${(event: CustomEvent) => this._handleSelectionChange(event, 'media')}
|
||||
.selection=${[this._selectedKey ?? '']}
|
||||
selectable></umb-tree>`;
|
||||
<uui-symbol-expand
|
||||
id="media-expand"
|
||||
@click=${() => (this.mediaExpanded = !this.mediaExpanded)}
|
||||
.open=${!this.mediaExpanded}></uui-symbol-expand>
|
||||
<uui-label for="media-expand">${this.localize.term('defaultdialogs_linkToMedia')}</uui-label>
|
||||
<div style="${styleMap({ display: !this.mediaExpanded ? 'block' : 'none' })}">
|
||||
<umb-tree
|
||||
?hide-tree-root=${true}
|
||||
?multiple=${false}
|
||||
alias="Umb.Tree.Media"
|
||||
@selection-change=${(event: CustomEvent) => this._handleSelectionChange(event, 'media')}
|
||||
.selection=${[this._selectedKey ?? '']}
|
||||
selectable></umb-tree>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
static styles = [
|
||||
@@ -185,7 +227,7 @@ export class UmbLinkPickerModalElement extends UmbModalBaseElement<UmbLinkPicker
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
uui-input,
|
||||
uui-input:not(#search-input),
|
||||
uui-label {
|
||||
margin-bottom: var(--uui-size-space-6);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbSelectionManagerBase } from '@umbraco-cms/backoffice/utils';
|
||||
import { UmbSelectionManager } from '@umbraco-cms/backoffice/utils';
|
||||
import { ManifestSection, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import {
|
||||
UmbSectionPickerModalData,
|
||||
@@ -16,7 +16,7 @@ export class UmbSectionPickerModalElement extends UmbModalBaseElement<
|
||||
@state()
|
||||
private _sections: Array<ManifestSection> = [];
|
||||
|
||||
#selectionManager = new UmbSelectionManagerBase();
|
||||
#selectionManager = new UmbSelectionManager();
|
||||
|
||||
#submit() {
|
||||
this.modalContext?.submit({
|
||||
@@ -38,7 +38,7 @@ export class UmbSectionPickerModalElement extends UmbModalBaseElement<
|
||||
this.observe(
|
||||
umbExtensionsRegistry.extensionsOfType('section'),
|
||||
(sections: Array<ManifestSection>) => (this._sections = sections),
|
||||
);
|
||||
), 'umbSectionsObserver';
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -30,11 +30,15 @@ type OptionalSubmitArgumentIfUndefined<T> = T extends undefined
|
||||
submit: (arg: T) => void;
|
||||
};
|
||||
|
||||
export interface UmbModalRejectReason {
|
||||
type: string;
|
||||
}
|
||||
|
||||
// TODO: consider splitting this into two separate handlers
|
||||
export class UmbModalContextClass<ModalPreset extends object = object, ModalValue = unknown> extends EventTarget {
|
||||
#submitPromise: Promise<ModalValue>;
|
||||
#submitResolver?: (value: ModalValue) => void;
|
||||
#submitRejecter?: () => void;
|
||||
#submitRejecter?: (reason?: UmbModalRejectReason) => void;
|
||||
|
||||
public readonly key: string;
|
||||
public readonly data: ModalPreset;
|
||||
@@ -90,8 +94,8 @@ export class UmbModalContextClass<ModalPreset extends object = object, ModalValu
|
||||
* @public
|
||||
* @memberof UmbModalContext
|
||||
*/
|
||||
public reject() {
|
||||
this.#submitRejecter?.();
|
||||
public reject(reason?: UmbModalRejectReason) {
|
||||
this.#submitRejecter?.(reason);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
|
||||
|
||||
export interface UmbChangePasswordModalData {
|
||||
requireOldPassword: boolean;
|
||||
userId: string;
|
||||
}
|
||||
|
||||
export const UMB_CHANGE_PASSWORD_MODAL = new UmbModalToken<UmbChangePasswordModalData>('Umb.Modal.ChangePassword', {
|
||||
type: 'dialog',
|
||||
});
|
||||
export interface UmbChangePasswordModalValue {
|
||||
oldPassword: string;
|
||||
newPassword: string;
|
||||
}
|
||||
|
||||
export const UMB_CHANGE_PASSWORD_MODAL = new UmbModalToken<UmbChangePasswordModalData, UmbChangePasswordModalValue>(
|
||||
'Umb.Modal.ChangePassword',
|
||||
{
|
||||
type: 'dialog',
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
|
||||
|
||||
export const UMB_CREATE_USER_MODAL = new UmbModalToken('Umb.Modal.CreateUser', {
|
||||
export const UMB_CREATE_USER_MODAL = new UmbModalToken('Umb.Modal.User.Create', {
|
||||
type: 'dialog',
|
||||
size: 'small',
|
||||
});
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
|
||||
|
||||
export interface UmbCreateUserSuccessModalData {
|
||||
userId: string;
|
||||
initialPassword: string;
|
||||
}
|
||||
|
||||
export type UmbCreateUserSuccessModalValue = undefined;
|
||||
|
||||
export const UMB_CREATE_USER_SUCCESS_MODAL = new UmbModalToken<
|
||||
UmbCreateUserSuccessModalData,
|
||||
UmbCreateUserSuccessModalValue
|
||||
>('Umb.Modal.User.CreateSuccess', {
|
||||
type: 'dialog',
|
||||
size: 'small',
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
|
||||
|
||||
export const UMB_CURRENT_USER_MODAL = new UmbModalToken('Umb.Modal.CurrentUser', {
|
||||
export const UMB_CURRENT_USER_MODAL = new UmbModalToken('Umb.Modal.User.Current', {
|
||||
type: 'sidebar',
|
||||
size: 'small',
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@ export * from './code-editor-modal.token.js';
|
||||
export * from './confirm-modal.token.js';
|
||||
export * from './create-dictionary-modal.token.js';
|
||||
export * from './create-user-modal.token.js';
|
||||
export * from './create-user-success-modal.token.js';
|
||||
export * from './current-user-modal.token.js';
|
||||
export * from './debug-modal.token.js';
|
||||
export * from './document-picker-modal.token.js';
|
||||
@@ -35,3 +36,4 @@ export * from './data-type-picker-flow-modal.token.js';
|
||||
export * from './data-type-picker-flow-data-type-picker-modal.token.js';
|
||||
export * from './entity-user-permission-settings-modal.token.js';
|
||||
export * from './permissions-modal.token.js';
|
||||
export * from './resend-invite-to-user-modal.token.js';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
|
||||
|
||||
export const UMB_INVITE_USER_MODAL = new UmbModalToken('Umb.Modal.InviteUser', {
|
||||
export const UMB_INVITE_USER_MODAL = new UmbModalToken('Umb.Modal.User.Invite', {
|
||||
type: 'dialog',
|
||||
size: 'small',
|
||||
});
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
|
||||
|
||||
export type UmbResendInviteToUserModalData = {
|
||||
userId: string;
|
||||
};
|
||||
|
||||
export type UmbResendInviteToUserModalValue = undefined;
|
||||
|
||||
export const UMB_RESEND_INVITE_TO_USER_MODAL = new UmbModalToken<
|
||||
UmbResendInviteToUserModalData,
|
||||
UmbResendInviteToUserModalValue
|
||||
>('Umb.Modal.User.ResendInvite', {
|
||||
type: 'dialog',
|
||||
size: 'small',
|
||||
});
|
||||
@@ -8,7 +8,7 @@ export interface UmbUserPickerModalValue {
|
||||
}
|
||||
|
||||
export const UMB_USER_PICKER_MODAL = new UmbModalToken<UmbUserPickerModalData, UmbUserPickerModalValue>(
|
||||
'Umb.Modal.UserPicker',
|
||||
'Umb.Modal.User.Picker',
|
||||
{
|
||||
type: 'sidebar',
|
||||
size: 'small',
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { ManifestPropertyEditorSchema } from '@umbraco-cms/backoffice/exten
|
||||
export const manifest: ManifestPropertyEditorSchema = {
|
||||
type: 'propertyEditorSchema',
|
||||
name: 'Rich Text',
|
||||
alias: 'Umbraco.TinyMCE',
|
||||
alias: 'Umbraco.RichText',
|
||||
meta: {
|
||||
defaultPropertyEditorUiAlias: 'Umb.PropertyEditorUi.TinyMCE',
|
||||
settings: {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { UmbTextStyles } from "@umbraco-cms/backoffice/style";
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { customElement, html, property } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
|
||||
@@ -11,8 +11,18 @@ export class UmbPropertyEditorUITinyMceDimensionsConfigurationElement extends Um
|
||||
value: { width?: number; height?: number } = {};
|
||||
|
||||
render() {
|
||||
return html`<uui-input type="number" placeholder="Width" .value=${this.value.width}></uui-input> x
|
||||
<uui-input type="number" placeholder="Height" .value=${this.value.height}></uui-input> pixels`;
|
||||
return html`<uui-input
|
||||
type="number"
|
||||
label=${this.localize.term('general_width')}
|
||||
placeholder=${this.localize.term('general_width')}
|
||||
.value=${this.value?.width}></uui-input>
|
||||
x
|
||||
<uui-input
|
||||
type="number"
|
||||
label=${this.localize.term('general_height')}
|
||||
placeholder=${this.localize.term('general_height')}
|
||||
.value=${this.value?.height}></uui-input>
|
||||
pixels`;
|
||||
}
|
||||
|
||||
static styles = [UmbTextStyles];
|
||||
|
||||
@@ -8,7 +8,7 @@ const configurationManifests: Array<ManifestPropertyEditorUi> = [
|
||||
loader: () => import('./toolbar/property-editor-ui-tiny-mce-toolbar-configuration.element.js'),
|
||||
meta: {
|
||||
label: 'TinyMCE Toolbar Configuration',
|
||||
propertyEditorSchemaAlias: 'Umbraco.TinyMCE.Configuration',
|
||||
propertyEditorSchemaAlias: 'Umbraco.RichText.Configuration',
|
||||
icon: 'umb:autofill',
|
||||
group: 'common',
|
||||
},
|
||||
@@ -20,7 +20,7 @@ const configurationManifests: Array<ManifestPropertyEditorUi> = [
|
||||
loader: () => import('./stylesheets/property-editor-ui-tiny-mce-stylesheets-configuration.element.js'),
|
||||
meta: {
|
||||
label: 'TinyMCE Stylesheets Configuration',
|
||||
propertyEditorSchemaAlias: 'Umbraco.TinyMCE.Configuration',
|
||||
propertyEditorSchemaAlias: 'Umbraco.RichText.Configuration',
|
||||
icon: 'umb:autofill',
|
||||
group: 'common',
|
||||
},
|
||||
@@ -32,7 +32,7 @@ const configurationManifests: Array<ManifestPropertyEditorUi> = [
|
||||
loader: () => import('./dimensions/property-editor-ui-tiny-mce-dimensions-configuration.element.js'),
|
||||
meta: {
|
||||
label: 'TinyMCE Dimensions Configuration',
|
||||
propertyEditorSchemaAlias: 'Umbraco.TinyMCE.Configuration',
|
||||
propertyEditorSchemaAlias: 'Umbraco.RichText.Configuration',
|
||||
icon: 'umb:autofill',
|
||||
group: 'common',
|
||||
},
|
||||
@@ -44,7 +44,7 @@ const configurationManifests: Array<ManifestPropertyEditorUi> = [
|
||||
loader: () => import('./max-image-size/property-editor-ui-tiny-mce-maximagesize-configuration.element.js'),
|
||||
meta: {
|
||||
label: 'TinyMCE Max Image Size Configuration',
|
||||
propertyEditorSchemaAlias: 'Umbraco.TinyMCE.Configuration',
|
||||
propertyEditorSchemaAlias: 'Umbraco.RichText.Configuration',
|
||||
icon: 'umb:autofill',
|
||||
group: 'common',
|
||||
},
|
||||
|
||||
@@ -1,21 +1,73 @@
|
||||
import { UmbTextStyles } from "@umbraco-cms/backoffice/style";
|
||||
import { css, customElement, html, property } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { css, customElement, html, property, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
import { UmbStylesheetRepository } from '@umbraco-cms/backoffice/stylesheet';
|
||||
import { StylesheetOverviewResponseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
|
||||
/**
|
||||
* @element umb-property-editor-ui-tiny-mce-stylesheets-configuration
|
||||
*/
|
||||
@customElement('umb-property-editor-ui-tiny-mce-stylesheets-configuration')
|
||||
export class UmbPropertyEditorUITinyMceStylesheetsConfigurationElement extends UmbLitElement {
|
||||
@property()
|
||||
@property({ type: Array })
|
||||
value: string[] = [];
|
||||
|
||||
@property({ type: Array, attribute: false })
|
||||
public config = [];
|
||||
|
||||
@state()
|
||||
stylesheetList: Array<StylesheetOverviewResponseModel & Partial<{ selected: boolean }>> = [];
|
||||
|
||||
#repository;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.#repository = new UmbStylesheetRepository(this);
|
||||
|
||||
this.#getAllStylesheets();
|
||||
}
|
||||
async #getAllStylesheets() {
|
||||
const { data } = await this.#repository.getAll();
|
||||
if (!data) return;
|
||||
|
||||
const styles = data.items;
|
||||
|
||||
this.stylesheetList = styles.map((stylesheet) => ({
|
||||
...stylesheet,
|
||||
selected: this.value?.some((path) => path === stylesheet.path),
|
||||
}));
|
||||
}
|
||||
|
||||
#onChange(event: CustomEvent) {
|
||||
const checkbox = event.target as HTMLInputElement;
|
||||
|
||||
if (checkbox.checked) {
|
||||
if (this.value) {
|
||||
this.value = [...this.value, checkbox.value];
|
||||
} else {
|
||||
this.value = [checkbox.value];
|
||||
}
|
||||
} else {
|
||||
this.value = this.value.filter((v) => v !== checkbox.value);
|
||||
}
|
||||
|
||||
this.dispatchEvent(new CustomEvent('property-value-change'));
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`<ul>
|
||||
${this.value?.map((v) => html`<li><uui-checkbox value=${v}>${v}</uui-checkbox></li>`)}
|
||||
${this.stylesheetList.map(
|
||||
(stylesheet) =>
|
||||
html`<li>
|
||||
<uui-checkbox
|
||||
.label=${stylesheet.name}
|
||||
.value=${stylesheet.path ?? ''}
|
||||
@change=${this.#onChange}
|
||||
?checked=${stylesheet.selected}>
|
||||
${stylesheet.name}
|
||||
</uui-checkbox>
|
||||
</li>`,
|
||||
)}
|
||||
</ul>`;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { UmbTextStyles } from "@umbraco-cms/backoffice/style";
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { customElement, css, html, property, map, state, PropertyValueMap } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
import { UmbPropertyEditorUiElement, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
|
||||
@@ -112,12 +112,13 @@ export class UmbPropertyEditorUITinyMceToolbarConfigurationElement
|
||||
return html`<ul>
|
||||
${map(
|
||||
this._toolbarConfig,
|
||||
(v) => html`<li>
|
||||
<uui-checkbox value=${v.alias} ?checked=${v.selected} @change=${this.onChange}>
|
||||
<uui-icon .svg=${tinyIconSet?.icons[v.icon ?? 'alignjustify']}></uui-icon>
|
||||
${v.label}
|
||||
</uui-checkbox>
|
||||
</li>`
|
||||
(v) =>
|
||||
html`<li>
|
||||
<uui-checkbox label=${v.label} value=${v.alias} ?checked=${v.selected} @change=${this.onChange}>
|
||||
<uui-icon .svg=${tinyIconSet?.icons[v.icon ?? 'alignjustify']}></uui-icon>
|
||||
${v.label}
|
||||
</uui-checkbox>
|
||||
</li>`,
|
||||
)}
|
||||
</ul>`;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ const manifest: ManifestPropertyEditorUi = {
|
||||
loader: () => import('./property-editor-ui-tiny-mce.element.js'),
|
||||
meta: {
|
||||
label: 'Rich Text Editor',
|
||||
propertyEditorSchemaAlias: 'Umbraco.TinyMCE',
|
||||
propertyEditorSchemaAlias: 'Umbraco.RichText',
|
||||
icon: 'umb:browser-window',
|
||||
group: 'richText',
|
||||
settings: {
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
UmbModalManagerContext,
|
||||
UMB_MODAL_MANAGER_CONTEXT_TOKEN,
|
||||
} from '@umbraco-cms/backoffice/modal';
|
||||
import { UMB_AUTH, UmbLoggedInUser } from '@umbraco-cms/backoffice/auth';
|
||||
import { UMB_AUTH_CONTEXT, UmbLoggedInUser } from '@umbraco-cms/backoffice/auth';
|
||||
|
||||
interface MediaPickerTargetData {
|
||||
altText?: string;
|
||||
@@ -28,7 +28,7 @@ export default class UmbTinyMceMediaPickerPlugin extends UmbTinyMcePluginBase {
|
||||
#mediaHelper: UmbMediaHelper;
|
||||
#currentUser?: UmbLoggedInUser;
|
||||
#modalContext?: UmbModalManagerContext;
|
||||
#auth?: typeof UMB_AUTH.TYPE;
|
||||
#auth?: typeof UMB_AUTH_CONTEXT.TYPE;
|
||||
|
||||
constructor(args: TinyMcePluginArguments) {
|
||||
super(args);
|
||||
|
||||
@@ -7,4 +7,4 @@ export * from './item-repository.interface.js';
|
||||
export * from './move-repository.interface.js';
|
||||
export * from './copy-repository.interface.js';
|
||||
export * from './repository-items.manager.js';
|
||||
export * from './repository.interface.js';
|
||||
export * from './repository-base.js';
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import { UmbBaseController, UmbControllerHost } from "@umbraco-cms/backoffice/controller-api";
|
||||
|
||||
export class UmbRepositoryBase extends UmbBaseController {
|
||||
constructor(host: UmbControllerHost) {
|
||||
super(host);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
export interface UmbRepository<EntityType = unknown> {
|
||||
/**
|
||||
* Get the type of the entity
|
||||
*
|
||||
* @public
|
||||
* @type {EntityType}
|
||||
* @returns undefined
|
||||
*/
|
||||
readonly ENTITY_TYPE: EntityType;
|
||||
}
|
||||
@@ -3,6 +3,5 @@ export * from './section-sidebar/index.js';
|
||||
export * from './section-sidebar-context-menu/index.js';
|
||||
export * from './section-sidebar-menu/index.js';
|
||||
export * from './section-sidebar-menu-with-entity-actions/index.js';
|
||||
export * from './section-main-views/index.js';
|
||||
export * from './section-default.element.js';
|
||||
export * from './section.context.js';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Meta, Story } from '@storybook/web-components';
|
||||
import { html } from 'lit';
|
||||
|
||||
import type { UmbSectionSidebarMenuWithEntityActionsElement } from './section-sidebar-menu-with-entity-actions.element.js';
|
||||
import { html } from '@umbraco-cms/backoffice/external/lit';
|
||||
|
||||
import './section-sidebar-menu-with-entity-actions.element.js';
|
||||
|
||||
export default {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Meta, StoryObj } from '@storybook/web-components';
|
||||
import { html } from 'lit';
|
||||
import type UmbTestSorterControllerElement from './test-sorter-controller.element.js';
|
||||
import { html } from '@umbraco-cms/backoffice/external/lit';
|
||||
import './test-sorter-controller.element.js';
|
||||
|
||||
const meta: Meta<UmbTestSorterControllerElement> = {
|
||||
|
||||
@@ -5,7 +5,7 @@ import { UmbBooleanState } from '@umbraco-cms/backoffice/observable-api';
|
||||
import { UmbBaseController, UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { createExtensionApi } from '@umbraco-cms/backoffice/extension-api';
|
||||
import { ProblemDetails, TreeItemPresentationModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import { UmbSelectionManagerBase } from '@umbraco-cms/backoffice/utils';
|
||||
import { UmbSelectionManager } from '@umbraco-cms/backoffice/utils';
|
||||
import { UmbSelectionChangeEvent } from '@umbraco-cms/backoffice/event';
|
||||
|
||||
// TODO: update interface
|
||||
@@ -31,7 +31,7 @@ export class UmbTreeContextBase<TreeItemType extends TreeItemPresentationModel>
|
||||
extends UmbBaseController
|
||||
implements UmbTreeContext<TreeItemType>
|
||||
{
|
||||
#selectionManager = new UmbSelectionManagerBase();
|
||||
#selectionManager = new UmbSelectionManager();
|
||||
|
||||
#selectable = new UmbBooleanState(false);
|
||||
public readonly selectable = this.#selectable.asObservable();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { css, html, customElement, ifDefined } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbTextStyles } from "@umbraco-cms/backoffice/style";
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { UmbCollectionContext, UMB_COLLECTION_CONTEXT } from '@umbraco-cms/backoffice/collection';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
import type { FolderTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
@@ -39,7 +39,7 @@ export class UmbWorkspaceViewCollectionElement extends UmbLitElement {
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`<umb-collection entity-type=${ifDefined(this._workspaceContext?.getEntityType())}></umb-collection>`;
|
||||
return html`<umb-collection></umb-collection>`;
|
||||
}
|
||||
|
||||
static styles = [
|
||||
|
||||
@@ -48,7 +48,7 @@ export class UmbDocumentTableCollectionViewElement extends UmbLitElement {
|
||||
private _tableItems: Array<UmbTableItem> = [];
|
||||
|
||||
@state()
|
||||
private _selection: Array<string> = [];
|
||||
private _selection: Array<string | null> = [];
|
||||
|
||||
private _collectionContext?: UmbCollectionContext<EntityType, any>;
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { t } from 'msw/lib/glossary-de6278a9.js';
|
||||
import { UmbDocumentPermissionServerDataSource } from './document-permission.server.data.js';
|
||||
import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ export class UmbMediaGridCollectionViewElement extends UmbLitElement {
|
||||
private _mediaItems?: Array<EntityTreeItemResponseModel>;
|
||||
|
||||
@state()
|
||||
private _selection: Array<string> = [];
|
||||
private _selection: Array<string | null> = [];
|
||||
|
||||
private _collectionContext?: UmbCollectionContext<EntityTreeItemResponseModel, any>;
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ export class UmbMediaTableCollectionViewElement extends UmbLitElement {
|
||||
private _tableItems: Array<UmbTableItem> = [];
|
||||
|
||||
@state()
|
||||
private _selection: Array<string> = [];
|
||||
private _selection: Array<string | null> = [];
|
||||
|
||||
private _collectionContext?: UmbCollectionContext<MediaDetails, any>;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ContentTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
|
||||
export * from './components/index.js';
|
||||
export * from './repository/index.js';
|
||||
|
||||
// Content
|
||||
export interface ContentProperty {
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export * from './media.repository.js';
|
||||
@@ -2,7 +2,7 @@ import { UmbLanguageRepository } from '../../repository/language.repository.js';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { css, html, customElement, state, repeat } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { LanguageResponseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import { UmbSelectionManagerBase } from '@umbraco-cms/backoffice/utils';
|
||||
import { UmbSelectionManager } from '@umbraco-cms/backoffice/utils';
|
||||
import {
|
||||
UmbLanguagePickerModalValue,
|
||||
UmbLanguagePickerModalData,
|
||||
@@ -18,7 +18,7 @@ export class UmbLanguagePickerModalElement extends UmbModalBaseElement<
|
||||
private _languages: Array<LanguageResponseModel> = [];
|
||||
|
||||
#languageRepository = new UmbLanguageRepository(this);
|
||||
#selectionManager = new UmbSelectionManagerBase();
|
||||
#selectionManager = new UmbSelectionManager();
|
||||
|
||||
connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { TagResource } from '@umbraco-cms/backoffice/backend-api';
|
||||
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import _ from 'lodash';
|
||||
import { UmbScriptsWorkspaceContext } from './scripts-workspace.context.js';
|
||||
import type { UmbCodeEditorElement } from '@umbraco-cms/backoffice/code-editor';
|
||||
import { UUITextStyles, UUIInputElement } from '@umbraco-cms/backoffice/external/uui';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { UmbScriptsWorkspaceContext } from './scripts-workspace.context.js';
|
||||
import { UUITextStyles } from '@umbraco-cms/backoffice/external/uui';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
import { UmbRoute, IRoutingInfo, PageComponent } from '@umbraco-cms/backoffice/router';
|
||||
@@ -40,7 +40,7 @@ export class UmbScriptsWorkspaceElement extends UmbLitElement {
|
||||
return html`<umb-router-slot .routes=${this._routes}></umb-router-slot>`;
|
||||
}
|
||||
|
||||
static styles = [UUITextStyles, css``];
|
||||
static styles = [UmbTextStyles, css``];
|
||||
}
|
||||
|
||||
export default UmbScriptsWorkspaceElement;
|
||||
|
||||
@@ -46,6 +46,16 @@ export class UmbStylesheetServerDataSource
|
||||
if (!path) throw new Error('Path is missing');
|
||||
return tryExecuteAndNotify(this.#host, StylesheetResource.getStylesheet({ path }));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches all stylesheets from the server
|
||||
* @return {*}
|
||||
* @memberof UmbStylesheetServerDataSource
|
||||
*/
|
||||
async getAll(skip: number = 0, take: number = 9999) {
|
||||
return tryExecuteAndNotify(this.#host, StylesheetResource.getStylesheetAll({ skip, take }));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Stylesheet
|
||||
*
|
||||
@@ -85,7 +95,7 @@ export class UmbStylesheetServerDataSource
|
||||
* @memberof UmbStylesheetServerDataSource
|
||||
*/
|
||||
getStylesheetRichTextRules(
|
||||
path: string
|
||||
path: string,
|
||||
): Promise<DataSourceResponse<RichTextStylesheetRulesResponseModel | ExtractRichTextStylesheetRulesResponseModel>> {
|
||||
return tryExecuteAndNotify(this.#host, StylesheetResource.getStylesheetRichTextRules({ path }));
|
||||
}
|
||||
@@ -97,11 +107,11 @@ export class UmbStylesheetServerDataSource
|
||||
* @memberof UmbStylesheetServerDataSource
|
||||
*/
|
||||
postStylesheetRichTextExtractRules(
|
||||
data: ExtractRichTextStylesheetRulesRequestModel
|
||||
data: ExtractRichTextStylesheetRulesRequestModel,
|
||||
): Promise<DataSourceResponse<ExtractRichTextStylesheetRulesResponseModel>> {
|
||||
return tryExecuteAndNotify(
|
||||
this.#host,
|
||||
StylesheetResource.postStylesheetRichTextExtractRules({ requestBody: data })
|
||||
StylesheetResource.postStylesheetRichTextExtractRules({ requestBody: data }),
|
||||
);
|
||||
}
|
||||
/**
|
||||
@@ -112,11 +122,11 @@ export class UmbStylesheetServerDataSource
|
||||
* @memberof UmbStylesheetServerDataSource
|
||||
*/
|
||||
postStylesheetRichTextInterpolateRules(
|
||||
data: InterpolateRichTextStylesheetRequestModel
|
||||
data: InterpolateRichTextStylesheetRequestModel,
|
||||
): Promise<DataSourceResponse<InterpolateRichTextStylesheetResponseModel>> {
|
||||
return tryExecuteAndNotify(
|
||||
this.#host,
|
||||
StylesheetResource.postStylesheetRichTextInterpolateRules({ requestBody: data })
|
||||
StylesheetResource.postStylesheetRichTextInterpolateRules({ requestBody: data }),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { Observable } from 'rxjs';
|
||||
import { StylesheetDetails } from '../index.js';
|
||||
import { UmbStylesheetTreeStore, UMB_STYLESHEET_TREE_STORE_CONTEXT_TOKEN } from './stylesheet.tree.store.js';
|
||||
import { UmbStylesheetTreeServerDataSource } from './sources/stylesheet.tree.server.data.js';
|
||||
@@ -7,6 +6,7 @@ import {
|
||||
StylesheetGetFolderResponse,
|
||||
UmbStylesheetFolderServerDataSource,
|
||||
} from './sources/stylesheet.folder.server.data.js';
|
||||
import type { Observable } from '@umbraco-cms/backoffice/external/rxjs';
|
||||
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api';
|
||||
import {
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
FolderResponseModel,
|
||||
InterpolateRichTextStylesheetRequestModel,
|
||||
InterpolateRichTextStylesheetResponseModel,
|
||||
PagedStylesheetOverviewResponseModel,
|
||||
ProblemDetails,
|
||||
RichTextStylesheetRulesResponseModel,
|
||||
TextFileResponseModelBaseModel,
|
||||
@@ -143,6 +144,10 @@ export class UmbStylesheetRepository
|
||||
return promise;
|
||||
}
|
||||
|
||||
async getAll(skip?: number, take?: number): Promise<DataSourceResponse<PagedStylesheetOverviewResponseModel>> {
|
||||
return this.#dataSource.getAll(skip, take);
|
||||
}
|
||||
|
||||
getStylesheetRules(
|
||||
path: string,
|
||||
): Promise<DataSourceResponse<RichTextStylesheetRulesResponseModel | ExtractRichTextStylesheetRulesResponseModel>> {
|
||||
|
||||
@@ -2,14 +2,22 @@ import { UmbStylesheetRepository } from '../repository/stylesheet.repository.js'
|
||||
import { StylesheetDetails } from '../index.js';
|
||||
import { UmbSaveableWorkspaceContextInterface, UmbWorkspaceContext } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbArrayState, UmbBooleanState, UmbObjectState, createObservablePart } from '@umbraco-cms/backoffice/observable-api';
|
||||
import {
|
||||
UmbArrayState,
|
||||
UmbBooleanState,
|
||||
UmbObjectState,
|
||||
createObservablePart,
|
||||
} from '@umbraco-cms/backoffice/observable-api';
|
||||
import { loadCodeEditor } from '@umbraco-cms/backoffice/code-editor';
|
||||
import { RichTextRuleModel, UpdateStylesheetRequestModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
|
||||
export type RichTextRuleModelSortable = RichTextRuleModel & { sortOrder?: number };
|
||||
|
||||
export class UmbStylesheetWorkspaceContext extends UmbWorkspaceContext<UmbStylesheetRepository, StylesheetDetails> implements UmbSaveableWorkspaceContextInterface {
|
||||
export class UmbStylesheetWorkspaceContext
|
||||
extends UmbWorkspaceContext<UmbStylesheetRepository, StylesheetDetails>
|
||||
implements UmbSaveableWorkspaceContextInterface
|
||||
{
|
||||
#data = new UmbObjectState<StylesheetDetails | undefined>(undefined);
|
||||
#rules = new UmbArrayState<RichTextRuleModelSortable>([], (rule) => rule.name);
|
||||
data = this.#data.asObservable();
|
||||
@@ -55,7 +63,6 @@ export class UmbStylesheetWorkspaceContext extends UmbWorkspaceContext<UmbStyles
|
||||
updateRule(unique: string, rule: RichTextRuleModelSortable) {
|
||||
this.#rules.updateOne(unique, rule);
|
||||
this.sendRulesGetContent();
|
||||
|
||||
}
|
||||
|
||||
setRules(rules: RichTextRuleModelSortable[]) {
|
||||
@@ -103,7 +110,6 @@ export class UmbStylesheetWorkspaceContext extends UmbWorkspaceContext<UmbStyles
|
||||
}
|
||||
|
||||
async sendContentGetRules() {
|
||||
|
||||
if (!this.getData()?.content) return;
|
||||
|
||||
const requestBody = {
|
||||
@@ -135,7 +141,7 @@ export class UmbStylesheetWorkspaceContext extends UmbWorkspaceContext<UmbStyles
|
||||
const createRequestBody = {
|
||||
name: stylesheet.name,
|
||||
content: stylesheet.content,
|
||||
parentPath: stylesheet.path === 'null' ? '' : stylesheet.path + '/',
|
||||
parentPath: stylesheet.path ?? '',
|
||||
};
|
||||
|
||||
this.repository.create(createRequestBody);
|
||||
@@ -166,7 +172,10 @@ export class UmbStylesheetWorkspaceContext extends UmbWorkspaceContext<UmbStyles
|
||||
}
|
||||
}
|
||||
|
||||
export const UMB_STYLESHEET_WORKSPACE_CONTEXT = new UmbContextToken<UmbSaveableWorkspaceContextInterface, UmbStylesheetWorkspaceContext>(
|
||||
export const UMB_STYLESHEET_WORKSPACE_CONTEXT = new UmbContextToken<
|
||||
UmbSaveableWorkspaceContextInterface,
|
||||
UmbStylesheetWorkspaceContext
|
||||
>(
|
||||
'UmbWorkspaceContext',
|
||||
(context): context is UmbStylesheetWorkspaceContext => context.getEntityType?.() === 'stylesheet'
|
||||
(context): context is UmbStylesheetWorkspaceContext => context.getEntityType?.() === 'stylesheet',
|
||||
);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { serverFilePathFromUrlFriendlyPath } from '../../utils.js';
|
||||
import { UmbStylesheetWorkspaceEditorElement } from './stylesheet-workspace-editor.element.js';
|
||||
import { UmbStylesheetWorkspaceContext } from './stylesheet-workspace.context.js';
|
||||
import { UmbTextStyles } from "@umbraco-cms/backoffice/style";
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import type { UmbRoute } from '@umbraco-cms/backoffice/router';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
@@ -10,7 +9,6 @@ import { UmbWorkspaceIsNewRedirectController } from '@umbraco-cms/backoffice/wor
|
||||
@customElement('umb-stylesheet-workspace')
|
||||
export class UmbStylesheetWorkspaceElement extends UmbLitElement {
|
||||
#workspaceContext = new UmbStylesheetWorkspaceContext(this);
|
||||
#element = new UmbStylesheetWorkspaceEditorElement();
|
||||
|
||||
@state()
|
||||
_routes: UmbRoute[] = [
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { UUITextStyles } from '@umbraco-ui/uui-css';
|
||||
import { css, html } from 'lit';
|
||||
import { customElement, state } from 'lit/decorators.js';
|
||||
import { UMB_STYLESHEET_WORKSPACE_CONTEXT, UmbStylesheetWorkspaceContext } from '../../stylesheet-workspace.context.js';
|
||||
import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
import { UmbCodeEditorElement } from '@umbraco-cms/backoffice/code-editor';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
|
||||
@customElement('umb-stylesheet-workspace-view-code-editor')
|
||||
export class UmbStylesheetWorkspaceViewCodeEditorElement extends UmbLitElement {
|
||||
@@ -62,7 +61,7 @@ export class UmbStylesheetWorkspaceViewCodeEditorElement extends UmbLitElement {
|
||||
}
|
||||
|
||||
static styles = [
|
||||
UUITextStyles,
|
||||
UmbTextStyles,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { UmbStylesheetWorkspaceContext } from '../../stylesheet-workspace.context.js';
|
||||
import { UMB_MODAL_TEMPLATING_STYLESHEET_RTF_STYLE_SIDEBAR_MODAL } from './stylesheet-workspace-view-rich-text-editor.element.js';
|
||||
import { UUITextStyles } from '@umbraco-cms/backoffice/external/uui';
|
||||
import { css, html, customElement, property } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { RichTextRuleModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
import { UMB_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UMB_MODAL_MANAGER_CONTEXT_TOKEN, UmbModalManagerContext } from '@umbraco-cms/backoffice/modal';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
|
||||
@customElement('umb-stylesheet-rich-text-editor-rule')
|
||||
export default class UmbStylesheetRichTextEditorRuleElement extends UmbLitElement {
|
||||
@@ -56,7 +56,7 @@ export default class UmbStylesheetRichTextEditorRuleElement extends UmbLitElemen
|
||||
}
|
||||
|
||||
static styles = [
|
||||
UUITextStyles,
|
||||
UmbTextStyles,
|
||||
css`
|
||||
:host {
|
||||
display: flex;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { RichTextRuleModelSortable } from '../../stylesheet-workspace.context.js';
|
||||
import { UUITextStyles } from '@umbraco-cms/backoffice/external/uui';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { css, html, customElement, ifDefined, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
|
||||
import { RichTextRuleModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
@@ -128,7 +128,7 @@ export default class UmbStylesheetRichTextEditorStyleModalElement extends UmbMod
|
||||
}
|
||||
|
||||
static styles = [
|
||||
UUITextStyles,
|
||||
UmbTextStyles,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
import { UUITextStyles } from '@umbraco-ui/uui-css';
|
||||
import { css, html } from 'lit';
|
||||
import { customElement, state } from 'lit/decorators.js';
|
||||
import { RichTextRuleModelSortable, UmbStylesheetWorkspaceContext } from '../../stylesheet-workspace.context.js';
|
||||
import { UMB_MODAL_TEMPLATING_STYLESHEET_RTF_STYLE_SIDEBAR } from '../../manifests.js';
|
||||
import {
|
||||
StylesheetRichTextEditorStyleModalData,
|
||||
UmbStylesheetRichTextEditorStyleModalValue,
|
||||
} from './stylesheet-workspace-view-rich-text-editor-style-sidebar.element.js';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
import { UMB_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UMB_MODAL_MANAGER_CONTEXT_TOKEN, UmbModalManagerContext, UmbModalToken } from '@umbraco-cms/backoffice/modal';
|
||||
import { RichTextRuleModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import { UmbSorterConfig, UmbSorterController } from '@umbraco-cms/backoffice/sorter';
|
||||
import { ifDefined, repeat } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { css, html, customElement, state, ifDefined, repeat } from '@umbraco-cms/backoffice/external/lit';
|
||||
|
||||
import './stylesheet-workspace-view-rich-text-editor-rule.element.js';
|
||||
|
||||
@@ -111,7 +109,7 @@ export class UmbStylesheetWorkspaceViewRichTextEditorElement extends UmbLitEleme
|
||||
}
|
||||
|
||||
static styles = [
|
||||
UUITextStyles,
|
||||
UmbTextStyles,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
|
||||
@@ -2,8 +2,8 @@ import { UmbTemplateRepository } from '../../repository/template.repository.js';
|
||||
import type { UmbQueryBuilderFilterElement } from './query-builder-filter.element.js';
|
||||
import { UUIComboboxListElement } from '@umbraco-cms/backoffice/external/uui';
|
||||
import { css, html, customElement, state, query, queryAll } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
|
||||
import {
|
||||
UmbModalBaseElement ,
|
||||
UMB_DOCUMENT_PICKER_MODAL,
|
||||
UMB_MODAL_MANAGER_CONTEXT_TOKEN,
|
||||
UmbModalManagerContext,
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { UMB_AUTH } from '@umbraco-cms/backoffice/auth';
|
||||
import { UMB_AUTH_CONTEXT } 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 UmbLitElement {
|
||||
#auth?: typeof UMB_AUTH.TYPE;
|
||||
#auth?: typeof UMB_AUTH_CONTEXT.TYPE;
|
||||
|
||||
@state()
|
||||
private name = '';
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.consumeContext(UMB_AUTH, (instance) => {
|
||||
this.consumeContext(UMB_AUTH_CONTEXT, (instance) => {
|
||||
this.#auth = instance;
|
||||
this.#observeCurrentUser();
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { UmbTextStyles } from "@umbraco-cms/backoffice/style";
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { css, CSSResultGroup, html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import {
|
||||
UmbModalManagerContext,
|
||||
@@ -6,14 +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';
|
||||
import { UMB_AUTH_CONTEXT, type UmbLoggedInUser } from '@umbraco-cms/backoffice/auth';
|
||||
|
||||
@customElement('umb-current-user-header-app')
|
||||
export class UmbCurrentUserHeaderAppElement extends UmbLitElement {
|
||||
@state()
|
||||
private _currentUser?: UmbLoggedInUser;
|
||||
|
||||
private _auth?: typeof UMB_AUTH.TYPE;
|
||||
private _auth?: typeof UMB_AUTH_CONTEXT.TYPE;
|
||||
private _modalContext?: UmbModalManagerContext;
|
||||
|
||||
constructor() {
|
||||
@@ -23,7 +23,7 @@ export class UmbCurrentUserHeaderAppElement extends UmbLitElement {
|
||||
this._modalContext = instance;
|
||||
});
|
||||
|
||||
this.consumeContext(UMB_AUTH, (instance) => {
|
||||
this.consumeContext(UMB_AUTH_CONTEXT, (instance) => {
|
||||
this._auth = instance;
|
||||
this._observeCurrentUser();
|
||||
});
|
||||
@@ -34,7 +34,7 @@ export class UmbCurrentUserHeaderAppElement extends UmbLitElement {
|
||||
|
||||
this.observe(this._auth.currentUser, (currentUser) => {
|
||||
this._currentUser = currentUser;
|
||||
});
|
||||
}, 'umbCurrentUserObserver');
|
||||
}
|
||||
|
||||
private _handleUserClick() {
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
// TODO:Do not export store, but instead export future repository
|
||||
export * from './current-user-history.store.js';
|
||||
export * from './utils/index.js';
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
import { UmbTextStyles } from "@umbraco-cms/backoffice/style";
|
||||
import { css, CSSResultGroup, html, nothing, customElement, property } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbModalContext, UmbChangePasswordModalData } from '@umbraco-cms/backoffice/modal';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
|
||||
@customElement('umb-change-password-modal')
|
||||
export class UmbChangePasswordModalElement extends UmbLitElement {
|
||||
@property({ attribute: false })
|
||||
modalContext?: UmbModalContext;
|
||||
|
||||
@property()
|
||||
data?: UmbChangePasswordModalData;
|
||||
|
||||
private _close() {
|
||||
this.modalContext?.submit();
|
||||
}
|
||||
|
||||
private _handleSubmit(e: SubmitEvent) {
|
||||
e.preventDefault();
|
||||
|
||||
const form = e.target as HTMLFormElement;
|
||||
if (!form) return;
|
||||
|
||||
const isValid = form.checkValidity();
|
||||
if (!isValid) return;
|
||||
|
||||
const formData = new FormData(form);
|
||||
|
||||
const oldPassword = formData.get('oldPassword') as string;
|
||||
const newPassword = formData.get('newPassword') as string;
|
||||
const confirmPassword = formData.get('confirmPassword') as string;
|
||||
console.log('IMPLEMENT SUBMIT', { oldPassword, newPassword, confirmPassword });
|
||||
this._close();
|
||||
}
|
||||
|
||||
private _renderOldPasswordInput() {
|
||||
return html`
|
||||
<uui-form-layout-item style="margin-bottom: var(--uui-size-layout-2)">
|
||||
<uui-label id="oldPasswordLabel" for="oldPassword" slot="label" required>Old password</uui-label>
|
||||
<uui-input-password
|
||||
id="oldPassword"
|
||||
name="oldPassword"
|
||||
required
|
||||
required-message="Old password is required"></uui-input-password>
|
||||
</uui-form-layout-item>
|
||||
`;
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<uui-dialog-layout class="uui-text" headline="Change password">
|
||||
<uui-form>
|
||||
<form id="LoginForm" name="login" @submit="${this._handleSubmit}">
|
||||
${this.data?.requireOldPassword ? this._renderOldPasswordInput() : nothing}
|
||||
<uui-form-layout-item>
|
||||
<uui-label id="newPasswordLabel" for="newPassword" slot="label" required>New password</uui-label>
|
||||
<uui-input-password
|
||||
id="newPassword"
|
||||
name="newPassword"
|
||||
required
|
||||
required-message="New password is required"></uui-input-password>
|
||||
</uui-form-layout-item>
|
||||
<uui-form-layout-item>
|
||||
<uui-label id="confirmPasswordLabel" for="confirmPassword" slot="label" required
|
||||
>Confirm password</uui-label
|
||||
>
|
||||
<uui-input-password
|
||||
id="confirmPassword"
|
||||
name="confirmPassword"
|
||||
required
|
||||
required-message="Confirm password is required"></uui-input-password>
|
||||
</uui-form-layout-item>
|
||||
|
||||
<div id="actions">
|
||||
<uui-button @click=${this._close} label="Cancel"></uui-button>
|
||||
<uui-button type="submit" label="Confirm" look="primary" color="positive"></uui-button>
|
||||
</div>
|
||||
</form>
|
||||
</uui-form>
|
||||
</uui-dialog-layout>
|
||||
`;
|
||||
}
|
||||
|
||||
static styles: CSSResultGroup = [
|
||||
UmbTextStyles,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
width: 400px;
|
||||
}
|
||||
uui-input-password {
|
||||
width: 100%;
|
||||
}
|
||||
#actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: var(--uui-size-layout-2);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
export default UmbChangePasswordModalElement;
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'umb-change-password-modal': UmbChangePasswordModalElement;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { UMB_APP } from '@umbraco-cms/backoffice/app';
|
||||
import { UMB_AUTH, type UmbLoggedInUser } from '@umbraco-cms/backoffice/auth';
|
||||
import { UMB_AUTH_CONTEXT, type UmbLoggedInUser } from '@umbraco-cms/backoffice/auth';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { css, CSSResultGroup, html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbModalContext } from '@umbraco-cms/backoffice/modal';
|
||||
@@ -13,14 +13,14 @@ export class UmbCurrentUserModalElement extends UmbLitElement {
|
||||
@state()
|
||||
private _currentUser?: UmbLoggedInUser;
|
||||
|
||||
#authContext?: typeof UMB_AUTH.TYPE;
|
||||
#authContext?: typeof UMB_AUTH_CONTEXT.TYPE;
|
||||
|
||||
#appContext?: typeof UMB_APP.TYPE;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.consumeContext(UMB_AUTH, (instance) => {
|
||||
this.consumeContext(UMB_AUTH_CONTEXT, (instance) => {
|
||||
this.#authContext = instance;
|
||||
this._observeCurrentUser();
|
||||
});
|
||||
@@ -35,7 +35,7 @@ export class UmbCurrentUserModalElement extends UmbLitElement {
|
||||
|
||||
this.observe(this.#authContext.currentUser, (currentUser) => {
|
||||
this._currentUser = currentUser;
|
||||
});
|
||||
}, 'umbCurrentUserObserver');
|
||||
}
|
||||
|
||||
private _close() {
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { ManifestModal } from '@umbraco-cms/backoffice/extension-registry';
|
||||
const modals: Array<ManifestModal> = [
|
||||
{
|
||||
type: 'modal',
|
||||
alias: 'Umb.Modal.CurrentUser',
|
||||
alias: 'Umb.Modal.User.Current',
|
||||
name: 'Current User Modal',
|
||||
loader: () => import('./current-user/current-user-modal.element.js'),
|
||||
},
|
||||
|
||||
@@ -27,7 +27,7 @@ export class UmbUserProfileAppHistoryElement extends UmbLitElement {
|
||||
if (this.#currentUserHistoryStore) {
|
||||
this.observe(this.#currentUserHistoryStore.latestHistory, (history) => {
|
||||
this._history = history;
|
||||
});
|
||||
}, 'umbCurrentUserHistoryObserver');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbTextStyles } from "@umbraco-cms/backoffice/style";
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
import {
|
||||
UmbModalManagerContext,
|
||||
UMB_CHANGE_PASSWORD_MODAL,
|
||||
UMB_MODAL_MANAGER_CONTEXT_TOKEN,
|
||||
} from '@umbraco-cms/backoffice/modal';
|
||||
import { UMB_AUTH, type UmbLoggedInUser } from '@umbraco-cms/backoffice/auth';
|
||||
import { UMB_AUTH_CONTEXT, type UmbLoggedInUser } from '@umbraco-cms/backoffice/auth';
|
||||
|
||||
@customElement('umb-user-profile-app-profile')
|
||||
export class UmbUserProfileAppProfileElement extends UmbLitElement {
|
||||
@@ -14,7 +14,7 @@ export class UmbUserProfileAppProfileElement extends UmbLitElement {
|
||||
private _currentUser?: UmbLoggedInUser;
|
||||
|
||||
private _modalContext?: UmbModalManagerContext;
|
||||
private _auth?: typeof UMB_AUTH.TYPE;
|
||||
private _auth?: typeof UMB_AUTH_CONTEXT.TYPE;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
@@ -23,7 +23,7 @@ export class UmbUserProfileAppProfileElement extends UmbLitElement {
|
||||
this._modalContext = instance;
|
||||
});
|
||||
|
||||
this.consumeContext(UMB_AUTH, (instance) => {
|
||||
this.consumeContext(UMB_AUTH_CONTEXT, (instance) => {
|
||||
this._auth = instance;
|
||||
this._observeCurrentUser();
|
||||
});
|
||||
@@ -34,21 +34,20 @@ export class UmbUserProfileAppProfileElement extends UmbLitElement {
|
||||
|
||||
this.observe(this._auth.currentUser, (currentUser) => {
|
||||
this._currentUser = currentUser;
|
||||
});
|
||||
}, 'umbCurrentUserObserver');
|
||||
}
|
||||
|
||||
private _edit() {
|
||||
if (!this._currentUser) return;
|
||||
|
||||
history.pushState(null, '', 'section/users/view/users/user/' + this._currentUser.id); //TODO Change to a tag with href and make dynamic
|
||||
history.pushState(null, '', 'section/user-management/view/users/user/' + this._currentUser.id); //TODO Change to a tag with href and make dynamic
|
||||
//TODO Implement modal routing for the current-user-modal, so that the modal closes when navigating to the edit profile page
|
||||
}
|
||||
private _changePassword() {
|
||||
if (!this._modalContext) return;
|
||||
|
||||
// TODO: check if current user is admin
|
||||
|
||||
this._modalContext.open(UMB_CHANGE_PASSWORD_MODAL, {
|
||||
requireOldPassword: false,
|
||||
userId: this._currentUser?.id ?? '',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user