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": [
|
"cSpell.words": [
|
||||||
|
"backoffice",
|
||||||
|
"pickable",
|
||||||
|
"Pickable",
|
||||||
"unprovide",
|
"unprovide",
|
||||||
"Unproviding"
|
"Unproviding"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,12 +1,21 @@
|
|||||||
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
|
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
|
||||||
import type { UmbPickerTreeDataSource } from '@umbraco-cms/backoffice/picker-data-source';
|
import type {
|
||||||
import type { UmbSearchRequestArgs } from '@umbraco-cms/backoffice/search';
|
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';
|
import type { UmbTreeChildrenOfRequestArgs, UmbTreeItemModel } from '@umbraco-cms/backoffice/tree';
|
||||||
|
|
||||||
export class ExampleCustomPickerTreePropertyEditorDataSource
|
export class ExampleCustomPickerTreePropertyEditorDataSource
|
||||||
extends UmbControllerBase
|
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() {
|
async requestTreeRoot() {
|
||||||
const root = {
|
const root = {
|
||||||
unique: null,
|
unique: null,
|
||||||
@@ -60,7 +69,7 @@ export class ExampleCustomPickerTreePropertyEditorDataSource
|
|||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
items: result,
|
items: result,
|
||||||
totalItems: result.length,
|
total: result.length,
|
||||||
};
|
};
|
||||||
|
|
||||||
return { data };
|
return { data };
|
||||||
|
|||||||
@@ -3,7 +3,10 @@ import {
|
|||||||
UmbDocumentItemRepository,
|
UmbDocumentItemRepository,
|
||||||
UmbDocumentSearchRepository,
|
UmbDocumentSearchRepository,
|
||||||
UmbDocumentTreeRepository,
|
UmbDocumentTreeRepository,
|
||||||
|
type UmbDocumentSearchItemModel,
|
||||||
type UmbDocumentSearchRequestArgs,
|
type UmbDocumentSearchRequestArgs,
|
||||||
|
type UmbDocumentTreeItemModel,
|
||||||
|
type UmbDocumentTreeRootModel,
|
||||||
} from '@umbraco-cms/backoffice/document';
|
} from '@umbraco-cms/backoffice/document';
|
||||||
import { UMB_DOCUMENT_TYPE_ENTITY_TYPE } from '@umbraco-cms/backoffice/document-type';
|
import { UMB_DOCUMENT_TYPE_ENTITY_TYPE } from '@umbraco-cms/backoffice/document-type';
|
||||||
import type {
|
import type {
|
||||||
@@ -20,16 +23,21 @@ import { getConfigValue, type UmbConfigCollectionModel } from '@umbraco-cms/back
|
|||||||
|
|
||||||
export class ExampleDocumentPickerPropertyEditorDataSource
|
export class ExampleDocumentPickerPropertyEditorDataSource
|
||||||
extends UmbControllerBase
|
extends UmbControllerBase
|
||||||
implements UmbPickerTreeDataSource, UmbPickerSearchableDataSource
|
implements
|
||||||
|
UmbPickerTreeDataSource<UmbDocumentTreeItemModel, UmbDocumentTreeRootModel>,
|
||||||
|
UmbPickerSearchableDataSource<UmbDocumentSearchItemModel>
|
||||||
{
|
{
|
||||||
#tree = new UmbDocumentTreeRepository(this);
|
#tree = new UmbDocumentTreeRepository(this);
|
||||||
#item = new UmbDocumentItemRepository(this);
|
#item = new UmbDocumentItemRepository(this);
|
||||||
#search = new UmbDocumentSearchRepository(this);
|
#search = new UmbDocumentSearchRepository(this);
|
||||||
#config: UmbConfigCollectionModel = [];
|
#config: UmbConfigCollectionModel = [];
|
||||||
|
|
||||||
|
treePickableFilter: (treeItem: UmbDocumentTreeItemModel) => boolean = (treeItem) => !!treeItem.unique;
|
||||||
|
|
||||||
setConfig(config: UmbConfigCollectionModel) {
|
setConfig(config: UmbConfigCollectionModel) {
|
||||||
// TODO: add examples for all config options
|
// TODO: add examples for all config options
|
||||||
this.#config = config;
|
this.#config = config;
|
||||||
|
this.#applyPickableFilterFromConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
getConfig(): UmbConfigCollectionModel {
|
getConfig(): UmbConfigCollectionModel {
|
||||||
@@ -57,6 +65,13 @@ export class ExampleDocumentPickerPropertyEditorDataSource
|
|||||||
}
|
}
|
||||||
|
|
||||||
search(args: UmbSearchRequestArgs) {
|
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 filterString = getConfigValue<string>(this.#config, 'filter');
|
||||||
const filterArray = filterString ? filterString.split(',') : [];
|
const filterArray = filterString ? filterString.split(',') : [];
|
||||||
const allowedContentTypes: UmbDocumentSearchRequestArgs['allowedContentTypes'] = filterArray.map(
|
const allowedContentTypes: UmbDocumentSearchRequestArgs['allowedContentTypes'] = filterArray.map(
|
||||||
@@ -65,10 +80,14 @@ export class ExampleDocumentPickerPropertyEditorDataSource
|
|||||||
unique,
|
unique,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
return allowedContentTypes;
|
||||||
|
}
|
||||||
|
|
||||||
const combinedArgs: UmbDocumentSearchRequestArgs = { ...args, allowedContentTypes };
|
#applyPickableFilterFromConfig() {
|
||||||
|
const allowedDocumentTypes = this.#getAllowedDocumentTypesConfig();
|
||||||
return this.#search.search(combinedArgs);
|
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));
|
this.modalContext?.dispatchEvent(new UmbDeselectedEvent(event.unique));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#searchSelectableFilter = () => true;
|
||||||
|
|
||||||
override render() {
|
override render() {
|
||||||
return html`
|
return html`
|
||||||
<umb-body-layout headline=${this.localize.term('general_choose')}>
|
<umb-body-layout headline=${this.localize.term('general_choose')}>
|
||||||
@@ -106,10 +108,14 @@ export class UmbCollectionItemPickerModalElement extends UmbModalBaseElement<
|
|||||||
</umb-body-layout>
|
</umb-body-layout>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
#renderSearch() {
|
#renderSearch() {
|
||||||
|
const selectableFilter =
|
||||||
|
this.data?.search?.pickableFilter ?? this.data?.pickableFilter ?? this.#searchSelectableFilter;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<umb-picker-search-field></umb-picker-search-field>
|
<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 { ElementLoaderProperty } from '@umbraco-cms/backoffice/extension-api';
|
||||||
import type { UUIModalElement, UUIModalSidebarSize } from '@umbraco-cms/backoffice/external/uui';
|
import type { UUIModalElement, UUIModalSidebarSize } from '@umbraco-cms/backoffice/external/uui';
|
||||||
|
import type { UmbSearchResultItemModel } from '@umbraco-cms/backoffice/search';
|
||||||
|
|
||||||
export type * from './extensions/types.js';
|
export type * from './extensions/types.js';
|
||||||
|
|
||||||
@@ -10,9 +11,13 @@ export interface UmbPickerModalData<ItemType> {
|
|||||||
search?: UmbPickerModalSearchConfig;
|
search?: UmbPickerModalSearchConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UmbPickerModalSearchConfig<QueryParamsType = Record<string, unknown>> {
|
export interface UmbPickerModalSearchConfig<
|
||||||
|
QueryParamsType = Record<string, unknown>,
|
||||||
|
SearchResultItemType extends UmbSearchResultItemModel = UmbSearchResultItemModel,
|
||||||
|
> {
|
||||||
providerAlias: string;
|
providerAlias: string;
|
||||||
queryParams?: QueryParamsType;
|
queryParams?: QueryParamsType;
|
||||||
|
pickableFilter?: (item: SearchResultItemType) => boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UmbPickerModalValue {
|
export interface UmbPickerModalValue {
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
import type { UmbPickerDataSource } from '../data-source/types.js';
|
import type { UmbPickerDataSource } from '../data-source/types.js';
|
||||||
import type { UmbCollectionRepository } from '@umbraco-cms/backoffice/collection';
|
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';
|
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 { UmbApi } from '@umbraco-cms/backoffice/extension-api';
|
||||||
import type { UmbItemRepository } from '@umbraco-cms/backoffice/repository';
|
import type { UmbItemRepository } from '@umbraco-cms/backoffice/repository';
|
||||||
import type { UmbConfigCollectionModel } from '@umbraco-cms/backoffice/utils';
|
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;
|
setConfig?(config: UmbConfigCollectionModel | undefined): void;
|
||||||
getConfig?(): UmbConfigCollectionModel | undefined;
|
getConfig?(): UmbConfigCollectionModel | undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
import type { UmbPickerDataSource } from '../types.js';
|
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 { UmbPickerDataSource } from '../data-source/types.js';
|
||||||
import type { UmbApi } from '@umbraco-cms/backoffice/extension-api';
|
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 { UmbSearchRequestArgs, UmbSearchResultItemModel } from '@umbraco-cms/backoffice/search';
|
||||||
import type { UmbItemModel } from '@umbraco-cms/backoffice/entity-item';
|
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')
|
@customElement('umb-picker-search-result')
|
||||||
export class UmbPickerSearchResultElement extends UmbLitElement {
|
export class UmbPickerSearchResultElement extends UmbLitElement {
|
||||||
|
|||||||
@@ -172,6 +172,8 @@ export class UmbTreePickerModalElement<TreeItemType extends UmbTreeItemModelBase
|
|||||||
this._pickerContext.expansion.setExpansion(expansion);
|
this._pickerContext.expansion.setExpansion(expansion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#searchSelectableFilter = () => true;
|
||||||
|
|
||||||
override render() {
|
override render() {
|
||||||
return html`
|
return html`
|
||||||
<umb-body-layout headline=${this.localize.term('general_choose')}>
|
<umb-body-layout headline=${this.localize.term('general_choose')}>
|
||||||
@@ -181,9 +183,12 @@ export class UmbTreePickerModalElement<TreeItemType extends UmbTreeItemModelBase
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
#renderSearch() {
|
#renderSearch() {
|
||||||
|
const selectableFilter =
|
||||||
|
this.data?.search?.pickableFilter ?? this.data?.pickableFilter ?? this.#searchSelectableFilter;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<umb-picker-search-field></umb-picker-search-field>
|
<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 { UmbModalToken, type UmbPickerModalData } from '@umbraco-cms/backoffice/modal';
|
||||||
import {
|
import {
|
||||||
UMB_TREE_PICKER_MODAL_ALIAS,
|
UMB_TREE_PICKER_MODAL_ALIAS,
|
||||||
|
type UmbTreeItemModel,
|
||||||
type UmbTreePickerModalData,
|
type UmbTreePickerModalData,
|
||||||
type UmbTreePickerModalValue,
|
type UmbTreePickerModalValue,
|
||||||
} from '@umbraco-cms/backoffice/tree';
|
} from '@umbraco-cms/backoffice/tree';
|
||||||
@@ -84,6 +85,9 @@ export class UmbEntityDataPickerInputContext extends UmbPickerInputContext<UmbIt
|
|||||||
}
|
}
|
||||||
|
|
||||||
override async openPicker(pickerData?: Partial<UmbPickerModalData<UmbItemModel>>) {
|
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();
|
this.modalAlias = this.#getModalToken();
|
||||||
await super.openPicker(pickerData);
|
await super.openPicker(pickerData);
|
||||||
}
|
}
|
||||||
@@ -133,7 +137,7 @@ export class UmbEntityDataPickerInputContext extends UmbPickerInputContext<UmbIt
|
|||||||
#createTreeItemPickerModalToken(api: UmbPickerTreeDataSource) {
|
#createTreeItemPickerModalToken(api: UmbPickerTreeDataSource) {
|
||||||
const supportsSearch = isPickerSearchableDataSource(api);
|
const supportsSearch = isPickerSearchableDataSource(api);
|
||||||
|
|
||||||
return new UmbModalToken<UmbTreePickerModalData<UmbItemModel>, UmbTreePickerModalValue>(
|
return new UmbModalToken<UmbTreePickerModalData<UmbTreeItemModel>, UmbTreePickerModalValue>(
|
||||||
UMB_TREE_PICKER_MODAL_ALIAS,
|
UMB_TREE_PICKER_MODAL_ALIAS,
|
||||||
{
|
{
|
||||||
modal: {
|
modal: {
|
||||||
@@ -143,9 +147,12 @@ export class UmbEntityDataPickerInputContext extends UmbPickerInputContext<UmbIt
|
|||||||
data: {
|
data: {
|
||||||
treeAlias: UMB_ENTITY_DATA_PICKER_TREE_ALIAS,
|
treeAlias: UMB_ENTITY_DATA_PICKER_TREE_ALIAS,
|
||||||
hideTreeRoot: true,
|
hideTreeRoot: true,
|
||||||
|
// TODO: make specific pickable filter for tree to avoid type issues
|
||||||
|
pickableFilter: api.treePickableFilter,
|
||||||
search: supportsSearch
|
search: supportsSearch
|
||||||
? {
|
? {
|
||||||
providerAlias: UMB_ENTITY_DATA_PICKER_SEARCH_PROVIDER_ALIAS,
|
providerAlias: UMB_ENTITY_DATA_PICKER_SEARCH_PROVIDER_ALIAS,
|
||||||
|
pickableFilter: api.searchPickableFilter,
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
},
|
},
|
||||||
@@ -167,9 +174,12 @@ export class UmbEntityDataPickerInputContext extends UmbPickerInputContext<UmbIt
|
|||||||
collection: {
|
collection: {
|
||||||
menuAlias: UMB_ENTITY_DATA_PICKER_COLLECTION_MENU_ALIAS,
|
menuAlias: UMB_ENTITY_DATA_PICKER_COLLECTION_MENU_ALIAS,
|
||||||
},
|
},
|
||||||
|
// TODO: make specific pickable filter for collection to avoid type issues
|
||||||
|
pickableFilter: api.collectionPickableFilter,
|
||||||
search: supportsSearch
|
search: supportsSearch
|
||||||
? {
|
? {
|
||||||
providerAlias: UMB_ENTITY_DATA_PICKER_SEARCH_PROVIDER_ALIAS,
|
providerAlias: UMB_ENTITY_DATA_PICKER_SEARCH_PROVIDER_ALIAS,
|
||||||
|
pickableFilter: api.searchPickableFilter,
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user