initial work on repository-selection.manager
This commit is contained in:
@@ -1,8 +1,5 @@
|
||||
import { UmbItemRepository } from '@umbraco-cms/backoffice/repository';
|
||||
import { UmbItemRepository, UmbRepositorySelectionManager } from '@umbraco-cms/backoffice/repository';
|
||||
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbArrayState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api';
|
||||
import { createExtensionClass } from '@umbraco-cms/backoffice/extension-api';
|
||||
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import {
|
||||
UMB_CONFIRM_MODAL,
|
||||
UMB_MODAL_CONTEXT_TOKEN,
|
||||
@@ -26,13 +23,10 @@ export class UmbPickerInputContext<ItemType extends ItemResponseModelBaseModel>
|
||||
|
||||
#init: Promise<unknown>;
|
||||
|
||||
#selection = new UmbArrayState<string>([]);
|
||||
selection = this.#selection.asObservable();
|
||||
#selectionManager;
|
||||
|
||||
#selectedItems = new UmbArrayState<ItemType>([]);
|
||||
selectedItems = this.#selectedItems.asObservable();
|
||||
|
||||
#selectedItemsObserver?: UmbObserverController<ItemType[]>;
|
||||
selection;
|
||||
selectedItems;
|
||||
|
||||
max = Infinity;
|
||||
min = 0;
|
||||
@@ -49,29 +43,13 @@ export class UmbPickerInputContext<ItemType extends ItemResponseModelBaseModel>
|
||||
this.modalAlias = modalAlias;
|
||||
this.#getUnique = getUniqueMethod || ((entry) => entry.id || '');
|
||||
|
||||
//TODO: The promise can probably be done in a cleaner way.
|
||||
const repositoryPromise: Promise<void> = new Promise((resolve) => {
|
||||
new UmbObserverController(
|
||||
this.host,
|
||||
this.#selectionManager = new UmbRepositorySelectionManager<ItemType>(host, repositoryAlias);
|
||||
|
||||
// TODO: this code is reused in multiple places, so it should be extracted to a function
|
||||
umbExtensionsRegistry.getByTypeAndAlias('repository', repositoryAlias),
|
||||
async (repositoryManifest) => {
|
||||
if (!repositoryManifest) return;
|
||||
|
||||
try {
|
||||
const result = await createExtensionClass<UmbItemRepository<ItemType>>(repositoryManifest, [this.host]);
|
||||
this.repository = result;
|
||||
resolve();
|
||||
} catch (error) {
|
||||
throw new Error('Could not create repository with alias: ' + repositoryAlias + '');
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
this.selection = this.#selectionManager.selection;
|
||||
this.selectedItems = this.#selectionManager.selectedItems;
|
||||
|
||||
this.#init = Promise.all([
|
||||
repositoryPromise,
|
||||
this.#selectionManager.init,
|
||||
new UmbContextConsumerController(this.host, UMB_MODAL_CONTEXT_TOKEN, (instance) => {
|
||||
this.modalContext = instance;
|
||||
}).asPromise(),
|
||||
@@ -79,14 +57,11 @@ export class UmbPickerInputContext<ItemType extends ItemResponseModelBaseModel>
|
||||
}
|
||||
|
||||
getSelection() {
|
||||
return this.#selection.value;
|
||||
return this.#selectionManager.getSelection();
|
||||
}
|
||||
|
||||
setSelection(selection: string[]) {
|
||||
this.#selection.next(selection);
|
||||
|
||||
//TODO: Check if it's safe to call requestItems here.
|
||||
this.#requestItems();
|
||||
this.#selectionManager.setSelection(selection);
|
||||
}
|
||||
|
||||
// TODO: If modalAlias is a ModalToken, then via TS, we should get the correct type for pickerData. Otherwise fallback to unknown.
|
||||
@@ -112,7 +87,7 @@ export class UmbPickerInputContext<ItemType extends ItemResponseModelBaseModel>
|
||||
if (!this.repository) throw new Error('Repository is not initialized');
|
||||
|
||||
// TODO: id won't always be available on the model, so we need to get the unique property from somewhere. Maybe the repository?
|
||||
const item = this.#selectedItems.value.find((item) => this.#getUnique(item) === unique);
|
||||
const item = this.#selectionManager.getSelectedItems().find((item) => this.#getUnique(item) === unique);
|
||||
if (!item) throw new Error('Could not find item with unique: ' + unique);
|
||||
|
||||
const modalHandler = this.modalContext?.open(UMB_CONFIRM_MODAL, {
|
||||
@@ -126,26 +101,8 @@ export class UmbPickerInputContext<ItemType extends ItemResponseModelBaseModel>
|
||||
this.#removeItem(unique);
|
||||
}
|
||||
|
||||
async #requestItems() {
|
||||
await this.#init;
|
||||
if (!this.repository) throw new Error('Repository is not initialized');
|
||||
if (this.#selectedItemsObserver) this.#selectedItemsObserver.destroy();
|
||||
|
||||
const { asObservable } = await this.repository.requestItems(this.getSelection());
|
||||
|
||||
if (asObservable) {
|
||||
this.#selectedItemsObserver = new UmbObserverController(this.host, asObservable(), (data) =>
|
||||
this.#selectedItems.next(data)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#removeItem(unique: string) {
|
||||
const newSelection = this.getSelection().filter((value) => value !== unique);
|
||||
this.#selection.next(newSelection);
|
||||
// remove items items from selectedItems array
|
||||
// TODO: id won't always be available on the model, so we need to get the unique property from somewhere. Maybe the repository?
|
||||
const newSelectedItems = this.#selectedItems.value.filter((item) => this.#getUnique(item) !== unique);
|
||||
this.#selectedItems.next(newSelectedItems);
|
||||
this.setSelection(newSelection);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,3 +6,4 @@ export * from './collection-repository.interface';
|
||||
export * from './item-repository.interface';
|
||||
export * from './move-repository.interface';
|
||||
export * from './copy-repository.interface';
|
||||
export * from './repository-selection.manager';
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
import { UmbItemRepository } from '@umbraco-cms/backoffice/repository';
|
||||
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbArrayState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api';
|
||||
import { createExtensionClass } from '@umbraco-cms/backoffice/extension-api';
|
||||
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import { ItemResponseModelBaseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
|
||||
export class UmbRepositorySelectionManager<ItemType extends ItemResponseModelBaseModel> {
|
||||
host: UmbControllerHostElement;
|
||||
repository?: UmbItemRepository<ItemType>;
|
||||
|
||||
init: Promise<void>;
|
||||
|
||||
#selection = new UmbArrayState<string>([]);
|
||||
selection = this.#selection.asObservable();
|
||||
|
||||
#selectedItems = new UmbArrayState<ItemType>([]);
|
||||
selectedItems = this.#selectedItems.asObservable();
|
||||
|
||||
#selectedItemsObserver?: UmbObserverController<ItemType[]>;
|
||||
|
||||
/* TODO: find a better way to have a getUniqueMethod. If we want to support trees/items of different types,
|
||||
then it need to be bound to the type and can't be a generic method we pass in. */
|
||||
constructor(host: UmbControllerHostElement, repositoryAlias: string) {
|
||||
this.host = host;
|
||||
|
||||
//TODO: The promise can probably be done in a cleaner way.
|
||||
this.init = new Promise((resolve) => {
|
||||
new UmbObserverController(
|
||||
this.host,
|
||||
|
||||
// TODO: this code is reused in multiple places, so it should be extracted to a function
|
||||
umbExtensionsRegistry.getByTypeAndAlias('repository', repositoryAlias),
|
||||
async (repositoryManifest) => {
|
||||
if (!repositoryManifest) return;
|
||||
|
||||
try {
|
||||
const result = await createExtensionClass<UmbItemRepository<ItemType>>(repositoryManifest, [this.host]);
|
||||
this.repository = result;
|
||||
resolve();
|
||||
} catch (error) {
|
||||
throw new Error('Could not create repository with alias: ' + repositoryAlias + '');
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
getSelection() {
|
||||
return this.#selection.value;
|
||||
}
|
||||
|
||||
setSelection(selection: string[]) {
|
||||
this.#selection.next(selection);
|
||||
|
||||
//TODO: Check if it's safe to call requestItems here.
|
||||
this.#requestItems();
|
||||
}
|
||||
|
||||
getSelectedItems() {
|
||||
return this.#selectedItems.value;
|
||||
}
|
||||
|
||||
async #requestItems() {
|
||||
await this.init;
|
||||
if (!this.repository) throw new Error('Repository is not initialized');
|
||||
if (this.#selectedItemsObserver) this.#selectedItemsObserver.destroy();
|
||||
|
||||
// TODO: Test if its just some items that is gone now, if so then just filter them out. (maybe use code from #removeItem)
|
||||
|
||||
const { asObservable } = await this.repository.requestItems(this.getSelection());
|
||||
|
||||
if (asObservable) {
|
||||
this.#selectedItemsObserver = new UmbObserverController(this.host, asObservable(), (data) =>
|
||||
this.#selectedItems.next(data)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#removeItem(unique: string) {
|
||||
const newSelection = this.getSelection().filter((value) => value !== unique);
|
||||
this.#selection.next(newSelection);
|
||||
// remove items items from selectedItems array
|
||||
// TODO: id won't always be available on the model, so we need to get the unique property from somewhere. Maybe the repository?
|
||||
const newSelectedItems = this.#selectedItems.value.filter((item) => this.#getUnique(item) !== unique);
|
||||
this.#selectedItems.next(newSelectedItems);
|
||||
}
|
||||
*/
|
||||
}
|
||||
@@ -3,9 +3,9 @@ import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
|
||||
import { customElement, property, state } from 'lit/decorators.js';
|
||||
import { FormControlMixin } from '@umbraco-ui/uui-base/lib/mixins';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import { UmbModalRouteRegistrationController, UMB_DATA_TYPE_PICKER_FLOW_MODAL } from '@umbraco-cms/backoffice/modal';
|
||||
import type { UmbDataTypeModel } from '@umbraco-cms/backoffice/models';
|
||||
import { UmbRepositorySelectionManager } from '@umbraco-cms/backoffice/repository';
|
||||
|
||||
// Note: Does only support picking a single data type. But this could be developed later into this same component. To follow other picker input components.
|
||||
/**
|
||||
@@ -17,20 +17,26 @@ import type { UmbDataTypeModel } from '@umbraco-cms/backoffice/models';
|
||||
*/
|
||||
@customElement('umb-data-type-flow-input')
|
||||
export class UmbInputDataTypeElement extends FormControlMixin(UmbLitElement) {
|
||||
#selectionManager;
|
||||
|
||||
protected getFormElement() {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@state() private _selectedDataType?: UmbDataTypeModel;
|
||||
@state()
|
||||
private _items?: Array<UmbDataTypeModel>;
|
||||
|
||||
/**
|
||||
* @param {string} dataTypeId
|
||||
* @default []
|
||||
*/
|
||||
@property({ attribute: false })
|
||||
get value(): string {
|
||||
return super.value.toString();
|
||||
}
|
||||
set value(dataTypeId: string) {
|
||||
super.value = dataTypeId;
|
||||
this.#observeDataTypeId();
|
||||
this.#selectionManager.setSelection(dataTypeId.split(','));
|
||||
}
|
||||
|
||||
@state()
|
||||
@@ -39,16 +45,22 @@ export class UmbInputDataTypeElement extends FormControlMixin(UmbLitElement) {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.#selectionManager = new UmbRepositorySelectionManager<UmbDataTypeModel>(this, 'dataType');
|
||||
this.observe(this.#selectionManager.selection, (selection) => {
|
||||
super.value = selection.join(',');
|
||||
});
|
||||
this.observe(this.#selectionManager.selectedItems, (selectedItems) => (this._items = selectedItems));
|
||||
|
||||
new UmbModalRouteRegistrationController(this, UMB_DATA_TYPE_PICKER_FLOW_MODAL)
|
||||
.onSetup(() => {
|
||||
return {
|
||||
selection: [this._value.toString()],
|
||||
selection: this.#selectionManager.getSelection(),
|
||||
submitLabel: 'Submit',
|
||||
};
|
||||
})
|
||||
.onSubmit((submitData) => {
|
||||
// TODO: we might should set the alias to null or empty string, if no selection.
|
||||
this.value = submitData.selection[0] ?? null;
|
||||
this.#selectionManager.setSelection(submitData.selection);
|
||||
this.dispatchEvent(new CustomEvent('change', { composed: true, bubbles: true }));
|
||||
})
|
||||
.observeRouteBuilder((routeBuilder) => {
|
||||
@@ -57,27 +69,13 @@ export class UmbInputDataTypeElement extends FormControlMixin(UmbLitElement) {
|
||||
});
|
||||
}
|
||||
|
||||
#observeDataTypeId() {
|
||||
if (!this._value) return;
|
||||
|
||||
/*this.observe(
|
||||
umbExtensionsRegistry.getByTypeAndAlias('propertyEditorUI', this._value.toString()),
|
||||
(propertyEditorUI) => {
|
||||
if (!propertyEditorUI) return;
|
||||
|
||||
this._selectedDataType = propertyEditorUI;
|
||||
},
|
||||
'observePropertyEditorUI'
|
||||
);*/
|
||||
}
|
||||
|
||||
render() {
|
||||
return this._selectedDataType
|
||||
return this._items && this._items.length > 0
|
||||
? html`
|
||||
<umb-ref-data-type
|
||||
name=${this._selectedDataType.name}
|
||||
property-editor-ui-alias=${this._selectedDataType.propertyEditorAlias}
|
||||
property-editor-model-alias=${this._selectedDataType.propertyEditorUiAlias}
|
||||
name=${this._items[0].name}
|
||||
property-editor-ui-alias=${this._items[0].propertyEditorAlias}
|
||||
property-editor-model-alias=${this._items[0].propertyEditorUiAlias}
|
||||
@open=${() => {
|
||||
console.warn('TO BE DONE..');
|
||||
}}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { customElement, property, state } from 'lit/decorators.js';
|
||||
import { FormControlMixin } from '@umbraco-ui/uui-base/lib/mixins';
|
||||
import { UmbDataTypePickerContext } from './data-type-input.context';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
import type { DataTypeItemResponseModel, FolderTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import type { DataTypeItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
|
||||
@customElement('umb-data-type-input')
|
||||
export class UmbDataTypeInputElement extends FormControlMixin(UmbLitElement) {
|
||||
|
||||
Reference in New Issue
Block a user