diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/utils/is-current-user.function.ts b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/utils/is-current-user.function.ts index 12ed90a23c..c775883aed 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/utils/is-current-user.function.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/utils/is-current-user.function.ts @@ -2,12 +2,10 @@ import { UMB_CURRENT_USER_CONTEXT } from '../current-user.context.js'; import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -export const isCurrentUser = async (host: UmbControllerHost, userId: string) => { - let currentUserContext: typeof UMB_CURRENT_USER_CONTEXT.TYPE | undefined; +export const isCurrentUser = async (host: UmbControllerHost, userUnique: string) => { + const ctrl = new UmbContextConsumerController(host, UMB_CURRENT_USER_CONTEXT); + const currentUserContext = await ctrl.asPromise(); + ctrl.destroy(); - await new UmbContextConsumerController(host, UMB_CURRENT_USER_CONTEXT, (context) => { - currentUserContext = context; - }).asPromise(); - - return await currentUserContext!.isUserCurrentUser(userId); + return await currentUserContext!.isUserCurrentUser(userUnique); }; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/conditions/user-allow-action-base.condition.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/conditions/user-allow-action-base.condition.ts index a80fd0271c..cc3500951b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/conditions/user-allow-action-base.condition.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/conditions/user-allow-action-base.condition.ts @@ -1,5 +1,5 @@ -import type { UmbUserDetailModel } from '../types.js'; -import type { UmbUserWorkspaceContext } from '../workspace/user-workspace.context.js'; +import type { UmbUserStateEnum } from '../types.js'; +import { UMB_USER_WORKSPACE_CONTEXT } from '../workspace/user-workspace.context.js'; import { UmbBaseController } from '@umbraco-cms/backoffice/class-api'; import { isCurrentUser } from '@umbraco-cms/backoffice/current-user'; import type { @@ -7,28 +7,38 @@ import type { UmbConditionControllerArguments, UmbExtensionCondition, } from '@umbraco-cms/backoffice/extension-api'; -import { UMB_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/workspace'; export class UmbUserActionConditionBase extends UmbBaseController implements UmbExtensionCondition { config: UmbConditionConfigBase; permitted = false; #onChange: () => void; - protected userData?: UmbUserDetailModel; + protected userUnique?: string; + protected userState?: UmbUserStateEnum | null; constructor(args: UmbConditionControllerArguments) { super(args.host); this.config = args.config; this.#onChange = args.onChange; - this.consumeContext(UMB_WORKSPACE_CONTEXT, (context) => { - const userContext = context as UmbUserWorkspaceContext; + this.consumeContext(UMB_USER_WORKSPACE_CONTEXT, (context) => { this.observe( - userContext.data, - (data) => { - this.userData = data; + context.unique, + (unique) => { + this.userUnique = unique; this.onUserDataChange(); }, - 'umbUserDataActionConditionObserver', + 'umbUserUnique', + ); + this.observe( + context.state, + (state) => { + this.userState = state; + // TODO: Investigate if we can remove this observation and just use the unique change to trigger the state change. [NL] + // Can user state change over time? if not then this observation is not needed and then we just need to retrieve the state when the unique has changed. [NL] + // These two could also be combined via the observeMultiple method, that could prevent triggering onUserDataChanged twice. [NL] + this.onUserDataChange(); + }, + 'umbUserState', ); }); } @@ -40,7 +50,7 @@ export class UmbUserActionConditionBase extends UmbBaseController implements Umb * @memberof UmbUserActionConditionBase */ protected async isCurrentUser() { - return this.userData?.unique ? isCurrentUser(this._host, this.userData.unique) : false; + return this.userUnique ? isCurrentUser(this._host, this.userUnique) : false; } /** diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/conditions/user-allow-delete-action.condition.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/conditions/user-allow-delete-action.condition.ts index a55f4ad671..b98e3cf14b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/conditions/user-allow-delete-action.condition.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/conditions/user-allow-delete-action.condition.ts @@ -1,18 +1,10 @@ import { UmbUserActionConditionBase } from './user-allow-action-base.condition.js'; -import type { - ManifestCondition, - UmbConditionConfigBase, - UmbConditionControllerArguments, -} from '@umbraco-cms/backoffice/extension-api'; +import type { ManifestCondition } from '@umbraco-cms/backoffice/extension-api'; export class UmbUserAllowDeleteActionCondition extends UmbUserActionConditionBase { - constructor(args: UmbConditionControllerArguments) { - super(args); - } - async onUserDataChange() { // don't allow the current user to delete themselves - if (!this.userData || !this.userData.unique || (await this.isCurrentUser())) { + if (!this.userUnique || (await this.isCurrentUser())) { this.permitted = false; } else { this.permitted = true; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/conditions/user-allow-disable-action.condition.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/conditions/user-allow-disable-action.condition.ts index 358b0ab2d3..a96967c3b5 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/conditions/user-allow-disable-action.condition.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/conditions/user-allow-disable-action.condition.ts @@ -1,25 +1,17 @@ +import { UmbUserStateEnum } from '../types.js'; import { UmbUserActionConditionBase } from './user-allow-action-base.condition.js'; -import { UserStateModel } from '@umbraco-cms/backoffice/external/backend-api'; -import type { - ManifestCondition, - UmbConditionConfigBase, - UmbConditionControllerArguments, -} from '@umbraco-cms/backoffice/extension-api'; +import type { ManifestCondition } from '@umbraco-cms/backoffice/extension-api'; export class UmbUserAllowDisableActionCondition extends UmbUserActionConditionBase { - constructor(args: UmbConditionControllerArguments) { - super(args); - } - async onUserDataChange() { // don't allow the current user to disable themselves - if (!this.userData || !this.userData.unique || (await this.isCurrentUser())) { + if (!this.userUnique || (await this.isCurrentUser())) { this.permitted = false; super.onUserDataChange(); return; } - this.permitted = this.userData?.state !== UserStateModel.DISABLED; + this.permitted = this.userState !== UmbUserStateEnum.DISABLED; super.onUserDataChange(); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/conditions/user-allow-enable-action.condition.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/conditions/user-allow-enable-action.condition.ts index 00268264ca..8bbb0accbd 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/conditions/user-allow-enable-action.condition.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/conditions/user-allow-enable-action.condition.ts @@ -1,25 +1,17 @@ +import { UmbUserStateEnum } from '../types.js'; import { UmbUserActionConditionBase } from './user-allow-action-base.condition.js'; -import { UserStateModel } from '@umbraco-cms/backoffice/external/backend-api'; -import type { - ManifestCondition, - UmbConditionConfigBase, - UmbConditionControllerArguments, -} from '@umbraco-cms/backoffice/extension-api'; +import type { ManifestCondition } from '@umbraco-cms/backoffice/extension-api'; export class UmbUserAllowEnableActionCondition extends UmbUserActionConditionBase { - constructor(args: UmbConditionControllerArguments) { - super(args); - } - async onUserDataChange() { // don't allow the current user to enable themselves - if (!this.userData || !this.userData.unique || (await this.isCurrentUser())) { + if (!this.userUnique || (await this.isCurrentUser())) { this.permitted = false; super.onUserDataChange(); return; } - this.permitted = this.userData?.state === UserStateModel.DISABLED; + this.permitted = this.userState === UmbUserStateEnum.DISABLED; super.onUserDataChange(); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/conditions/user-allow-unlock-action.condition.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/conditions/user-allow-unlock-action.condition.ts index 11b481faf8..281acac60a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/conditions/user-allow-unlock-action.condition.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/conditions/user-allow-unlock-action.condition.ts @@ -1,25 +1,17 @@ +import { UmbUserStateEnum } from '../types.js'; import { UmbUserActionConditionBase } from './user-allow-action-base.condition.js'; -import { UserStateModel } from '@umbraco-cms/backoffice/external/backend-api'; -import type { - ManifestCondition, - UmbConditionConfigBase, - UmbConditionControllerArguments, -} from '@umbraco-cms/backoffice/extension-api'; +import type { ManifestCondition } from '@umbraco-cms/backoffice/extension-api'; export class UmbUserAllowUnlockActionCondition extends UmbUserActionConditionBase { - constructor(args: UmbConditionControllerArguments) { - super(args); - } - async onUserDataChange() { // don't allow the current user to unlock themselves - if (!this.userData || !this.userData.unique || (await this.isCurrentUser())) { + if (!this.userUnique || (await this.isCurrentUser())) { this.permitted = false; super.onUserDataChange(); return; } - this.permitted = this.userData?.state === UserStateModel.LOCKED_OUT; + this.permitted = this.userState === UmbUserStateEnum.LOCKED_OUT; super.onUserDataChange(); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/invite/entity-action/resend-invite/resend-invite.action.condition.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/invite/entity-action/resend-invite/resend-invite.action.condition.ts index 73dbad59cb..7fc8d4a9cc 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/invite/entity-action/resend-invite/resend-invite.action.condition.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/invite/entity-action/resend-invite/resend-invite.action.condition.ts @@ -1,24 +1,16 @@ import { UmbUserActionConditionBase } from '../../../conditions/user-allow-action-base.condition.js'; import { UserStateModel } from '@umbraco-cms/backoffice/external/backend-api'; -import type { - ManifestCondition, - UmbConditionConfigBase, - UmbConditionControllerArguments, -} from '@umbraco-cms/backoffice/extension-api'; +import type { ManifestCondition } from '@umbraco-cms/backoffice/extension-api'; export class UmbUserAllowResendInviteActionCondition extends UmbUserActionConditionBase { - constructor(args: UmbConditionControllerArguments) { - super(args); - } - async onUserDataChange() { - if (!this.userData || !this.userData.unique) { + if (!this.userUnique) { this.permitted = false; super.onUserDataChange(); return; } - this.permitted = this.userData?.state === UserStateModel.INVITED; + this.permitted = this.userState === UserStateModel.INVITED; super.onUserDataChange(); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/types.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/types.ts index c447767734..3cb879b380 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/types.ts @@ -1,5 +1,8 @@ import type { UmbUserEntityType } from './entity.js'; -import type { UserStateModel } from '@umbraco-cms/backoffice/external/backend-api'; +import { UserStateModel } from '@umbraco-cms/backoffice/external/backend-api'; + +export type UmbUserStateEnum = UserStateModel; +export const UmbUserStateEnum = UserStateModel; export interface UmbUserDetailModel { entityType: UmbUserEntityType; @@ -12,7 +15,7 @@ export interface UmbUserDetailModel { documentStartNodeUniques: Array; mediaStartNodeUniques: Array; avatarUrls: Array; - state: UserStateModel | null; + state: UmbUserStateEnum | null; failedLoginAttempts: number; createDate: string | null; updateDate: string | null; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/components/user-workspace-profile-settings/user-workspace-profile-settings.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/components/user-workspace-profile-settings/user-workspace-profile-settings.element.ts index 5a8f1547c6..96a0126009 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/components/user-workspace-profile-settings/user-workspace-profile-settings.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/components/user-workspace-profile-settings/user-workspace-profile-settings.element.ts @@ -57,7 +57,7 @@ export class UmbUserWorkspaceProfileSettingsElement extends UmbLitElement { description=${this.localize.term('user_languageHelp')}> diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-workspace.context.ts index c62bd094b8..9863a34596 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-workspace.context.ts @@ -1,4 +1,4 @@ -import type { UmbUserDetailModel } from '../types.js'; +import type { UmbUserDetailModel, UmbUserStateEnum } from '../types.js'; import { UMB_USER_ENTITY_TYPE } from '../entity.js'; import { UmbUserDetailRepository } from '../repository/index.js'; import { UmbUserAvatarRepository } from '../repository/avatar/index.js'; @@ -24,12 +24,15 @@ export class UmbUserWorkspaceContext #persistedData = new UmbObjectState(undefined); #currentData = new UmbObjectState(undefined); - //data = this.#currentData.asObservable(); + readonly data = this.#currentData.asObservable(); + readonly state = this.#currentData.asObservablePart((x) => x?.state); + readonly unique = this.#currentData.asObservablePart((x) => x?.unique); async load(unique: string) { const { data, asObservable } = await this.detailRepository.requestByUnique(unique); if (data) { this.setIsNew(false); + this.#persistedData.update(data); this.#currentData.update(data); } @@ -49,6 +52,9 @@ export class UmbUserWorkspaceContext getUnique(): string | undefined { return this.getData()?.unique; } + getState(): UmbUserStateEnum | null | undefined { + return this.getData()?.state; + } getEntityType(): string { return UMB_USER_ENTITY_TYPE; @@ -69,14 +75,15 @@ export class UmbUserWorkspaceContext let newData = undefined; if (this.getIsNew()) { - const { data } = await this.detailRepository.create(this.#data.value); + const { data } = await this.detailRepository.create(this.#currentData.value); newData = data; } else { - const { data } = await this.detailRepository.save(this.#data.value); + const { data } = await this.detailRepository.save(this.#currentData.value); newData = data; } if (newData) { + this.#persistedData.setValue(newData); this.#currentData.setValue(newData); this.saveComplete(newData); } @@ -98,6 +105,8 @@ export class UmbUserWorkspaceContext destroy(): void { this.#persistedData.destroy(); this.#currentData.destroy(); + this.detailRepository.destroy(); + this.avatarRepository.destroy(); super.destroy(); } }