Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Isolate RxJS #970

Merged
merged 20 commits into from
Nov 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/apps/app/app.element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,9 @@
// 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;
Expand Down Expand Up @@ -134,7 +134,7 @@
// 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) {
Expand All @@ -153,7 +153,7 @@

// TODO: wrap all debugging logic in a separate class. Maybe this could be part of the context-api? When we create a new root, we could attach the debugger to it?
// Listen for the debug event from the <umb-debug> component
this.addEventListener(umbDebugContextEventType, (event: any) => {

Check warning on line 156 in src/apps/app/app.element.ts

View workflow job for this annotation

GitHub Actions / build (20)

Unexpected any. Specify a different type
// Once we got to the outter most component <umb-app>
// we can send the event containing all the contexts
// we have collected whilst coming up through the DOM
Expand Down Expand Up @@ -186,7 +186,7 @@
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
Expand All @@ -200,9 +200,9 @@
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);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/libs/class-api/class.mixin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type UmbClassMixinConstructor = new (
declare class UmbClassMixinDeclaration implements UmbClassMixinInterface {
_host: UmbControllerHost;
observe<T>(
source: Observable<T> | { asObservable: () => Observable<T> },
source: Observable<T>,
callback: (_value: T) => void,
controllerAlias?: UmbControllerAlias
): UmbObserverController<T>;
Expand Down
69 changes: 63 additions & 6 deletions src/libs/observable-api/basic-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,74 @@ import { BehaviorSubject } from '@umbraco-cms/backoffice/external/rxjs';
/**
* @export
* @class UmbBasicState
* @extends {BehaviorSubject<T>}
* @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<T> extends BehaviorSubject<T> {
export class UmbBasicState<T> {

protected _subject:BehaviorSubject<T>;

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 <caption>Example observe the data of a state</caption>
* const myState = new UmbArrayState('Hello world');
*
* this.observe(myState, (latestStateValue) => console.log("Value is: ", latestStateValue));
*/
public asObservable(): ReturnType<BehaviorSubject<T>['asObservable']> {
return this._subject.asObservable();
}

/**
* @property value
* @description - Holds the current data of this state.
* @example <caption>Example retrieve the current data of a state</caption>
* const myState = new UmbArrayState('Hello world');
* console.log("Value is: ", myState.getValue());
*/
public get value(): BehaviorSubject<T>['value'] {
return this._subject.value;
};

/**
* @method getValue
* @return {T} The current data of this state.
* @description - Provides the current data of this state.
* @example <caption>Example retrieve the current data of a state</caption>
* const myState = new UmbArrayState('Hello world');
* console.log("Value is: ", myState.value);
*/
public getValue(): ReturnType<BehaviorSubject<T>['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 <caption>Example retrieve the current data of a state</caption>
* 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);
}
}
}
4 changes: 2 additions & 2 deletions src/libs/observable-api/boolean-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { UmbBasicState } from './basic-state.js';
/**
* @export
* @class UmbBooleanState
* @extends {BehaviorSubject<T>}
* @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<T>}
* @description - This state ensures the data is unique, not updating any Observes unless there is an actual change of the value.
*/
export class UmbBooleanState<T> extends UmbBasicState<T | boolean> {
constructor(initialData: T | boolean) {
Expand Down
12 changes: 6 additions & 6 deletions src/libs/observable-api/class-state.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -7,18 +7,18 @@ export interface UmbClassStateData {
/**
* @export
* @class UmbClassState
* @extends {BehaviorSubject<T>}
* @description - A RxJS BehaviorSubject which can hold class instance which has a equal method to compare in coming instances for changes.
* @extends {UmbBasicState<T>}
* @description - This state can hold class instance which has a equal method to compare in coming instances for changes.
*/
export class UmbClassState<T extends UmbClassStateData | undefined> extends BehaviorSubject<T> {
export class UmbClassState<T extends UmbClassStateData | undefined> extends UmbBasicState<T> {
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);
}
}
4 changes: 2 additions & 2 deletions src/libs/observable-api/create-observable-part.function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ import { distinctUntilChanged, map, Observable, shareReplay } from '@umbraco-cms
*/

export function createObservablePart<R, T>(
source$: Observable<T>,
source: Observable<T>,
mappingFunction: MappingFunction<T, R>,
memoizationFunction?: MemoizationFunction<R>
): Observable<R> {
return source$.pipe(
return source.pipe(
map(mappingFunction),
distinctUntilChanged(memoizationFunction || defaultMemoization),
shareReplay(1)
Expand Down
11 changes: 6 additions & 5 deletions src/libs/observable-api/deep-state.ts
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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<T> extends BehaviorSubject<T> {
export class UmbDeepState<T> extends UmbBasicState<T> {

constructor(initialData: T) {
super(deepFreeze(initialData));
}
Expand All @@ -21,14 +22,14 @@ export class UmbDeepState<T> extends BehaviorSubject<T> {
mappingFunction: MappingFunction<T, ReturnType>,
memoizationFunction?: MemoizationFunction<ReturnType>
) {
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);
}
}
}
2 changes: 1 addition & 1 deletion src/libs/observable-api/number-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { UmbBasicState } from './basic-state.js';
* @export
* @class UmbNumberState
* @extends {BehaviorSubject<T>}
* @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<T> extends UmbBasicState<T | number> {
constructor(initialData: T | number) {
Expand Down
2 changes: 1 addition & 1 deletion src/libs/observable-api/object-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export class UmbObjectState<T> extends UmbDeepState<T> {
* myState.update({value: 'myNewValue'});
*/
update(partialData: Partial<T>) {
this.next({ ...this.getValue(), ...partialData });
this.next({ ...this._subject.getValue(), ...partialData });
return this;
}
}
2 changes: 1 addition & 1 deletion src/libs/observable-api/string-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { UmbBasicState } from './basic-state.js';
* @export
* @class UmbStringState
* @extends {UmbBasicState<T>}
* @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<T> extends UmbBasicState<T | string> {
constructor(initialData: T | string) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,7 @@ export class UmbContentTypePropertyStructureManager<R extends UmbDetailRepositor
}
public destroy() {
this._reset();
this.#contentTypes.complete();
this.#containers.complete();
this.#contentTypes.destroy();
this.#containers.destroy();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,6 @@ export class UmbEntityWorkspaceManager<
};

public destroy = (): void => {
this.state.unsubscribe();
this.state.destroy();
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ export class UmbWorkspacePropertyContext<ValueType = any> 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.
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export class UmbWorkspaceSplitViewContext extends UmbBaseController {
this._observeVariant();
});

this.observe(this.#index, () => {
this.observe(this.index, () => {
this._observeVariant();
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export class UmbDictionaryWorkspaceContext
}

public destroy(): void {
this.#data.complete();
this.#data.destroy();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ export class UmbDocumentWorkspaceContext
}

public destroy(): void {
this.#currentData.complete();
this.#currentData.destroy();
this.structure.destroy();
super.destroy();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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');
}
});
}

Expand Down
19 changes: 11 additions & 8 deletions src/packages/health-check/views/health-check-group.element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
});

}
});
}

Expand Down
Loading
Loading