Picker data source: Add support for pickable filters (#20491)
* add pickable to vs code dictionary * set up types for pickable filters in data sources * pass search pickable filter to search result * apply filter config in document data source example * add pickable filters to custom tree example * Update input-entity-data.context.ts * remove unused * Update types.ts
This commit is contained in:
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -1,5 +1,8 @@
|
||||
{
|
||||
"cSpell.words": [
|
||||
"backoffice",
|
||||
"pickable",
|
||||
"Pickable",
|
||||
"unprovide",
|
||||
"Unproviding"
|
||||
],
|
||||
|
||||
@@ -1,12 +1,21 @@
|
||||
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
|
||||
import type { UmbPickerTreeDataSource } from '@umbraco-cms/backoffice/picker-data-source';
|
||||
import type { UmbSearchRequestArgs } from '@umbraco-cms/backoffice/search';
|
||||
import type {
|
||||
UmbPickerSearchableDataSource,
|
||||
UmbPickerTreeDataSource,
|
||||
} from '@umbraco-cms/backoffice/picker-data-source';
|
||||
import type { UmbSearchRequestArgs, UmbSearchResultItemModel } from '@umbraco-cms/backoffice/search';
|
||||
import type { UmbTreeChildrenOfRequestArgs, UmbTreeItemModel } from '@umbraco-cms/backoffice/tree';
|
||||
|
||||
export class ExampleCustomPickerTreePropertyEditorDataSource
|
||||
extends UmbControllerBase
|
||||
implements UmbPickerTreeDataSource
|
||||
implements UmbPickerTreeDataSource, UmbPickerSearchableDataSource
|
||||
{
|
||||
treePickableFilter: (treeItem: UmbTreeItemModel) => boolean = (treeItem) =>
|
||||
!!treeItem.unique && treeItem.entityType === 'example';
|
||||
|
||||
searchPickableFilter: (searchItem: UmbSearchResultItemModel) => boolean = (searchItem) =>
|
||||
!!searchItem.unique && searchItem.entityType === 'example';
|
||||
|
||||
async requestTreeRoot() {
|
||||
const root = {
|
||||
unique: null,
|
||||
@@ -60,7 +69,7 @@ export class ExampleCustomPickerTreePropertyEditorDataSource
|
||||
|
||||
const data = {
|
||||
items: result,
|
||||
totalItems: result.length,
|
||||
total: result.length,
|
||||
};
|
||||
|
||||
return { data };
|
||||
|
||||
@@ -3,7 +3,10 @@ import {
|
||||
UmbDocumentItemRepository,
|
||||
UmbDocumentSearchRepository,
|
||||
UmbDocumentTreeRepository,
|
||||
type UmbDocumentSearchItemModel,
|
||||
type UmbDocumentSearchRequestArgs,
|
||||
type UmbDocumentTreeItemModel,
|
||||
type UmbDocumentTreeRootModel,
|
||||
} from '@umbraco-cms/backoffice/document';
|
||||
import { UMB_DOCUMENT_TYPE_ENTITY_TYPE } from '@umbraco-cms/backoffice/document-type';
|
||||
import type {
|
||||
@@ -20,16 +23,21 @@ import { getConfigValue, type UmbConfigCollectionModel } from '@umbraco-cms/back
|
||||
|
||||
export class ExampleDocumentPickerPropertyEditorDataSource
|
||||
extends UmbControllerBase
|
||||
implements UmbPickerTreeDataSource, UmbPickerSearchableDataSource
|
||||
implements
|
||||
UmbPickerTreeDataSource<UmbDocumentTreeItemModel, UmbDocumentTreeRootModel>,
|
||||
UmbPickerSearchableDataSource<UmbDocumentSearchItemModel>
|
||||
{
|
||||
#tree = new UmbDocumentTreeRepository(this);
|
||||
#item = new UmbDocumentItemRepository(this);
|
||||
#search = new UmbDocumentSearchRepository(this);
|
||||
#config: UmbConfigCollectionModel = [];
|
||||
|
||||
treePickableFilter: (treeItem: UmbDocumentTreeItemModel) => boolean = (treeItem) => !!treeItem.unique;
|
||||
|
||||
setConfig(config: UmbConfigCollectionModel) {
|
||||
// TODO: add examples for all config options
|
||||
this.#config = config;
|
||||
this.#applyPickableFilterFromConfig();
|
||||
}
|
||||
|
||||
getConfig(): UmbConfigCollectionModel {
|
||||
@@ -57,6 +65,13 @@ export class ExampleDocumentPickerPropertyEditorDataSource
|
||||
}
|
||||
|
||||
search(args: UmbSearchRequestArgs) {
|
||||
const allowedContentTypes = this.#getAllowedDocumentTypesConfig();
|
||||
const combinedArgs: UmbDocumentSearchRequestArgs = { ...args, allowedContentTypes };
|
||||
|
||||
return this.#search.search(combinedArgs);
|
||||
}
|
||||
|
||||
#getAllowedDocumentTypesConfig() {
|
||||
const filterString = getConfigValue<string>(this.#config, 'filter');
|
||||
const filterArray = filterString ? filterString.split(',') : [];
|
||||
const allowedContentTypes: UmbDocumentSearchRequestArgs['allowedContentTypes'] = filterArray.map(
|
||||
@@ -65,10 +80,14 @@ export class ExampleDocumentPickerPropertyEditorDataSource
|
||||
unique,
|
||||
}),
|
||||
);
|
||||
return allowedContentTypes;
|
||||
}
|
||||
|
||||
const combinedArgs: UmbDocumentSearchRequestArgs = { ...args, allowedContentTypes };
|
||||
|
||||
return this.#search.search(combinedArgs);
|
||||
#applyPickableFilterFromConfig() {
|
||||
const allowedDocumentTypes = this.#getAllowedDocumentTypesConfig();
|
||||
if (!allowedDocumentTypes || allowedDocumentTypes.length === 0) return;
|
||||
this.treePickableFilter = (treeItem: UmbDocumentTreeItemModel) =>
|
||||
allowedDocumentTypes.some((entityType) => entityType.unique === treeItem.documentType.unique);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -98,6 +98,8 @@ export class UmbCollectionItemPickerModalElement extends UmbModalBaseElement<
|
||||
this.modalContext?.dispatchEvent(new UmbDeselectedEvent(event.unique));
|
||||
}
|
||||
|
||||
#searchSelectableFilter = () => true;
|
||||
|
||||
override render() {
|
||||
return html`
|
||||
<umb-body-layout headline=${this.localize.term('general_choose')}>
|
||||
@@ -106,10 +108,14 @@ export class UmbCollectionItemPickerModalElement extends UmbModalBaseElement<
|
||||
</umb-body-layout>
|
||||
`;
|
||||
}
|
||||
|
||||
#renderSearch() {
|
||||
const selectableFilter =
|
||||
this.data?.search?.pickableFilter ?? this.data?.pickableFilter ?? this.#searchSelectableFilter;
|
||||
|
||||
return html`
|
||||
<umb-picker-search-field></umb-picker-search-field>
|
||||
<umb-picker-search-result .pickableFilter=${this.data?.pickableFilter}></umb-picker-search-result>
|
||||
<umb-picker-search-result .pickableFilter=${selectableFilter}></umb-picker-search-result>
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { ElementLoaderProperty } from '@umbraco-cms/backoffice/extension-api';
|
||||
import type { UUIModalElement, UUIModalSidebarSize } from '@umbraco-cms/backoffice/external/uui';
|
||||
import type { UmbSearchResultItemModel } from '@umbraco-cms/backoffice/search';
|
||||
|
||||
export type * from './extensions/types.js';
|
||||
|
||||
@@ -10,9 +11,13 @@ export interface UmbPickerModalData<ItemType> {
|
||||
search?: UmbPickerModalSearchConfig;
|
||||
}
|
||||
|
||||
export interface UmbPickerModalSearchConfig<QueryParamsType = Record<string, unknown>> {
|
||||
export interface UmbPickerModalSearchConfig<
|
||||
QueryParamsType = Record<string, unknown>,
|
||||
SearchResultItemType extends UmbSearchResultItemModel = UmbSearchResultItemModel,
|
||||
> {
|
||||
providerAlias: string;
|
||||
queryParams?: QueryParamsType;
|
||||
pickableFilter?: (item: SearchResultItemType) => boolean;
|
||||
}
|
||||
|
||||
export interface UmbPickerModalValue {
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import type { UmbPickerDataSource } from '../data-source/types.js';
|
||||
import type { UmbCollectionRepository } from '@umbraco-cms/backoffice/collection';
|
||||
import type { UmbItemModel } from '@umbraco-cms/backoffice/entity-item';
|
||||
import type { UmbApi } from '@umbraco-cms/backoffice/extension-api';
|
||||
|
||||
export interface UmbPickerCollectionDataSource extends UmbPickerDataSource, UmbCollectionRepository, UmbApi {}
|
||||
export interface UmbPickerCollectionDataSource<CollectionItemType extends UmbItemModel = UmbItemModel>
|
||||
extends UmbPickerDataSource,
|
||||
UmbCollectionRepository<CollectionItemType>,
|
||||
UmbApi {
|
||||
collectionPickableFilter?: (item: CollectionItemType) => boolean;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import type { UmbItemModel } from '@umbraco-cms/backoffice/entity-item';
|
||||
import type { UmbApi } from '@umbraco-cms/backoffice/extension-api';
|
||||
import type { UmbItemRepository } from '@umbraco-cms/backoffice/repository';
|
||||
import type { UmbConfigCollectionModel } from '@umbraco-cms/backoffice/utils';
|
||||
|
||||
export interface UmbPickerDataSource extends UmbItemRepository<any>, UmbApi {
|
||||
export interface UmbPickerDataSource<PickedItemType extends UmbItemModel = UmbItemModel>
|
||||
extends UmbItemRepository<PickedItemType>,
|
||||
UmbApi {
|
||||
setConfig?(config: UmbConfigCollectionModel | undefined): void;
|
||||
getConfig?(): UmbConfigCollectionModel | undefined;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import type { UmbPickerDataSource } from '../types.js';
|
||||
import type { UmbSearchRepository } from '@umbraco-cms/backoffice/search';
|
||||
import type { UmbSearchRepository, UmbSearchResultItemModel } from '@umbraco-cms/backoffice/search';
|
||||
|
||||
export interface UmbPickerSearchableDataSource extends UmbPickerDataSource, UmbSearchRepository<any> {}
|
||||
export interface UmbPickerSearchableDataSource<
|
||||
SearchResultItemType extends UmbSearchResultItemModel = UmbSearchResultItemModel,
|
||||
> extends UmbPickerDataSource,
|
||||
UmbSearchRepository<SearchResultItemType> {
|
||||
searchPickableFilter?: (searchItem: SearchResultItemType) => boolean;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
import type { UmbPickerDataSource } from '../data-source/types.js';
|
||||
import type { UmbApi } from '@umbraco-cms/backoffice/extension-api';
|
||||
import type { UmbTreeRepository } from '@umbraco-cms/backoffice/tree';
|
||||
import type { UmbTreeItemModel, UmbTreeRepository, UmbTreeRootModel } from '@umbraco-cms/backoffice/tree';
|
||||
|
||||
export interface UmbPickerTreeDataSource extends UmbPickerDataSource, UmbTreeRepository, UmbApi {}
|
||||
export interface UmbPickerTreeDataSource<
|
||||
TreeItemType extends UmbTreeItemModel = UmbTreeItemModel,
|
||||
TreeRootType extends UmbTreeRootModel = UmbTreeRootModel,
|
||||
> extends UmbPickerDataSource,
|
||||
UmbTreeRepository<TreeItemType, TreeRootType>,
|
||||
UmbApi {
|
||||
treePickableFilter?: (item: TreeItemType) => boolean;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
import type { UmbSearchRequestArgs, UmbSearchResultItemModel } from '@umbraco-cms/backoffice/search';
|
||||
import type { UmbItemModel } from '@umbraco-cms/backoffice/entity-item';
|
||||
|
||||
type PickableFilterMethodType<T extends UmbItemModel = UmbItemModel> = (item: T) => boolean;
|
||||
type PickableFilterMethodType<T extends UmbSearchResultItemModel = UmbSearchResultItemModel> = (item: T) => boolean;
|
||||
|
||||
@customElement('umb-picker-search-result')
|
||||
export class UmbPickerSearchResultElement extends UmbLitElement {
|
||||
|
||||
@@ -172,6 +172,8 @@ export class UmbTreePickerModalElement<TreeItemType extends UmbTreeItemModelBase
|
||||
this._pickerContext.expansion.setExpansion(expansion);
|
||||
}
|
||||
|
||||
#searchSelectableFilter = () => true;
|
||||
|
||||
override render() {
|
||||
return html`
|
||||
<umb-body-layout headline=${this.localize.term('general_choose')}>
|
||||
@@ -181,9 +183,12 @@ export class UmbTreePickerModalElement<TreeItemType extends UmbTreeItemModelBase
|
||||
`;
|
||||
}
|
||||
#renderSearch() {
|
||||
const selectableFilter =
|
||||
this.data?.search?.pickableFilter ?? this.data?.pickableFilter ?? this.#searchSelectableFilter;
|
||||
|
||||
return html`
|
||||
<umb-picker-search-field></umb-picker-search-field>
|
||||
<umb-picker-search-result .pickableFilter=${this.data?.pickableFilter}></umb-picker-search-result>
|
||||
<umb-picker-search-result .pickableFilter=${selectableFilter}></umb-picker-search-result>
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registr
|
||||
import { UmbModalToken, type UmbPickerModalData } from '@umbraco-cms/backoffice/modal';
|
||||
import {
|
||||
UMB_TREE_PICKER_MODAL_ALIAS,
|
||||
type UmbTreeItemModel,
|
||||
type UmbTreePickerModalData,
|
||||
type UmbTreePickerModalValue,
|
||||
} from '@umbraco-cms/backoffice/tree';
|
||||
@@ -84,6 +85,9 @@ export class UmbEntityDataPickerInputContext extends UmbPickerInputContext<UmbIt
|
||||
}
|
||||
|
||||
override async openPicker(pickerData?: Partial<UmbPickerModalData<UmbItemModel>>) {
|
||||
// TODO: investigate type issues
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
this.modalAlias = this.#getModalToken();
|
||||
await super.openPicker(pickerData);
|
||||
}
|
||||
@@ -133,7 +137,7 @@ export class UmbEntityDataPickerInputContext extends UmbPickerInputContext<UmbIt
|
||||
#createTreeItemPickerModalToken(api: UmbPickerTreeDataSource) {
|
||||
const supportsSearch = isPickerSearchableDataSource(api);
|
||||
|
||||
return new UmbModalToken<UmbTreePickerModalData<UmbItemModel>, UmbTreePickerModalValue>(
|
||||
return new UmbModalToken<UmbTreePickerModalData<UmbTreeItemModel>, UmbTreePickerModalValue>(
|
||||
UMB_TREE_PICKER_MODAL_ALIAS,
|
||||
{
|
||||
modal: {
|
||||
@@ -143,9 +147,12 @@ export class UmbEntityDataPickerInputContext extends UmbPickerInputContext<UmbIt
|
||||
data: {
|
||||
treeAlias: UMB_ENTITY_DATA_PICKER_TREE_ALIAS,
|
||||
hideTreeRoot: true,
|
||||
// TODO: make specific pickable filter for tree to avoid type issues
|
||||
pickableFilter: api.treePickableFilter,
|
||||
search: supportsSearch
|
||||
? {
|
||||
providerAlias: UMB_ENTITY_DATA_PICKER_SEARCH_PROVIDER_ALIAS,
|
||||
pickableFilter: api.searchPickableFilter,
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
@@ -167,9 +174,12 @@ export class UmbEntityDataPickerInputContext extends UmbPickerInputContext<UmbIt
|
||||
collection: {
|
||||
menuAlias: UMB_ENTITY_DATA_PICKER_COLLECTION_MENU_ALIAS,
|
||||
},
|
||||
// TODO: make specific pickable filter for collection to avoid type issues
|
||||
pickableFilter: api.collectionPickableFilter,
|
||||
search: supportsSearch
|
||||
? {
|
||||
providerAlias: UMB_ENTITY_DATA_PICKER_SEARCH_PROVIDER_ALIAS,
|
||||
pickableFilter: api.searchPickableFilter,
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user