Merge pull request #1571 from umbraco/feature/user-profile-actions-default
Feature/user-profile-actions-default
This commit is contained in:
@@ -12,6 +12,7 @@ export class UmbCurrentUserContext extends UmbContextBase<UmbCurrentUserContext>
|
||||
#currentUser = new UmbObjectState<UmbCurrentUserModel | undefined>(undefined);
|
||||
readonly currentUser = this.#currentUser.asObservable();
|
||||
|
||||
readonly unique = this.#currentUser.asObservablePart((user) => user?.unique);
|
||||
readonly languageIsoCode = this.#currentUser.asObservablePart((user) => user?.languageIsoCode);
|
||||
|
||||
#authContext?: typeof UMB_AUTH_CONTEXT.TYPE;
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import { html, customElement } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
|
||||
@customElement('umb-external-login-providers-user-profile-app')
|
||||
export class UmbExternalLoginProvidersUserProfileAppElement extends UmbLitElement {
|
||||
render() {
|
||||
return html`
|
||||
<uui-box>
|
||||
<b slot="headline">External login providers</b>
|
||||
<umb-extension-slot id="externalLoginProviders" type="externalLoginProvider"></umb-extension-slot>
|
||||
</uui-box>
|
||||
`;
|
||||
}
|
||||
|
||||
static styles = [UmbTextStyles];
|
||||
}
|
||||
|
||||
export default UmbExternalLoginProvidersUserProfileAppElement;
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'umb-external-login-providers-user-profile-app': UmbExternalLoginProvidersUserProfileAppElement;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import type { ManifestUserProfileApp } from '@umbraco-cms/backoffice/extension-registry';
|
||||
|
||||
export const userProfileApps: Array<ManifestUserProfileApp> = [
|
||||
{
|
||||
type: 'userProfileApp',
|
||||
alias: 'Umb.UserProfileApp.CurrentUser.ExternalLoginProviders',
|
||||
name: 'External Login Providers User Profile App',
|
||||
element: () => import('./external-login-providers-user-profile-app.element.js'),
|
||||
weight: 700,
|
||||
meta: {
|
||||
label: 'External Login Providers User Profile App',
|
||||
pathname: 'externalLoginProviders',
|
||||
},
|
||||
},
|
||||
];
|
||||
export const manifests = [...userProfileApps];
|
||||
@@ -1,6 +1,5 @@
|
||||
import { manifest as actionDefaultKindManifest } from './action/default.kind.js';
|
||||
import { manifests as modalManifests } from './modals/manifests.js';
|
||||
import { manifests as externalLoginProviderManifests } from './external-login/manifests.js';
|
||||
import { manifests as historyManifests } from './history/manifests.js';
|
||||
import { manifests as mfaLoginProviderManifests } from './mfa-login/manifests.js';
|
||||
import { manifests as profileManifests } from './profile/manifests.js';
|
||||
@@ -31,7 +30,6 @@ export const headerApps: Array<ManifestTypes> = [
|
||||
|
||||
export const manifests = [
|
||||
actionDefaultKindManifest,
|
||||
...externalLoginProviderManifests,
|
||||
...headerApps,
|
||||
...historyManifests,
|
||||
...mfaLoginProviderManifests,
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import { UMB_CURRENT_USER_MFA_MODAL } from '../modals/current-user-mfa/current-user-mfa-modal.token.js';
|
||||
import { UmbActionBase } from '@umbraco-cms/backoffice/action';
|
||||
import type { UmbCurrentUserAction, UmbCurrentUserActionArgs } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
|
||||
|
||||
export class UmbConfigureMfaProvidersApi<ArgsMetaType = never>
|
||||
extends UmbActionBase<UmbCurrentUserActionArgs<ArgsMetaType>>
|
||||
implements UmbCurrentUserAction<ArgsMetaType>
|
||||
{
|
||||
async getHref() {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async execute() {
|
||||
const modalManagerContext = await this.getContext(UMB_MODAL_MANAGER_CONTEXT);
|
||||
await modalManagerContext.open(this, UMB_CURRENT_USER_MFA_MODAL).onSubmit();
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,24 @@
|
||||
import type { ManifestUserProfileApp } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import { UmbConfigureMfaProvidersApi } from './configure-mfa-providers-action.js';
|
||||
import type { ManifestCurrentUserActionDefaultKind } from '@umbraco-cms/backoffice/extension-registry';
|
||||
|
||||
export const userProfileApps: Array<ManifestUserProfileApp> = [
|
||||
export const userProfileApps: Array<ManifestCurrentUserActionDefaultKind> = [
|
||||
{
|
||||
type: 'userProfileApp',
|
||||
alias: 'Umb.UserProfileApp.CurrentUser.MfaLoginProviders',
|
||||
name: 'MFA Login Providers User Profile App',
|
||||
element: () => import('./mfa-providers-user-profile-app.element.js'),
|
||||
type: 'currentUserAction',
|
||||
kind: 'default',
|
||||
alias: 'Umb.CurrentUser.App.MfaLoginProviders',
|
||||
name: 'MFA Login Providers Current User App',
|
||||
weight: 800,
|
||||
api: UmbConfigureMfaProvidersApi,
|
||||
meta: {
|
||||
label: 'Two-Factor Authentication',
|
||||
pathname: 'mfa-providers',
|
||||
label: '#user_configureTwoFactor',
|
||||
icon: 'icon-rectangle-ellipsis',
|
||||
look: 'secondary',
|
||||
},
|
||||
conditions: [
|
||||
{
|
||||
alias: 'Umb.Condition.User.AllowMfaAction',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
export const manifests = [...userProfileApps];
|
||||
|
||||
@@ -6,8 +6,8 @@ import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
|
||||
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import { firstValueFrom } from '@umbraco-cms/backoffice/external/rxjs';
|
||||
|
||||
@customElement('umb-mfa-providers-user-profile-app')
|
||||
export class UmbMfaProvidersUserProfileAppElement extends UmbLitElement {
|
||||
@customElement('umb-mfa-providers-current-user-app')
|
||||
export class UmbMfaProvidersCurrentUserAppElement extends UmbLitElement {
|
||||
@state()
|
||||
_hasProviders = false;
|
||||
|
||||
@@ -26,11 +26,14 @@ export class UmbMfaProvidersUserProfileAppElement extends UmbLitElement {
|
||||
}
|
||||
|
||||
return html`
|
||||
<uui-box .headline=${this.localize.term('member_2fa')}>
|
||||
<uui-button type="button" look="primary" @click=${this.#onClick}>
|
||||
<umb-localize key="user_configureTwoFactor">Configure Two Factor</umb-localize>
|
||||
</uui-button>
|
||||
</uui-box>
|
||||
<uui-button
|
||||
type="button"
|
||||
look="primary"
|
||||
label="${this.localize.term('user_configureTwoFactor')}"
|
||||
@click=${this.#onClick}>
|
||||
<uui-icon name="icon-rectangle-ellipsis"></uui-icon>
|
||||
<umb-localize key="user_configureTwoFactor">Configure Two Factor</umb-localize>
|
||||
</uui-button>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -42,10 +45,10 @@ export class UmbMfaProvidersUserProfileAppElement extends UmbLitElement {
|
||||
static styles = [UmbTextStyles];
|
||||
}
|
||||
|
||||
export default UmbMfaProvidersUserProfileAppElement;
|
||||
export default UmbMfaProvidersCurrentUserAppElement;
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'umb-mfa-providers-user-profile-app': UmbMfaProvidersUserProfileAppElement;
|
||||
'umb-mfa-providers-current-user-app': UmbMfaProvidersCurrentUserAppElement;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { UMB_CURRENT_USER_CONTEXT } from '../current-user.context.js';
|
||||
import { UmbActionBase } from '@umbraco-cms/backoffice/action';
|
||||
import type { UmbCurrentUserAction, UmbCurrentUserActionArgs } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UMB_CHANGE_PASSWORD_MODAL, UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
|
||||
|
||||
export class UmbChangePasswordCurrentUserAction<ArgsMetaType = never>
|
||||
extends UmbActionBase<UmbCurrentUserActionArgs<ArgsMetaType>>
|
||||
implements UmbCurrentUserAction<ArgsMetaType>
|
||||
{
|
||||
#unique?: string;
|
||||
|
||||
constructor(host: UmbControllerHost, args: UmbCurrentUserActionArgs<ArgsMetaType>) {
|
||||
super(host, args);
|
||||
|
||||
this.consumeContext(UMB_CURRENT_USER_CONTEXT, (context) => {
|
||||
this.observe(
|
||||
context.unique,
|
||||
(unique) => {
|
||||
this.#unique = unique;
|
||||
},
|
||||
'umbEditCurrentUserActionObserver',
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
async getHref() {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async execute() {
|
||||
if (!this.#unique) return;
|
||||
|
||||
const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT);
|
||||
modalManager.open(this, UMB_CHANGE_PASSWORD_MODAL, {
|
||||
data: {
|
||||
user: {
|
||||
unique: this.#unique,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,65 +1,12 @@
|
||||
import { html, customElement, state, css } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { html, customElement, css } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
import { UMB_CHANGE_PASSWORD_MODAL, UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
|
||||
import { UMB_CURRENT_USER_CONTEXT, type UmbCurrentUserModel } from '@umbraco-cms/backoffice/current-user';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
|
||||
@customElement('umb-current-user-profile-user-profile-app')
|
||||
export class UmbCurrentUserProfileUserProfileAppElement extends UmbLitElement {
|
||||
@state()
|
||||
private _currentUser?: UmbCurrentUserModel;
|
||||
|
||||
#currentUserContext?: typeof UMB_CURRENT_USER_CONTEXT.TYPE;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.consumeContext(UMB_CURRENT_USER_CONTEXT, (instance) => {
|
||||
this.#currentUserContext = instance;
|
||||
this._observeCurrentUser();
|
||||
});
|
||||
}
|
||||
|
||||
private async _observeCurrentUser() {
|
||||
if (!this.#currentUserContext) return;
|
||||
|
||||
this.observe(
|
||||
this.#currentUserContext.currentUser,
|
||||
(currentUser) => {
|
||||
this._currentUser = currentUser;
|
||||
},
|
||||
'umbCurrentUserObserver',
|
||||
);
|
||||
}
|
||||
|
||||
private _edit() {
|
||||
if (!this._currentUser) return;
|
||||
|
||||
history.pushState(null, '', 'section/user-management/view/users/user/edit/' + this._currentUser.unique); //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
|
||||
}
|
||||
async #changePassword() {
|
||||
if (!this._currentUser) throw new Error('Current User not found');
|
||||
|
||||
const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT);
|
||||
modalManager.open(this, UMB_CHANGE_PASSWORD_MODAL, {
|
||||
data: {
|
||||
user: {
|
||||
unique: this._currentUser.unique,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<uui-box .headline=${this.localize.term('user_yourProfile')}>
|
||||
<uui-button look="primary" label=${this.localize.term('general_edit')} @click=${this._edit}>
|
||||
${this.localize.term('general_edit')}
|
||||
</uui-button>
|
||||
<uui-button look="primary" label=${this.localize.term('general_changePassword')} @click=${this.#changePassword}>
|
||||
${this.localize.term('general_changePassword')}
|
||||
</uui-button>
|
||||
<umb-extension-with-api-slot id="actions" type="currentUserAction"></umb-extension-with-api-slot>
|
||||
</uui-box>
|
||||
`;
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { UMB_CURRENT_USER_CONTEXT } from '../current-user.context.js';
|
||||
import { UmbActionBase } from '@umbraco-cms/backoffice/action';
|
||||
import type { UmbCurrentUserAction, UmbCurrentUserActionArgs } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
|
||||
|
||||
export class UmbEditCurrentUserAction<ArgsMetaType = never>
|
||||
extends UmbActionBase<UmbCurrentUserActionArgs<ArgsMetaType>>
|
||||
implements UmbCurrentUserAction<ArgsMetaType>
|
||||
{
|
||||
#init;
|
||||
#unique?: string;
|
||||
|
||||
constructor(host: UmbControllerHost, args: UmbCurrentUserActionArgs<ArgsMetaType>) {
|
||||
super(host, args);
|
||||
|
||||
this.#init = new Promise<void>((res) => {
|
||||
this.consumeContext(UMB_CURRENT_USER_CONTEXT, (context) => {
|
||||
this.observe(
|
||||
context.unique,
|
||||
(unique) => {
|
||||
this.#unique = unique;
|
||||
res();
|
||||
},
|
||||
'umbEditCurrentUserActionObserver',
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async getHref() {
|
||||
await this.#init;
|
||||
return `section/user-management/view/users/user/edit/${this.#unique}`;
|
||||
}
|
||||
|
||||
async execute() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,11 @@
|
||||
import type { ManifestUserProfileApp } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import { UmbChangePasswordCurrentUserAction } from './change-password-current-user.action.js';
|
||||
import { UmbEditCurrentUserAction } from './edit-current-user.action.js';
|
||||
import type {
|
||||
ManifestCurrentUserActionDefaultKind,
|
||||
ManifestUserProfileApp,
|
||||
} from '@umbraco-cms/backoffice/extension-registry';
|
||||
|
||||
export const userProfileApps: Array<ManifestUserProfileApp> = [
|
||||
const userProfileApps: Array<ManifestUserProfileApp> = [
|
||||
{
|
||||
type: 'userProfileApp',
|
||||
alias: 'Umb.UserProfileApp.CurrentUser.Profile',
|
||||
@@ -13,4 +18,38 @@ export const userProfileApps: Array<ManifestUserProfileApp> = [
|
||||
},
|
||||
},
|
||||
];
|
||||
export const manifests = [...userProfileApps];
|
||||
|
||||
const currentUserActions: Array<ManifestCurrentUserActionDefaultKind> = [
|
||||
{
|
||||
type: 'currentUserAction',
|
||||
kind: 'default',
|
||||
alias: 'Umb.CurrentUser.Button.Edit',
|
||||
name: 'Current User Edit Button',
|
||||
weight: 1000,
|
||||
api: UmbEditCurrentUserAction,
|
||||
meta: {
|
||||
label: '#general_edit',
|
||||
icon: 'edit',
|
||||
},
|
||||
conditions: [
|
||||
{
|
||||
alias: 'Umb.Condition.SectionUserPermission',
|
||||
match: 'Umb.Section.Users',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'currentUserAction',
|
||||
kind: 'default',
|
||||
alias: 'Umb.CurrentUser.Button.ChangePassword',
|
||||
name: 'Current User Change Password Button',
|
||||
weight: 900,
|
||||
api: UmbChangePasswordCurrentUserAction,
|
||||
meta: {
|
||||
label: '#general_changePassword',
|
||||
icon: 'lock',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export const manifests = [...userProfileApps, ...currentUserActions];
|
||||
|
||||
Reference in New Issue
Block a user