diff --git a/src/apps/app/app.element.ts b/src/apps/app/app.element.ts index cea6b8233b..b72f5744bf 100644 --- a/src/apps/app/app.element.ts +++ b/src/apps/app/app.element.ts @@ -86,9 +86,9 @@ export class UmbAppElement extends UmbLitElement { // just in case the user language is not the default language. // We **need** to do this because the default language (typically en-us) holds all the fallback keys for all the other languages. // This way we can ensure that the document language is always loaded first and subsequently registered as the fallback language. - umbLocalizationRegistry.isDefaultLoaded.subscribe((isDefaultLoaded) => { + this.observe(umbLocalizationRegistry.isDefaultLoaded, (isDefaultLoaded) => { if (!this.#authContext) { - throw new Error('[Fatal] AuthContext requested before it was initialised'); + throw new Error('[Fatal] AuthContext requested before it was initialized'); } if (!isDefaultLoaded) return; @@ -134,7 +134,7 @@ export class UmbAppElement extends UmbLitElement { // If the auth flow fails, there is most likely something wrong with the connection to the backend server // and we should redirect to the error page let errorMsg = - 'An error occured while trying to initialise the connection to the Umbraco server (check console for details)'; + 'An error occurred while trying to initialize the connection to the Umbraco server (check console for details)'; // Get the type of the error and check http status codes if (error instanceof Error) { @@ -186,7 +186,7 @@ export class UmbAppElement extends UmbLitElement { async #setAuthStatus() { if (this.bypassAuth === false) { if (!this.#authContext) { - throw new Error('[Fatal] AuthContext requested before it was initialised'); + throw new Error('[Fatal] AuthContext requested before it was initialized'); } // Get service configuration from authentication server @@ -200,9 +200,9 @@ export class UmbAppElement extends UmbLitElement { this.#listenForLanguageChange(); if (this.#authContext?.isAuthorized()) { - this.#authContext.isLoggedIn.next(true); + this.#authContext?.setLoggedIn(true); } else { - this.#authContext?.isLoggedIn.next(false); + this.#authContext?.setLoggedIn(false); } } diff --git a/src/libs/class-api/class.mixin.ts b/src/libs/class-api/class.mixin.ts index 992bdc968d..ac2d5f957f 100644 --- a/src/libs/class-api/class.mixin.ts +++ b/src/libs/class-api/class.mixin.ts @@ -23,7 +23,7 @@ type UmbClassMixinConstructor = new ( declare class UmbClassMixinDeclaration implements UmbClassMixinInterface { _host: UmbControllerHost; observe( - source: Observable | { asObservable: () => Observable }, + source: Observable, callback: (_value: T) => void, controllerAlias?: UmbControllerAlias ): UmbObserverController; diff --git a/src/libs/observable-api/basic-state.ts b/src/libs/observable-api/basic-state.ts index 2090ed0a77..2172afa7fd 100644 --- a/src/libs/observable-api/basic-state.ts +++ b/src/libs/observable-api/basic-state.ts @@ -3,17 +3,74 @@ import { BehaviorSubject } from '@umbraco-cms/backoffice/external/rxjs'; /** * @export * @class UmbBasicState - * @extends {BehaviorSubject} - * @description - A RxJS BehaviorSubject this Subject ensures the data is unique, not updating any Observes unless there is an actual change of the value. + * @description - State ensures the data is unique, not updating any Observes unless there is an actual change of the value using `===`. */ -export class UmbBasicState extends BehaviorSubject { +export class UmbBasicState { + + protected _subject:BehaviorSubject; + constructor(initialData: T) { - super(initialData); + this._subject = new BehaviorSubject(initialData); + } + + + /** + * @method asObservable + * @return {Observable} Observable that the State casts to. + * @description - Creates a new Observable with this State as the source. Observe this to subscribe to its value and future changes. + * @example Example observe the data of a state + * const myState = new UmbArrayState('Hello world'); + * + * this.observe(myState, (latestStateValue) => console.log("Value is: ", latestStateValue)); + */ + public asObservable(): ReturnType['asObservable']> { + return this._subject.asObservable(); + } + + /** + * @property value + * @description - Holds the current data of this state. + * @example Example retrieve the current data of a state + * const myState = new UmbArrayState('Hello world'); + * console.log("Value is: ", myState.getValue()); + */ + public get value(): BehaviorSubject['value'] { + return this._subject.value; + }; + + /** + * @method getValue + * @return {T} The current data of this state. + * @description - Provides the current data of this state. + * @example Example retrieve the current data of a state + * const myState = new UmbArrayState('Hello world'); + * console.log("Value is: ", myState.value); + */ + public getValue(): ReturnType['getValue']> { + return this._subject.getValue(); + } + + /** + * @method destroy + * @description - Destroys this state and completes all observations made to it. + */ + public destroy(): void { + this._subject.complete(); } + /** + * @method next + * @param {T} data - The next set of data for this state to hold. + * @description - Set the data of this state, if data is different than current this will trigger observations to update. + * @example Example retrieve the current data of a state + * const myState = new UmbArrayState('Good morning'); + * // myState.value is equal 'Good morning'. + * myState.next('Goodnight') + * // myState.value is equal 'Goodnight'. + */ next(newData: T): void { - if (newData !== this.getValue()) { - super.next(newData); + if (newData !== this._subject.getValue()) { + this._subject.next(newData); } } } diff --git a/src/libs/observable-api/boolean-state.ts b/src/libs/observable-api/boolean-state.ts index d470484376..ce7acf7773 100644 --- a/src/libs/observable-api/boolean-state.ts +++ b/src/libs/observable-api/boolean-state.ts @@ -3,8 +3,8 @@ import { UmbBasicState } from './basic-state.js'; /** * @export * @class UmbBooleanState - * @extends {BehaviorSubject} - * @description - A RxJS BehaviorSubject this Subject ensures the data is unique, not updating any Observes unless there is an actual change of the value. + * @extends {UmbBasicState} + * @description - This state ensures the data is unique, not updating any Observes unless there is an actual change of the value. */ export class UmbBooleanState extends UmbBasicState { constructor(initialData: T | boolean) { diff --git a/src/libs/observable-api/class-state.ts b/src/libs/observable-api/class-state.ts index adfe3d2d80..b67a38e89c 100644 --- a/src/libs/observable-api/class-state.ts +++ b/src/libs/observable-api/class-state.ts @@ -1,4 +1,4 @@ -import { BehaviorSubject } from '@umbraco-cms/backoffice/external/rxjs'; +import { UmbBasicState } from "./basic-state.js"; export interface UmbClassStateData { equal(otherClass: this | undefined): boolean; @@ -7,18 +7,18 @@ export interface UmbClassStateData { /** * @export * @class UmbClassState - * @extends {BehaviorSubject} - * @description - A RxJS BehaviorSubject which can hold class instance which has a equal method to compare in coming instances for changes. + * @extends {UmbBasicState} + * @description - This state can hold class instance which has a equal method to compare in coming instances for changes. */ -export class UmbClassState extends BehaviorSubject { +export class UmbClassState extends UmbBasicState { constructor(initialData: T) { super(initialData); } next(newData: T): void { - const oldValue = this.getValue(); + const oldValue = this._subject.getValue(); if (newData && oldValue?.equal(newData)) return; - super.next(newData); + this._subject.next(newData); } } diff --git a/src/libs/observable-api/create-observable-part.function.ts b/src/libs/observable-api/create-observable-part.function.ts index 446f8517df..e1c63ded17 100644 --- a/src/libs/observable-api/create-observable-part.function.ts +++ b/src/libs/observable-api/create-observable-part.function.ts @@ -15,11 +15,11 @@ import { distinctUntilChanged, map, Observable, shareReplay } from '@umbraco-cms */ export function createObservablePart( - source$: Observable, + source: Observable, mappingFunction: MappingFunction, memoizationFunction?: MemoizationFunction ): Observable { - return source$.pipe( + return source.pipe( map(mappingFunction), distinctUntilChanged(memoizationFunction || defaultMemoization), shareReplay(1) diff --git a/src/libs/observable-api/deep-state.ts b/src/libs/observable-api/deep-state.ts index 3da9fb69dc..7bbe0bfc9e 100644 --- a/src/libs/observable-api/deep-state.ts +++ b/src/libs/observable-api/deep-state.ts @@ -1,9 +1,9 @@ +import { UmbBasicState } from './basic-state.js'; import { createObservablePart } from './create-observable-part.function.js'; import { deepFreeze } from './deep-freeze.function.js'; import type { MappingFunction } from './mapping-function.js'; import type { MemoizationFunction } from './memoization-function.js'; import { naiveObjectComparison } from './naive-object-comparison.js'; -import { BehaviorSubject } from '@umbraco-cms/backoffice/external/rxjs'; /** * @export @@ -12,7 +12,8 @@ import { BehaviorSubject } from '@umbraco-cms/backoffice/external/rxjs'; * @description - A RxJS BehaviorSubject which deepFreezes the data to ensure its not manipulated from any implementations. * Additionally the Subject ensures the data is unique, not updating any Observes unless there is an actual change of the content. */ -export class UmbDeepState extends BehaviorSubject { +export class UmbDeepState extends UmbBasicState { + constructor(initialData: T) { super(deepFreeze(initialData)); } @@ -21,14 +22,14 @@ export class UmbDeepState extends BehaviorSubject { mappingFunction: MappingFunction, memoizationFunction?: MemoizationFunction ) { - return createObservablePart(this, mappingFunction, memoizationFunction); + return createObservablePart(this._subject, mappingFunction, memoizationFunction); } next(newData: T): void { const frozenData = deepFreeze(newData); // Only update data if its different than current data. - if (!naiveObjectComparison(frozenData, this.getValue())) { - super.next(frozenData); + if (!naiveObjectComparison(frozenData, this._subject.getValue())) { + this._subject.next(frozenData); } } } diff --git a/src/libs/observable-api/number-state.ts b/src/libs/observable-api/number-state.ts index ff8dce516f..d508418117 100644 --- a/src/libs/observable-api/number-state.ts +++ b/src/libs/observable-api/number-state.ts @@ -4,7 +4,7 @@ import { UmbBasicState } from './basic-state.js'; * @export * @class UmbNumberState * @extends {BehaviorSubject} - * @description - A RxJS BehaviorSubject this Subject ensures the data is unique, not updating any Observes unless there is an actual change of the value. + * @description - State holding data of number, this ensures the data is unique, not updating any Observes unless there is an actual change of the value bu using `===`. */ export class UmbNumberState extends UmbBasicState { constructor(initialData: T | number) { diff --git a/src/libs/observable-api/object-state.ts b/src/libs/observable-api/object-state.ts index d472bfde55..7eb00528b4 100644 --- a/src/libs/observable-api/object-state.ts +++ b/src/libs/observable-api/object-state.ts @@ -21,7 +21,7 @@ export class UmbObjectState extends UmbDeepState { * myState.update({value: 'myNewValue'}); */ update(partialData: Partial) { - this.next({ ...this.getValue(), ...partialData }); + this.next({ ...this._subject.getValue(), ...partialData }); return this; } } diff --git a/src/libs/observable-api/string-state.ts b/src/libs/observable-api/string-state.ts index fb08c7c89f..d893e5b8ce 100644 --- a/src/libs/observable-api/string-state.ts +++ b/src/libs/observable-api/string-state.ts @@ -4,7 +4,7 @@ import { UmbBasicState } from './basic-state.js'; * @export * @class UmbStringState * @extends {UmbBasicState} - * @description - A RxJS BehaviorSubject this Subject ensures the data is unique, not updating any Observes unless there is an actual change of the value. + * @description - A state holding string data, this ensures the data is unique, not updating any Observes unless there is an actual change of the value, by using `===`. */ export class UmbStringState extends UmbBasicState { constructor(initialData: T | string) { diff --git a/src/packages/core/content-type/content-type-structure-manager.class.ts b/src/packages/core/content-type/content-type-structure-manager.class.ts index add77202a9..fdfcb1467a 100644 --- a/src/packages/core/content-type/content-type-structure-manager.class.ts +++ b/src/packages/core/content-type/content-type-structure-manager.class.ts @@ -452,7 +452,7 @@ export class UmbContentTypePropertyStructureManager { - this.state.unsubscribe(); + this.state.destroy(); }; } diff --git a/src/packages/core/workspace/workspace-property/workspace-property.context.ts b/src/packages/core/workspace/workspace-property/workspace-property.context.ts index 2de1ef1e84..135619f858 100644 --- a/src/packages/core/workspace/workspace-property/workspace-property.context.ts +++ b/src/packages/core/workspace/workspace-property/workspace-property.context.ts @@ -144,7 +144,7 @@ export class UmbWorkspacePropertyContext extends UmbBaseControl } public destroy(): void { - this.#data.unsubscribe(); + this.#data.destroy(); this._providerController.destroy(); // This would also be handled by the controller host, but if someone wanted to replace/remove this context without the host being destroyed. Then we have clean up out selfs here. } } diff --git a/src/packages/core/workspace/workspace-split-view/workspace-split-view.context.ts b/src/packages/core/workspace/workspace-split-view/workspace-split-view.context.ts index b408e5ec7d..cd8966ea93 100644 --- a/src/packages/core/workspace/workspace-split-view/workspace-split-view.context.ts +++ b/src/packages/core/workspace/workspace-split-view/workspace-split-view.context.ts @@ -33,7 +33,7 @@ export class UmbWorkspaceSplitViewContext extends UmbBaseController { this._observeVariant(); }); - this.observe(this.#index, () => { + this.observe(this.index, () => { this._observeVariant(); }); diff --git a/src/packages/dictionary/dictionary/workspace/dictionary-workspace.context.ts b/src/packages/dictionary/dictionary/workspace/dictionary-workspace.context.ts index 6e762a44fe..1a14c0fd4a 100644 --- a/src/packages/dictionary/dictionary/workspace/dictionary-workspace.context.ts +++ b/src/packages/dictionary/dictionary/workspace/dictionary-workspace.context.ts @@ -89,7 +89,7 @@ export class UmbDictionaryWorkspaceContext } public destroy(): void { - this.#data.complete(); + this.#data.destroy(); } } diff --git a/src/packages/documents/documents/workspace/document-workspace.context.ts b/src/packages/documents/documents/workspace/document-workspace.context.ts index c4fbfb841a..b742f68955 100644 --- a/src/packages/documents/documents/workspace/document-workspace.context.ts +++ b/src/packages/documents/documents/workspace/document-workspace.context.ts @@ -213,7 +213,7 @@ export class UmbDocumentWorkspaceContext } public destroy(): void { - this.#currentData.complete(); + this.#currentData.destroy(); this.structure.destroy(); super.destroy(); } diff --git a/src/packages/health-check/views/health-check-group-box-overview.element.ts b/src/packages/health-check/views/health-check-group-box-overview.element.ts index 3e360ee1d0..33f8a59cc2 100644 --- a/src/packages/health-check/views/health-check-group-box-overview.element.ts +++ b/src/packages/health-check/views/health-check-group-box-overview.element.ts @@ -33,9 +33,11 @@ export class UmbHealthCheckGroupBoxOverviewElement extends UmbLitElement { if (!this._healthCheckContext || !this.manifest?.meta.label) return; this._api = this._healthCheckContext?.apis.get(this.manifest?.meta.label); - this._api?.results.subscribe((results) => { - this._keyResults = results; - }); + if(this._api) { + this.observe(this._api.results, (results) => { + this._keyResults = results; + }, '_observeApiResults'); + } }); } diff --git a/src/packages/health-check/views/health-check-group.element.ts b/src/packages/health-check/views/health-check-group.element.ts index 7c675a017a..e7493d4d48 100644 --- a/src/packages/health-check/views/health-check-group.element.ts +++ b/src/packages/health-check/views/health-check-group.element.ts @@ -47,16 +47,19 @@ export class UmbDashboardHealthCheckGroupElement extends UmbLitElement { this._api = this._healthCheckContext?.apis.get(this.groupName); - this._api?.getGroupChecks(this.groupName); + if(this._api) { + this._api.getGroupChecks(this.groupName); - this._api?.checks.subscribe((group) => { - this._checks = group?.checks; - this._group = group; - }); + this.observe(this._api.checks, (group) => { + this._checks = group?.checks; + this._group = group; + }); - this._api?.results.subscribe((results) => { - this._idResults = results?.checks; - }); + this.observe(this._api.results, (results) => { + this._idResults = results?.checks; + }); + + } }); } diff --git a/src/packages/log-viewer/workspace/logviewer.context.ts b/src/packages/log-viewer/workspace/logviewer.context.ts index ce20d85c0a..85f19d7ce8 100644 --- a/src/packages/log-viewer/workspace/logviewer.context.ts +++ b/src/packages/log-viewer/workspace/logviewer.context.ts @@ -2,8 +2,6 @@ import { UmbLogViewerRepository } from '../repository/log-viewer.repository.js'; import { UmbBasicState, UmbArrayState, - createObservablePart, - UmbDeepState, UmbObjectState, UmbStringState, } from '@umbraco-cms/backoffice/observable-api'; @@ -73,41 +71,41 @@ export class UmbLogViewerWorkspaceContext extends UmbBaseController implements U }; #savedSearches = new UmbObjectState(undefined); - savedSearches = createObservablePart(this.#savedSearches, (data) => data?.items); + savedSearches = this.#savedSearches.asObservablePart((data) => data?.items); - #logCount = new UmbDeepState(null); - logCount = createObservablePart(this.#logCount, (data) => data); + #logCount = new UmbObjectState(null); + logCount = this.#logCount.asObservable(); - #dateRange = new UmbDeepState(this.defaultDateRange); - dateRange = createObservablePart(this.#dateRange, (data) => data); + #dateRange = new UmbObjectState(this.defaultDateRange); + dateRange = this.#dateRange.asObservable(); - #loggers = new UmbDeepState(null); - loggers = createObservablePart(this.#loggers, (data) => data?.items); + #loggers = new UmbObjectState(null); + loggers = this.#loggers.asObservablePart((data) => data?.items); #canShowLogs = new UmbBasicState(null); - canShowLogs = createObservablePart(this.#canShowLogs, (data) => data); + canShowLogs = this.#canShowLogs.asObservable(); #isLoadingLogs = new UmbBasicState(null); - isLoadingLogs = createObservablePart(this.#isLoadingLogs, (data) => data); + isLoadingLogs = this.#isLoadingLogs.asObservable(); #filterExpression = new UmbStringState(''); - filterExpression = createObservablePart(this.#filterExpression, (data) => data); + filterExpression = this.#filterExpression.asObservable(); - #messageTemplates = new UmbDeepState(null); - messageTemplates = createObservablePart(this.#messageTemplates, (data) => data); + #messageTemplates = new UmbObjectState(null); + messageTemplates = this.#messageTemplates.asObservable(); #logLevelsFilter = new UmbArrayState([]); - logLevelsFilter = createObservablePart(this.#logLevelsFilter, (data) => data); + logLevelsFilter = this.#logLevelsFilter.asObservable(); - #logs = new UmbDeepState(null); - logs = createObservablePart(this.#logs, (data) => data?.items); - logsTotal = createObservablePart(this.#logs, (data) => data?.total); + #logs = new UmbObjectState(null); + logs = this.#logs.asObservablePart((data) => data?.items); + logsTotal = this.#logs.asObservablePart((data) => data?.total); #polling = new UmbObjectState({ enabled: false, interval: 2000 }); - polling = createObservablePart(this.#polling, (data) => data); + polling = this.#polling.asObservable(); #sortingDirection = new UmbBasicState(DirectionModel.ASCENDING); - sortingDirection = createObservablePart(this.#sortingDirection, (data) => data); + sortingDirection = this.#sortingDirection.asObservable(); #intervalID: number | null = null; diff --git a/src/packages/media/media-types/workspace/media-type-workspace.context.ts b/src/packages/media/media-types/workspace/media-type-workspace.context.ts index 0c9a887378..7da542eca1 100644 --- a/src/packages/media/media-types/workspace/media-type-workspace.context.ts +++ b/src/packages/media/media-types/workspace/media-type-workspace.context.ts @@ -74,7 +74,7 @@ export class UmbMediaTypeWorkspaceContext } public destroy(): void { - this.#data.complete(); + this.#data.destroy(); } } diff --git a/src/packages/media/media/workspace/media-workspace.context.ts b/src/packages/media/media/workspace/media-workspace.context.ts index 8d5148c25b..9eb0391345 100644 --- a/src/packages/media/media/workspace/media-workspace.context.ts +++ b/src/packages/media/media/workspace/media-workspace.context.ts @@ -79,7 +79,7 @@ export class UmbMediaWorkspaceContext } public destroy(): void { - this.#data.complete(); + this.#data.destroy(); } } diff --git a/src/packages/members/member-groups/workspace/member-group-workspace.context.ts b/src/packages/members/member-groups/workspace/member-group-workspace.context.ts index 73ae447b63..7dd14b2039 100644 --- a/src/packages/members/member-groups/workspace/member-group-workspace.context.ts +++ b/src/packages/members/member-groups/workspace/member-group-workspace.context.ts @@ -61,7 +61,7 @@ export class UmbMemberGroupWorkspaceContext } public destroy(): void { - this.#data.complete(); + this.#data.destroy(); } } diff --git a/src/packages/members/member-types/workspace/member-type-workspace.context.ts b/src/packages/members/member-types/workspace/member-type-workspace.context.ts index 49994e0df6..760ca83cb5 100644 --- a/src/packages/members/member-types/workspace/member-type-workspace.context.ts +++ b/src/packages/members/member-types/workspace/member-type-workspace.context.ts @@ -71,7 +71,7 @@ export class UmbMemberTypeWorkspaceContext } public destroy(): void { - this.#data.complete(); + this.#data.destroy(); } } diff --git a/src/packages/members/members/member.detail.store.ts b/src/packages/members/members/member.detail.store.ts index 09a6a53b2c..3b5994db10 100644 --- a/src/packages/members/members/member.detail.store.ts +++ b/src/packages/members/members/member.detail.store.ts @@ -40,7 +40,7 @@ export class UmbMemberStore extends UmbStoreBase implements UmbEntityDetailStore this._data.appendOne(member); } - return createObservablePart(this._data, (members) => members.find((member) => member.id === id) as MemberDetails); + return this._data.asObservablePart((members) => members.find((member) => member.id === id) as MemberDetails); } async save(member: Array): Promise { diff --git a/src/packages/packages/package/repository/server-extension.controller.ts b/src/packages/packages/package/repository/server-extension.controller.ts index 00619bf058..d18cd6044c 100644 --- a/src/packages/packages/package/repository/server-extension.controller.ts +++ b/src/packages/packages/package/repository/server-extension.controller.ts @@ -1,12 +1,10 @@ import { UmbPackageRepository } from './package.repository.js'; -import { Subject, takeUntil } from '@umbraco-cms/backoffice/external/rxjs'; import { UmbBaseController, UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; import { UmbBackofficeExtensionRegistry } from '@umbraco-cms/backoffice/extension-registry'; export class UmbExtensionInitializer extends UmbBaseController { - #host: UmbControllerHostElement; + #extensionRegistry: UmbBackofficeExtensionRegistry; - #unobserve = new Subject(); #repository: UmbPackageRepository; #localPackages: Array>; @@ -16,7 +14,7 @@ export class UmbExtensionInitializer extends UmbBaseController { localPackages: Array> ) { super(host, UmbExtensionInitializer.name); - this.#host = host; + this.#extensionRegistry = extensionRegistry; this.#repository = new UmbPackageRepository(host); this.#localPackages = localPackages; @@ -28,8 +26,7 @@ export class UmbExtensionInitializer extends UmbBaseController { } hostDisconnected(): void { - this.#unobserve.next(); - this.#unobserve.complete(); + this.removeControllerByAlias('_observeExtensions'); } async #loadLocalPackages() { @@ -40,13 +37,8 @@ export class UmbExtensionInitializer extends UmbBaseController { } async #loadServerPackages() { - const extensions$ = await this.#repository.extensions(); - - extensions$ - .pipe( - // If the app breaks then stop the request - takeUntil(this.#unobserve) - ) - .subscribe((extensions) => this.#extensionRegistry.registerMany(extensions)); + const extensions = await this.#repository.extensions(); + + this.observe(extensions, (extensions) => this.#extensionRegistry.registerMany(extensions), '_observeExtensions'); } } diff --git a/src/packages/settings/data-types/workspace/data-type-workspace.context.ts b/src/packages/settings/data-types/workspace/data-type-workspace.context.ts index fd3cf35957..8c91ba0078 100644 --- a/src/packages/settings/data-types/workspace/data-type-workspace.context.ts +++ b/src/packages/settings/data-types/workspace/data-type-workspace.context.ts @@ -256,7 +256,7 @@ export class UmbDataTypeWorkspaceContext } public destroy(): void { - this.#data.complete(); + this.#data.destroy(); } } diff --git a/src/packages/settings/languages/workspace/language/language-workspace.context.ts b/src/packages/settings/languages/workspace/language/language-workspace.context.ts index b749c5f662..ba5ea55a24 100644 --- a/src/packages/settings/languages/workspace/language/language-workspace.context.ts +++ b/src/packages/settings/languages/workspace/language/language-workspace.context.ts @@ -98,7 +98,7 @@ export class UmbLanguageWorkspaceContext } destroy(): void { - this.#data.complete(); + this.#data.destroy(); } } diff --git a/src/packages/settings/relation-types/workspace/relation-type-workspace.context.ts b/src/packages/settings/relation-types/workspace/relation-type-workspace.context.ts index b871b61208..11d85995f4 100644 --- a/src/packages/settings/relation-types/workspace/relation-type-workspace.context.ts +++ b/src/packages/settings/relation-types/workspace/relation-type-workspace.context.ts @@ -73,7 +73,7 @@ export class UmbRelationTypeWorkspaceContext } public destroy(): void { - this.#data.complete(); + this.#data.destroy(); } } diff --git a/src/packages/templating/code-editor/code-editor.element.ts b/src/packages/templating/code-editor/code-editor.element.ts index d74d7fa607..fd1750db69 100644 --- a/src/packages/templating/code-editor/code-editor.element.ts +++ b/src/packages/templating/code-editor/code-editor.element.ts @@ -99,9 +99,9 @@ export class UmbCodeEditorElement extends UmbLitElement implements UmbCodeEditor constructor() { super(); this.consumeContext(UMB_THEME_CONTEXT_TOKEN, (instance) => { - instance.theme.subscribe((themeAlias) => { + this.observe(instance.theme, (themeAlias) => { this.theme = themeAlias ? this.#translateTheme(themeAlias) : CodeEditorTheme.Light; - }); + }, '_observeTheme'); }); } diff --git a/src/packages/templating/code-editor/code-editor.stories.ts b/src/packages/templating/code-editor/code-editor.stories.ts index 2d76d9f972..c56a254a31 100644 --- a/src/packages/templating/code-editor/code-editor.stories.ts +++ b/src/packages/templating/code-editor/code-editor.stories.ts @@ -113,15 +113,15 @@ const codeSnippets: Record = { "Smartypants, double quotes" and 'single quotes'`, typescript: `import { UmbTemplateRepository } from '../repository/template.repository.js'; import { UmbWorkspaceContext } from '../../../shared/components/workspace/workspace-context/workspace-context.js'; - import { createObservablePart, UmbDeepState } from '@umbraco-cms/observable-api'; + import { UmbObjectState } from '@umbraco-cms/observable-api'; import { TemplateModel } from '@umbraco-cms/backend-api'; import { UmbControllerHostElement } from '@umbraco-cms/controller'; export class UmbTemplateWorkspaceContext extends UmbWorkspaceContext { - #data = new UmbDeepState(undefined); + #data = new UmbObjectState(undefined); data = this.#data.asObservable(); - name = createObservablePart(this.#data, (data) => data?.name); - content = createObservablePart(this.#data, (data) => data?.content); + name = this.#data.asObservablePart((data) => data?.name); + content = this.#data.asObservablePart((data) => data?.content); constructor(host: UmbControllerHostElement) { super(host, 'Umb.Workspace.Template', new UmbTemplateRepository(host)); diff --git a/src/packages/templating/partial-views/workspace/partial-view-workspace.context.ts b/src/packages/templating/partial-views/workspace/partial-view-workspace.context.ts index e333029321..8c69431124 100644 --- a/src/packages/templating/partial-views/workspace/partial-view-workspace.context.ts +++ b/src/packages/templating/partial-views/workspace/partial-view-workspace.context.ts @@ -44,9 +44,9 @@ export class UmbPartialViewWorkspaceContext extends UmbWorkspaceContext< #data = new UmbDeepState(undefined); data = this.#data.asObservable(); - name = createObservablePart(this.#data, (data) => data?.name); - content = createObservablePart(this.#data, (data) => data?.content); - path = createObservablePart(this.#data, (data) => data?.path); + name = this.#data.asObservablePart((data) => data?.name); + content = this.#data.asObservablePart((data) => data?.content); + path = this.#data.asObservablePart((data) => data?.path); #isCodeEditorReady = new UmbBooleanState(false); isCodeEditorReady = this.#isCodeEditorReady.asObservable(); diff --git a/src/packages/templating/scripts/workspace/scripts-workspace.context.ts b/src/packages/templating/scripts/workspace/scripts-workspace.context.ts index 13fcc1d344..224ad7d7e7 100644 --- a/src/packages/templating/scripts/workspace/scripts-workspace.context.ts +++ b/src/packages/templating/scripts/workspace/scripts-workspace.context.ts @@ -1,6 +1,6 @@ import { ScriptDetails, SCRIPTS_WORKSPACE_ALIAS } from '../config.js'; import { UmbScriptsRepository } from '../repository/scripts.repository.js'; -import { createObservablePart, UmbBooleanState, UmbDeepState } from '@umbraco-cms/backoffice/observable-api'; +import { UmbBooleanState, UmbDeepState } from '@umbraco-cms/backoffice/observable-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; import { UmbWorkspaceContext } from '@umbraco-cms/backoffice/workspace'; import { loadCodeEditor } from '@umbraco-cms/backoffice/code-editor'; @@ -9,9 +9,9 @@ import { TextFileResponseModelBaseModel, UpdateScriptRequestModel } from '@umbra export class UmbScriptsWorkspaceContext extends UmbWorkspaceContext { #data = new UmbDeepState(undefined); data = this.#data.asObservable(); - name = createObservablePart(this.#data, (data) => data?.name); - content = createObservablePart(this.#data, (data) => data?.content); - path = createObservablePart(this.#data, (data) => data?.path); + name = this.#data.asObservablePart((data) => data?.name); + content = this.#data.asObservablePart((data) => data?.content); + path = this.#data.asObservablePart((data) => data?.path); #isCodeEditorReady = new UmbBooleanState(false); isCodeEditorReady = this.#isCodeEditorReady.asObservable(); diff --git a/src/packages/templating/stylesheets/workspace/stylesheet-workspace.context.ts b/src/packages/templating/stylesheets/workspace/stylesheet-workspace.context.ts index 9462b846a6..ca05d25fe0 100644 --- a/src/packages/templating/stylesheets/workspace/stylesheet-workspace.context.ts +++ b/src/packages/templating/stylesheets/workspace/stylesheet-workspace.context.ts @@ -5,8 +5,7 @@ import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api import { UmbArrayState, UmbBooleanState, - UmbObjectState, - createObservablePart, + UmbObjectState } from '@umbraco-cms/backoffice/observable-api'; import { loadCodeEditor } from '@umbraco-cms/backoffice/code-editor'; import { RichTextRuleModel, UpdateStylesheetRequestModel } from '@umbraco-cms/backoffice/backend-api'; @@ -22,9 +21,9 @@ export class UmbStylesheetWorkspaceContext #rules = new UmbArrayState([], (rule) => rule.name); data = this.#data.asObservable(); rules = this.#rules.asObservable(); - name = createObservablePart(this.#data, (data) => data?.name); - content = createObservablePart(this.#data, (data) => data?.content); - path = createObservablePart(this.#data, (data) => data?.path); + name = this.#data.asObservablePart((data) => data?.name); + content = this.#data.asObservablePart((data) => data?.content); + path = this.#data.asObservablePart((data) => data?.path); #isCodeEditorReady = new UmbBooleanState(false); isCodeEditorReady = this.#isCodeEditorReady.asObservable(); @@ -180,7 +179,7 @@ export class UmbStylesheetWorkspaceContext } public destroy(): void { - this.#data.complete(); + this.#data.destroy(); } } diff --git a/src/packages/templating/templates/workspace/template-workspace.context.ts b/src/packages/templating/templates/workspace/template-workspace.context.ts index 3513ae3800..fdaefaf947 100644 --- a/src/packages/templating/templates/workspace/template-workspace.context.ts +++ b/src/packages/templating/templates/workspace/template-workspace.context.ts @@ -16,11 +16,11 @@ export class UmbTemplateWorkspaceContext extends UmbWorkspaceContext(null); masterTemplate = this.#masterTemplate.asObservable(); - name = createObservablePart(this.#data, (data) => data?.name); - alias = createObservablePart(this.#data, (data) => data?.alias); - content = createObservablePart(this.#data, (data) => data?.content); - id = createObservablePart(this.#data, (data) => data?.id); - masterTemplateID = createObservablePart(this.#data, (data) => data?.masterTemplateId); + name = this.#data.asObservablePart((data) => data?.name); + alias = this.#data.asObservablePart((data) => data?.alias); + content = this.#data.asObservablePart((data) => data?.content); + id = this.#data.asObservablePart((data) => data?.id); + masterTemplateID = this.#data.asObservablePart((data) => data?.masterTemplateId); #isCodeEditorReady = new UmbBooleanState(false); isCodeEditorReady = this.#isCodeEditorReady.asObservable(); @@ -163,7 +163,7 @@ ${currentContent}`; } public destroy() { - this.#data.complete(); + this.#data.destroy(); super.destroy(); } } diff --git a/src/packages/user/current-user/user-profile-apps/user-profile-app-themes.element.ts b/src/packages/user/current-user/user-profile-apps/user-profile-app-themes.element.ts index 1c2e0d10c1..1606a0b8bb 100644 --- a/src/packages/user/current-user/user-profile-apps/user-profile-app-themes.element.ts +++ b/src/packages/user/current-user/user-profile-apps/user-profile-app-themes.element.ts @@ -6,7 +6,7 @@ import { ManifestTheme, umbExtensionsRegistry } from '@umbraco-cms/backoffice/ex @customElement('umb-user-profile-app-themes') export class UmbUserProfileAppThemesElement extends UmbLitElement { - #themeService?: UmbThemeContext; + #themeContext?: UmbThemeContext; @state() private _themeAlias: string | null = null; @@ -16,24 +16,24 @@ export class UmbUserProfileAppThemesElement extends UmbLitElement { constructor() { super(); - this.consumeContext(UMB_THEME_CONTEXT_TOKEN, (instance) => { - this.#themeService = instance; - instance.theme.subscribe((themeAlias) => { + this.consumeContext(UMB_THEME_CONTEXT_TOKEN, (context) => { + this.#themeContext = context; + this.observe(context.theme, (themeAlias) => { this._themeAlias = themeAlias; - }); + }, '_observeCurrentTheme'); - umbExtensionsRegistry.extensionsOfType('theme').subscribe((themes) => { + this.observe(umbExtensionsRegistry.extensionsOfType('theme'), (themes) => { this._themes = themes; - }); + }, '_observeThemeExtensions'); }); } #handleThemeChange(event: UUISelectEvent) { - if (!this.#themeService) return; + if (!this.#themeContext) return; const theme = event.target.value.toString(); - this.#themeService.setThemeByAlias(theme); + this.#themeContext.setThemeByAlias(theme); } get #options() { diff --git a/src/packages/user/user-group/workspace/user-group-workspace.context.ts b/src/packages/user/user-group/workspace/user-group-workspace.context.ts index 488a2efb1e..04d94822d8 100644 --- a/src/packages/user/user-group/workspace/user-group-workspace.context.ts +++ b/src/packages/user/user-group/workspace/user-group-workspace.context.ts @@ -93,7 +93,7 @@ export class UmbUserGroupWorkspaceContext } destroy(): void { - this.#data.complete(); + this.#data.destroy(); } async delete(id: string) { diff --git a/src/packages/user/user/workspace/user-workspace.context.ts b/src/packages/user/user/workspace/user-workspace.context.ts index 1ea014f0e9..055a83d351 100644 --- a/src/packages/user/user/workspace/user-workspace.context.ts +++ b/src/packages/user/user/workspace/user-workspace.context.ts @@ -35,7 +35,7 @@ export class UmbUserWorkspaceContext this.observe(asObservable(), (user) => this.onUserStoreChanges(user), 'umbUserStoreObserver'); } - /* TODO: some properties are allowed to update without saving. + /* TODO: some properties are allowed to update without saving. For a user properties like state will be updated when one of the entity actions are executed. Therefore we have to subscribe to the user store to update the state in the workspace data. There might be a less manual way to do this. @@ -90,7 +90,7 @@ export class UmbUserWorkspaceContext } destroy(): void { - this.#data.complete(); + this.#data.destroy(); } } diff --git a/src/shared/auth/auth.context.ts b/src/shared/auth/auth.context.ts index d17f9e68c9..7c45ea7793 100644 --- a/src/shared/auth/auth.context.ts +++ b/src/shared/auth/auth.context.ts @@ -2,27 +2,27 @@ import { IUmbAuth } from './auth.interface.js'; import { UmbAuthFlow } from './auth-flow.js'; import { UmbLoggedInUser } from './types.js'; import { UserResource } from '@umbraco-cms/backoffice/backend-api'; -import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; +import { UmbBaseController, UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; import { UmbBooleanState, UmbObjectState } from '@umbraco-cms/backoffice/observable-api'; import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; import { firstValueFrom } from '@umbraco-cms/backoffice/external/rxjs'; -export class UmbAuthContext implements IUmbAuth { +export class UmbAuthContext extends UmbBaseController implements IUmbAuth { #currentUser = new UmbObjectState(undefined); readonly currentUser = this.#currentUser.asObservable(); - - readonly isLoggedIn = new UmbBooleanState(false); + + #isLoggedIn = new UmbBooleanState(false); + readonly isLoggedIn = this.#isLoggedIn.asObservable(); readonly languageIsoCode = this.#currentUser.asObservablePart((user) => user?.languageIsoCode ?? 'en-us'); - #host; #authFlow; constructor(host: UmbControllerHostElement, serverUrl: string, redirectUrl: string) { - this.#host = host; + super(host) this.#authFlow = new UmbAuthFlow(serverUrl, redirectUrl); - this.isLoggedIn.subscribe((isLoggedIn) => { + this.observe(this.isLoggedIn, (isLoggedIn) => { if (isLoggedIn) { this.fetchCurrentUser(); } @@ -36,6 +36,11 @@ export class UmbAuthContext implements IUmbAuth { return this.#authFlow.makeAuthorizationRequest(); } + /* TEMPORARY METHOD UNTIL RESPONSIBILITY IS MOVED TO CONTEXT */ + setLoggedIn(newValue: boolean): void { + return this.#isLoggedIn.next(newValue); + } + isAuthorized() { return this.#authFlow.isAuthorized(); } @@ -45,7 +50,7 @@ export class UmbAuthContext implements IUmbAuth { } async fetchCurrentUser(): Promise { - const { data } = await tryExecuteAndNotify(this.#host, UserResource.getUserCurrent()); + const { data } = await tryExecuteAndNotify(this._host, UserResource.getUserCurrent()); this.#currentUser.next(data);