Merge remote-tracking branch 'origin/main' into feature/auth-app
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* @export
|
||||
* @method appendToFrozenArray
|
||||
* @param {Observable<T>} source - RxJS Subject to use for this Observable.
|
||||
* @param {(mappable: T) => R} mappingFunction - Method to return the part for this Observable to return.
|
||||
* @param {(previousResult: R, currentResult: R) => boolean} [memoizationFunction] - Method to Compare if the data has changed. Should return true when data is different.
|
||||
* @description - Creates a RxJS Observable from RxJS Subject.
|
||||
* @example <caption>Example append new entry for a UniqueBehaviorSubject which is an array. Where the key is unique and the item will be updated if matched with existing.</caption>
|
||||
* const entry = {key: 'myKey', value: 'myValue'};
|
||||
* const newDataSet = appendToFrozenArray(mySubject.getValue(), entry, x => x.key === key);
|
||||
* mySubject.next(newDataSet);
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export function appendToFrozenArray<T>(data: T[], entry: T, getUniqueMethod?: (entry: T) => unknown): T[] {
|
||||
const unFrozenDataSet = [...data];
|
||||
if (getUniqueMethod) {
|
||||
const unique = getUniqueMethod(entry);
|
||||
const indexToReplace = unFrozenDataSet.findIndex((x) => getUniqueMethod(x) === unique);
|
||||
if (indexToReplace !== -1) {
|
||||
unFrozenDataSet[indexToReplace] = entry;
|
||||
} else {
|
||||
unFrozenDataSet.push(entry);
|
||||
}
|
||||
} else {
|
||||
unFrozenDataSet.push(entry);
|
||||
}
|
||||
return unFrozenDataSet;
|
||||
}
|
||||
@@ -4,3 +4,4 @@ export * from './unique-behavior-subject';
|
||||
export * from './unique-array-behavior-subject';
|
||||
export * from './unique-object-behavior-subject';
|
||||
export * from './create-observable-part.method'
|
||||
export * from './append-to-frozen-array.method'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { expect } from '@open-wc/testing';
|
||||
import { createObservablePart } from '@umbraco-cms/observable-api';
|
||||
import { UniqueArrayBehaviorSubject } from './unique-array-behavior-subject';
|
||||
import { createObservablePart } from '@umbraco-cms/observable-api';
|
||||
|
||||
describe('UniqueArrayBehaviorSubject', () => {
|
||||
|
||||
@@ -16,7 +16,7 @@ describe('UniqueArrayBehaviorSubject', () => {
|
||||
{key: '2', another: 'myValue2'},
|
||||
{key: '3', another: 'myValue3'}
|
||||
];
|
||||
subject = new UniqueArrayBehaviorSubject(initialData, (a, b) => a.key === b.key);
|
||||
subject = new UniqueArrayBehaviorSubject(initialData, x => x.key);
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { appendToFrozenArray, UniqueBehaviorSubject } from "./unique-behavior-subject";
|
||||
import { UniqueBehaviorSubject } from "./unique-behavior-subject";
|
||||
import { appendToFrozenArray } from "./append-to-frozen-array.method";
|
||||
|
||||
/**
|
||||
* @export
|
||||
@@ -13,14 +14,41 @@ import { appendToFrozenArray, UniqueBehaviorSubject } from "./unique-behavior-su
|
||||
export class UniqueArrayBehaviorSubject<T> extends UniqueBehaviorSubject<T[]> {
|
||||
|
||||
|
||||
constructor(initialData: T[], private _uniqueCompare?: (existingEntry: T, newEntry: T) => boolean) {
|
||||
constructor(initialData: T[], private _getUnique?: (entry: T) => unknown) {
|
||||
super(initialData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @method append
|
||||
* @param {unknown} unique - The unique value to remove.
|
||||
* @description - Remove some new data of this Subject.
|
||||
* @example <caption>Example remove entry with key '1'</caption>
|
||||
* const data = [
|
||||
* { key: 1, value: 'foo'},
|
||||
* { key: 2, value: 'bar'}
|
||||
* ];
|
||||
* const mySubject = new UniqueArrayBehaviorSubject(data, (x) => x.key);
|
||||
* mySubject.remove([1]);
|
||||
*/
|
||||
remove(uniques: unknown[]) {
|
||||
const unFrozenDataSet = [...this.getValue()];
|
||||
if (this._getUnique) {
|
||||
uniques.forEach( unique =>
|
||||
unFrozenDataSet.filter(x => {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
return this._getUnique(x) !== unique;
|
||||
})
|
||||
);
|
||||
|
||||
this.next(unFrozenDataSet);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @method append
|
||||
* @param {Partial<T>} partialData - A object containing some of the data for this Subject.
|
||||
* @description - Append some new data to this Object.
|
||||
* @description - Append some new data to this Subject.
|
||||
* @example <caption>Example append some data.</caption>
|
||||
* const data = [
|
||||
* { key: 1, value: 'foo'},
|
||||
@@ -30,13 +58,13 @@ export class UniqueArrayBehaviorSubject<T> extends UniqueBehaviorSubject<T[]> {
|
||||
* mySubject.append({ key: 1, value: 'replaced-foo'});
|
||||
*/
|
||||
appendOne(entry: T) {
|
||||
this.next(appendToFrozenArray(this.getValue(), entry, this._uniqueCompare))
|
||||
this.next(appendToFrozenArray(this.getValue(), entry, this._getUnique))
|
||||
}
|
||||
|
||||
/**
|
||||
* @method append
|
||||
* @param {T[]} entries - A array of new data to be added in this Subject.
|
||||
* @description - Append some new data to this Object, if it compares to existing data it will replace it.
|
||||
* @description - Append some new data to this Subject, if it compares to existing data it will replace it.
|
||||
* @example <caption>Example append some data.</caption>
|
||||
* const data = [
|
||||
* { key: 1, value: 'foo'},
|
||||
@@ -49,6 +77,7 @@ export class UniqueArrayBehaviorSubject<T> extends UniqueBehaviorSubject<T[]> {
|
||||
* ]);
|
||||
*/
|
||||
append(entries: T[]) {
|
||||
// TODO: stop calling appendOne for each but make sure to handle this in one.
|
||||
entries.forEach(x => this.appendOne(x))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,36 +28,6 @@ export function naiveObjectComparison(objOne: any, objTwo: any): boolean {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @export
|
||||
* @method appendToFrozenArray
|
||||
* @param {Observable<T>} source - RxJS Subject to use for this Observable.
|
||||
* @param {(mappable: T) => R} mappingFunction - Method to return the part for this Observable to return.
|
||||
* @param {(previousResult: R, currentResult: R) => boolean} [memoizationFunction] - Method to Compare if the data has changed. Should return true when data is different.
|
||||
* @description - Creates a RxJS Observable from RxJS Subject.
|
||||
* @example <caption>Example append new entry for a UniqueBehaviorSubject which is an array. Where the key is unique and the item will be updated if matched with existing.</caption>
|
||||
* const entry = {key: 'myKey', value: 'myValue'};
|
||||
* const newDataSet = appendToFrozenArray(mySubject.getValue(), entry, x => x.key === key);
|
||||
* mySubject.next(newDataSet);
|
||||
*/
|
||||
export function appendToFrozenArray<T>(data: T[], entry: T, uniqueMethod?: (existingEntry: T, newEntry: T) => boolean): T[] {
|
||||
const unFrozenDataSet = [...data];
|
||||
if(uniqueMethod) {
|
||||
const indexToReplace = unFrozenDataSet.findIndex((x) => uniqueMethod(x, entry));
|
||||
if(indexToReplace !== -1) {
|
||||
unFrozenDataSet[indexToReplace] = entry;
|
||||
} else {
|
||||
unFrozenDataSet.push(entry);
|
||||
}
|
||||
} else {
|
||||
unFrozenDataSet.push(entry);
|
||||
}
|
||||
return unFrozenDataSet;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
export type MappingFunction<T, R> = (mappable: T) => R;
|
||||
export type MemoizationFunction<R> = (previousResult: R, currentResult: R) => boolean;
|
||||
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export * from './icon/icon.store';
|
||||
export * from './store';
|
||||
export * from './store-base';
|
||||
|
||||
11
src/Umbraco.Web.UI.Client/libs/store/store-base.ts
Normal file
11
src/Umbraco.Web.UI.Client/libs/store/store-base.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { UmbContextProviderController } from "../context-api/provide/context-provider.controller";
|
||||
import { UmbControllerHostInterface } from "../controller/controller-host.mixin";
|
||||
|
||||
export class UmbStoreBase {
|
||||
|
||||
|
||||
constructor (protected _host: UmbControllerHostInterface, public readonly storeAlias: string) {
|
||||
new UmbContextProviderController(_host, storeAlias, this);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,94 +1,33 @@
|
||||
import type { Observable } from 'rxjs';
|
||||
import { UniqueBehaviorSubject } from '@umbraco-cms/observable-api';
|
||||
import { UmbControllerHostInterface } from '@umbraco-cms/controller';
|
||||
|
||||
export interface UmbDataStoreIdentifiers {
|
||||
key?: string;
|
||||
[more: string]: any;
|
||||
}
|
||||
|
||||
export interface UmbDataStore<T> {
|
||||
export interface UmbDataStore {
|
||||
readonly storeAlias: string;
|
||||
readonly items: Observable<Array<T>>;
|
||||
updateItems(items: Array<T>): void;
|
||||
}
|
||||
|
||||
export interface UmbTreeDataStore<T> extends UmbDataStore<T> {
|
||||
export interface UmbTreeStore<T> extends UmbDataStore {
|
||||
getTreeRoot(): Observable<Array<T>>;
|
||||
getTreeItemChildren(key: string): Observable<Array<T>>;
|
||||
}
|
||||
|
||||
/**
|
||||
* @export
|
||||
* @class UmbDataStoreBase
|
||||
* @implements {UmbDataStore<T>}
|
||||
* @template T
|
||||
* @description - Base class for Data Stores
|
||||
*/
|
||||
export abstract class UmbDataStoreBase<T extends UmbDataStoreIdentifiers> implements UmbDataStore<T> {
|
||||
public abstract readonly storeAlias: string;
|
||||
|
||||
protected _items = new UniqueBehaviorSubject(<Array<T>>[]);
|
||||
public readonly items = this._items.asObservable();
|
||||
|
||||
protected host: UmbControllerHostInterface;
|
||||
|
||||
constructor(host: UmbControllerHostInterface) {
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description - Delete items from the store.
|
||||
* @param {Array<string>} keys
|
||||
* @memberof UmbDataStoreBase
|
||||
*/
|
||||
public deleteItems(keys: Array<string>): void {
|
||||
const remainingItems = this._items.getValue().filter((item) => item.key && keys.includes(item.key) === false);
|
||||
this._items.next(remainingItems);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description - Update the store with new items. Existing items are updated, new items are added, old are kept. Items are matched by the compareKey.
|
||||
* @param {Array<T>} items
|
||||
* @param {keyof T} [compareKey='key']
|
||||
* @memberof UmbDataStoreBase
|
||||
*/
|
||||
public updateItems(items: Array<T>, compareKey: keyof T = 'key'): void {
|
||||
const newData = [...this._items.getValue()];
|
||||
items.forEach((newItem) => {
|
||||
const storedItemIndex = newData.findIndex((item) => item[compareKey] === newItem[compareKey]);
|
||||
if (storedItemIndex !== -1) {
|
||||
newData[storedItemIndex] = newItem;
|
||||
} else {
|
||||
newData.push(newItem);
|
||||
}
|
||||
});
|
||||
|
||||
this._items.next(newData);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @export
|
||||
* @class UmbNodeStoreBase
|
||||
* @implements {UmbDataStore<T>}
|
||||
* @template T
|
||||
* @description - Base class for Data Stores
|
||||
*/
|
||||
export abstract class UmbNodeStoreBase<T extends UmbDataStoreIdentifiers> extends UmbDataStoreBase<T> {
|
||||
export interface UmbContentStore<T> extends UmbDataStore {
|
||||
/**
|
||||
* @description - Request data by key. The data is added to the store and is returned as an Observable.
|
||||
* @param {string} key
|
||||
* @return {*} {(Observable<unknown>)}
|
||||
* @return {*} {(Observable<T>)}
|
||||
* @memberof UmbDataStoreBase
|
||||
*/
|
||||
abstract getByKey(key: string): Observable<unknown>;
|
||||
getByKey(key: string): Observable<T | undefined>;
|
||||
|
||||
/**
|
||||
* @description - Save data.
|
||||
* @param {object} data
|
||||
* @return {*} {(Promise<void>)}
|
||||
* @memberof UmbNodeStoreBase
|
||||
* @memberof UmbContentStore
|
||||
*/
|
||||
abstract save(data: T[]): Promise<void>;
|
||||
save(data: T[]): Promise<void>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user