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

This commit is contained in:
Jacob Overgaard
2023-01-25 11:38:41 +01:00
8 changed files with 78 additions and 35 deletions

View File

@@ -55,11 +55,11 @@ customElements.define('umb-storybook', UmbStoryBookElement);
const storybookProvider = (story) => html` <umb-storybook>${story()}</umb-storybook> `;
const dataTypeStoreProvider = (story) => html`
<umb-context-provider key=${UMB_DATA_TYPE_DETAIL_STORE_CONTEXT_TOKEN.toString()} .value=${new UmbDataTypeDetailStore()}>${story()}</umb-context-provider>
<umb-context-provider key=${UMB_DATA_TYPE_DETAIL_STORE_CONTEXT_TOKEN.toString()} .create=${host => new UmbDataTypeDetailStore(host)}>${story()}</umb-context-provider>
`;
const documentTypeStoreProvider = (story) => html`
<umb-context-provider key=${UMB_DOCUMENT_TYPE_DETAIL_STORE_CONTEXT_TOKEN.toString()} .value=${new UmbDocumentTypeDetailStore()}
<umb-context-provider key=${UMB_DOCUMENT_TYPE_DETAIL_STORE_CONTEXT_TOKEN.toString()} .create=${host => new UmbDocumentTypeDetailStore(host)}
>${story()}</umb-context-provider
>
`;

View File

