Merge remote-tracking branch 'origin/main' into feature/auth-app

This commit is contained in:
Jacob Overgaard
2023-01-24 13:52:50 +01:00
69 changed files with 1780 additions and 1086 deletions

View File

@@ -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;
}

View File

@@ -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'

View File

@@ -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);
});

View File

@@ -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))
}
}

View File

@@ -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;

View File

@@ -1,2 +1,3 @@
export * from './icon/icon.store';
export * from './store';
export * from './store-base';

View 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);
}
}

View File

@@ -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>;
}