@@ -1,9 +1,18 @@
import { html } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { UmbLitElement } from './lit-element.element';
import type { UmbControllerHostInterface } from '@umbraco-cms/controller';
@customElement('umb-context-provider')
export class UmbContextProviderElement extends UmbLitElement {
/**
* The value to provide to the context.
* @required
*/
@property({ type: Object, attribute: false })
create?: (host:UmbControllerHostInterface) => unknown;
/**
* The value to provide to the context.
* @required
@@ -23,7 +32,9 @@ export class UmbContextProviderElement extends UmbLitElement {
if (!this.key) {
throw new Error('The key property is required.');
}
if (!this.value) {
if (this.create) {
this.value = this.create(this);
} else if (!this.value) {
throw new Error('The value property is required.');
}
this.provideContext(this.key, this.value);

View File

@@ -1,5 +1,5 @@
import { DeepState } from "./deep-state";
import { appendToFrozenArray } from "./append-to-frozen-array.method";
import { pushToUniqueArray } from "./push-to-unique-array.method";
/**
* @export
@@ -21,15 +21,15 @@ export class ArrayState<T> extends DeepState<T[]> {
/**
* @method append
* @param {unknown} unique - The unique value to remove.
* @returns ArrayState<T>
* @return {ArrayState<T>} Reference to it self.
* @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 ArrayState(data, (x) => x.key);
* mySubject.remove([1]);
* const myState = new ArrayState(data, (x) => x.key);
* myState.remove([1]);
*/
remove(uniques: unknown[]) {
let next = this.getValue();
@@ -51,7 +51,7 @@ export class ArrayState<T> extends DeepState<T[]> {
/**
* @method filter
* @param {unknown} filterMethod - The unique value to remove.
* @returns ArrayState<T>
* @return {ArrayState<T>} Reference to it self.
* @description - Remove some new data of this Subject.
* @example <caption>Example remove entry with key '1'</caption>
* const data = [
@@ -59,8 +59,8 @@ export class ArrayState<T> extends DeepState<T[]> {
* { key: 2, value: 'bar'},
* { key: 3, value: 'poo'}
* ];
* const mySubject = new ArrayState(data, (x) => x.key);
* mySubject.filter((entry) => entry.key !== 1);
* const myState = new ArrayState(data, (x) => x.key);
* myState.filter((entry) => entry.key !== 1);
*
* Result:
* [
@@ -75,48 +75,55 @@ export class ArrayState<T> extends DeepState<T[]> {
}
/**
* @method append
* @param {Partial<T>} partialData - A object containing some of the data for this Subject.
* @returns ArrayState<T>
* @method appendOne
* @param {T} entry - new data to be added in this Subject.
* @return {ArrayState<T>} Reference to it self.
* @description - Append some new data to this Subject.
* @example <caption>Example append some data.</caption>
* const data = [
* { key: 1, value: 'foo'},
* { key: 2, value: 'bar'}
* ];
* const mySubject = new ArrayState(data);
* mySubject.append({ key: 1, value: 'replaced-foo'});
* const myState = new ArrayState(data);
* myState.append({ key: 1, value: 'replaced-foo'});
*/
appendOne(entry: T) {
this.next(appendToFrozenArray(this.getValue(), entry, this._getUnique))
const next = [...this.getValue()];
if(this._getUnique) {
pushToUniqueArray(next, entry, this._getUnique);
} else {
next.push(entry);
}
this.next(next);
return this;
}
/**
* @method append
* @param {T[]} entries - A array of new data to be added in this Subject.
* @returns ArrayState<T>
* @return {ArrayState<T>} Reference to it self.
* @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'},
* { key: 2, value: 'bar'}
* ];
* const mySubject = new ArrayState(data);
* mySubject.append([
* const myState = new ArrayState(data);
* myState.append([
* { key: 1, value: 'replaced-foo'},
* { key: 3, value: 'another-bla'}
* ]);
*/
append(entries: T[]) {
// TODO: stop calling appendOne for each but make sure to handle this in one.
entries.forEach(x => this.appendOne(x))
/*
const unFrozenDataSet = [...this.getValue()];
this.next(unFrozenDataSet);
*/
if(this._getUnique) {
const next = [...this.getValue()];
entries.forEach(entry => {
pushToUniqueArray(next, entry, this._getUnique!);
});
this.next(next);
} else {
this.next([...this.getValue(), ...entries]);
}
return this;
}
}

View File

@@ -12,15 +12,17 @@ import { DeepState } from "./deep-state";
export class ObjectState<T> extends DeepState<T> {
/**
* @method append
* @param {Partial<T>} partialData - A object containing some of the data for this Subject.
* @method update
* @param {Partial<T>} partialData - A object containing some of the data to update in this Subject.
* @description - Append some new data to this Object.
* @return {ObjectState<T>} Reference to it self.
* @example <caption>Example append some data.</caption>
* const data = {key: 'myKey', value: 'myInitialValue'};
* const mySubject = new ObjectState(data)
* mySubject.append({value: 'myNewValue'})
* const myState = new ObjectState(data);
* myState.update({value: 'myNewValue'});
*/
update(partialData: Partial<T>) {
this.next({ ...this.getValue(), ...partialData });
return this;
}
}

View File

@@ -0,0 +1,22 @@
/**
* @export
* @method pushToUniqueArray
* @param {T[]} data - An array of objects.
* @param {T} entry - The object to insert or replace with.
* @param {getUniqueMethod: (entry: T) => unknown} [getUniqueMethod] - Method to get the unique value of an entry.
* @description - Append or replaces an item of an Array.
* @example <caption>Example append new entry for a 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 = pushToUniqueArray([], entry, x => x.key === key);
* mySubject.next(newDataSet);
*/
export function pushToUniqueArray<T>(data: T[], entry: T, getUniqueMethod: (entry: T) => unknown): T[] {
const unique = getUniqueMethod(entry);
const indexToReplace = data.findIndex((x) => getUniqueMethod(x) === unique);
if (indexToReplace !== -1) {
data[indexToReplace] = entry;
} else {
data.push(entry);
}
return data;
}

View File

@@ -46,9 +46,9 @@ export class UmbWorkspaceDocumentContext extends UmbWorkspaceContentContext<Docu
// TODO: make sure to check that we have a details model? otherwise fail? 8This can be relevant if we use the same context for tree actions?
const entry = {alias: alias, value: value};
const newDataSet = appendToFrozenArray((this._data.getValue() as DocumentDetails).data, entry, (x: any) => x.alias);
const newDataSet = appendToFrozenArray(this._data.getValue().data, entry, x => x.alias);
this.update({data: newDataSet});
this._data.update({data: newDataSet});
}
/*

View File

@@ -2,7 +2,7 @@ import { v4 as uuidv4 } from 'uuid';
import { UmbNotificationService, UMB_NOTIFICATION_SERVICE_CONTEXT_TOKEN, UmbNotificationDefaultData } from '@umbraco-cms/notification';
import { UmbControllerHostInterface } from '@umbraco-cms/controller';
import { UmbContextConsumerController, UmbContextProviderController } from '@umbraco-cms/context-api';
import { DeepState, UmbObserverController, createObservablePart } from '@umbraco-cms/observable-api';
import { ObjectState, UmbObserverController, createObservablePart } from '@umbraco-cms/observable-api';
import { UmbContentStore } from '@umbraco-cms/store';
import type { ContentTreeItem } from '@umbraco-cms/backend-api';
@@ -33,7 +33,7 @@ export abstract class UmbWorkspaceContentContext<
constructor(host: UmbControllerHostInterface, defaultData: ContentTypeType, storeAlias: string, entityType: string) {
this._host = host;
this._data = new DeepState<ContentTypeType>(defaultData);
this._data = new ObjectState<ContentTypeType>(defaultData);
this.data = this._data.asObservable();
this.name = createObservablePart(this._data, (data) => data.name);

View File

@@ -21,6 +21,7 @@
"baseUrl": ".",
"paths": {
"@umbraco-cms/css": ["libs/css/custom-properties.css"],
"@umbraco-cms/modal": ["src/core/modal"],
"@umbraco-cms/models": ["libs/models"],
"@umbraco-cms/backend-api": ["libs/backend-api"],
"@umbraco-cms/context-api": ["libs/context-api"],