From 5b7f92783b72dac5305c9ad74407f60036735a16 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 20 Jan 2025 11:19:41 +0100 Subject: [PATCH 01/38] add option to interface --- .../documents/documents/search/document.search-provider.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document.search-provider.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document.search-provider.ts index 6e9a94559fc0..9fae721b4383 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document.search-provider.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document.search-provider.ts @@ -3,9 +3,13 @@ import type { UmbDocumentSearchItemModel } from './types.js'; import type { UmbSearchProvider, UmbSearchRequestArgs } from '@umbraco-cms/backoffice/search'; import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; +export interface UmbDocumentSearchRequestArgs extends UmbSearchRequestArgs { + allowedContentTypes: Array<{ unique: string }>; +} + export class UmbDocumentSearchProvider extends UmbControllerBase - implements UmbSearchProvider + implements UmbSearchProvider { #repository = new UmbDocumentSearchRepository(this); From 4ffa2ff3d0b8ba24645781933ccadbb5b38ef10d Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 20 Jan 2025 11:19:58 +0100 Subject: [PATCH 02/38] pass config to picker --- .../components/input-document/input-document.element.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts index 05015e1cf8ee..ea4a8e6cb5ef 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts @@ -20,6 +20,7 @@ import { UMB_WORKSPACE_MODAL } from '@umbraco-cms/backoffice/workspace'; import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/router'; import type { UmbDocumentItemModel } from '@umbraco-cms/backoffice/document'; import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; +import { UMB_DOCUMENT_TYPE_ENTITY_TYPE } from '@umbraco-cms/backoffice/document-type'; const elementName = 'umb-input-document'; @@ -175,6 +176,8 @@ export class UmbInputDocumentElement extends UmbFormControlMixin { if (this.allowedContentTypeIds && this.allowedContentTypeIds.length > 0) { return this.allowedContentTypeIds.includes(item.documentType.unique); @@ -187,6 +190,10 @@ export class UmbInputDocumentElement extends UmbFormControlMixin ({ + unique: id, + entityType: UMB_DOCUMENT_TYPE_ENTITY_TYPE, + })), }); } From babda459ec4d88263f3420c0ce3e9c2f06541c8d Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 20 Jan 2025 11:20:18 +0100 Subject: [PATCH 03/38] add option to interface --- .../documents/modals/document-picker-modal.token.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/document-picker-modal.token.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/document-picker-modal.token.ts index 5fb0115f87ac..5d710e438d8f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/document-picker-modal.token.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/document-picker-modal.token.ts @@ -7,7 +7,10 @@ import { } from '@umbraco-cms/backoffice/tree'; import type { UmbDocumentItemModel } from '@umbraco-cms/backoffice/document'; -export type UmbDocumentPickerModalData = UmbTreePickerModalData; +export interface UmbDocumentPickerModalData extends UmbTreePickerModalData { + allowedContentTypes: Array<{ unique: string; entityType: string }>; +} + export type UmbDocumentPickerModalValue = UmbTreePickerModalValue; export const UMB_DOCUMENT_PICKER_MODAL = new UmbModalToken( From 33f2c99cc99645cd2ae06dd5f24ea5d8cff21dc1 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 20 Jan 2025 11:22:27 +0100 Subject: [PATCH 04/38] force type --- .../documents/documents/modals/document-picker-modal.token.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/document-picker-modal.token.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/document-picker-modal.token.ts index 5d710e438d8f..ff6f7e08b959 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/document-picker-modal.token.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/document-picker-modal.token.ts @@ -6,9 +6,10 @@ import { UMB_TREE_PICKER_MODAL_ALIAS, } from '@umbraco-cms/backoffice/tree'; import type { UmbDocumentItemModel } from '@umbraco-cms/backoffice/document'; +import type { UmbDocumentTypeEntityType } from '@umbraco-cms/backoffice/document-type'; export interface UmbDocumentPickerModalData extends UmbTreePickerModalData { - allowedContentTypes: Array<{ unique: string; entityType: string }>; + allowedContentTypes: Array<{ unique: string; entityType: UmbDocumentTypeEntityType }>; } export type UmbDocumentPickerModalValue = UmbTreePickerModalValue; From 330eb546c954c92cb3b4210b5a5915af32adb4d3 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 20 Jan 2025 13:56:12 +0100 Subject: [PATCH 05/38] add request args to type --- src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts | 2 +- .../src/packages/core/picker/search/manager/types.ts | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts index 061086786c82..152977158da2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts @@ -12,7 +12,7 @@ export interface UmbPickerModalData { export interface UmbPickerModalSearchConfig { providerAlias: string; - queryParams?: object; + requestArgs?: object; } export interface UmbPickerModalValue { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/types.ts index a8ef1e5a670d..3b5cea857836 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/types.ts @@ -1,6 +1,8 @@ import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity'; -export interface UmbPickerSearchManagerConfig { +export interface UmbPickerSearchManagerConfig { providerAlias: string; + // TODO: searchFrom should have been part of the requestArgs object to make the type more flexible searchFrom?: UmbEntityModel; + requestArgs?: SearchRequestArgsType; } From 8cab8eb5b6124d87a3b958ecb3c08c33f1db04cc Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 20 Jan 2025 13:57:20 +0100 Subject: [PATCH 06/38] pass allowed content types as request args --- .../tree-picker-modal.element.ts | 6 ++- .../input-document/input-document.context.ts | 45 ++++++++++++++++++- .../input-document/input-document.element.ts | 30 +++++-------- .../modals/document-picker-modal.token.ts | 6 +-- 4 files changed, 62 insertions(+), 25 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts index 9f775bf18911..7df964bb6fa4 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts @@ -55,7 +55,11 @@ export class UmbTreePickerModalElement; +} export class UmbDocumentPickerInputContext extends UmbPickerInputContext< UmbDocumentItemModel, @@ -14,6 +23,40 @@ export class UmbDocumentPickerInputContext extends UmbPickerInputContext< constructor(host: UmbControllerHost) { super(host, UMB_DOCUMENT_ITEM_REPOSITORY_ALIAS, UMB_DOCUMENT_PICKER_MODAL, (entry) => entry.unique); } + + override async openPicker(pickerData?: Partial, args?: UmbOpenDocumentPickerArgs) { + const pickerConfig = { + ...pickerData, + }; + + pickerConfig.pickableFilter = (item) => this.#pickableFilter(item, args?.allowedContentTypes); + + if (!pickerData?.search) { + pickerConfig.search = { + providerAlias: UMB_DOCUMENT_SEARCH_PROVIDER_ALIAS, + ...pickerData?.search, + }; + } + + pickerConfig.search!.requestArgs = { + allowedContentTypes: args?.allowedContentTypes, + ...pickerData?.search?.requestArgs, + }; + + super.openPicker(pickerConfig); + } + + #pickableFilter = ( + item: UmbDocumentItemModel, + allowedContentTypes?: Array<{ unique: string; entityType: UmbDocumentTypeEntityType }>, + ): boolean => { + if (allowedContentTypes && allowedContentTypes.length > 0) { + return allowedContentTypes + .map((contentTypeReference) => contentTypeReference.unique) + .includes(item.documentType.unique); + } + return true; + }; } /** @deprecated Use `UmbDocumentPickerInputContext` instead. This method will be removed in Umbraco 15. */ diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts index ea4a8e6cb5ef..c16b2c675968 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.element.ts @@ -176,25 +176,19 @@ export class UmbInputDocumentElement extends UmbFormControlMixin { - if (this.allowedContentTypeIds && this.allowedContentTypeIds.length > 0) { - return this.allowedContentTypeIds.includes(item.documentType.unique); - } - return true; - }; - #openPicker() { - this.#pickerContext.openPicker({ - hideTreeRoot: true, - pickableFilter: this.#pickableFilter, - startNode: this.startNode, - allowedContentTypes: this.allowedContentTypeIds?.map((id) => ({ - unique: id, - entityType: UMB_DOCUMENT_TYPE_ENTITY_TYPE, - })), - }); + this.#pickerContext.openPicker( + { + hideTreeRoot: true, + startNode: this.startNode, + }, + { + allowedContentTypes: this.allowedContentTypeIds?.map((id) => ({ + unique: id, + entityType: UMB_DOCUMENT_TYPE_ENTITY_TYPE, + })), + }, + ); } #onRemove(item: UmbDocumentItemModel) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/document-picker-modal.token.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/document-picker-modal.token.ts index ff6f7e08b959..5fb0115f87ac 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/document-picker-modal.token.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/document-picker-modal.token.ts @@ -6,12 +6,8 @@ import { UMB_TREE_PICKER_MODAL_ALIAS, } from '@umbraco-cms/backoffice/tree'; import type { UmbDocumentItemModel } from '@umbraco-cms/backoffice/document'; -import type { UmbDocumentTypeEntityType } from '@umbraco-cms/backoffice/document-type'; - -export interface UmbDocumentPickerModalData extends UmbTreePickerModalData { - allowedContentTypes: Array<{ unique: string; entityType: UmbDocumentTypeEntityType }>; -} +export type UmbDocumentPickerModalData = UmbTreePickerModalData; export type UmbDocumentPickerModalValue = UmbTreePickerModalValue; export const UMB_DOCUMENT_PICKER_MODAL = new UmbModalToken( From d110d5308904c1505a7d0ac44cf650d8a7a504e7 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 20 Jan 2025 14:09:39 +0100 Subject: [PATCH 07/38] add comments --- .../input-document/input-document.context.ts | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.context.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.context.ts index a1124dbcb40e..e08be7dc4c88 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.context.ts @@ -10,7 +10,7 @@ import { UmbPickerInputContext } from '@umbraco-cms/backoffice/picker-input'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import type { UmbDocumentTypeEntityType } from '@umbraco-cms/backoffice/document-type'; -interface UmbOpenDocumentPickerArgs { +interface UmbInputDocumentOpenPickerArgs { allowedContentTypes?: Array<{ unique: string; entityType: UmbDocumentTypeEntityType }>; } @@ -24,26 +24,29 @@ export class UmbDocumentPickerInputContext extends UmbPickerInputContext< super(host, UMB_DOCUMENT_ITEM_REPOSITORY_ALIAS, UMB_DOCUMENT_PICKER_MODAL, (entry) => entry.unique); } - override async openPicker(pickerData?: Partial, args?: UmbOpenDocumentPickerArgs) { - const pickerConfig = { + override async openPicker(pickerData?: Partial, args?: UmbInputDocumentOpenPickerArgs) { + const combinedPickerData = { ...pickerData, }; - pickerConfig.pickableFilter = (item) => this.#pickableFilter(item, args?.allowedContentTypes); + // transform allowedContentTypes to a pickable filter + combinedPickerData.pickableFilter = (item) => this.#pickableFilter(item, args?.allowedContentTypes); + // set default search data if (!pickerData?.search) { - pickerConfig.search = { + combinedPickerData.search = { providerAlias: UMB_DOCUMENT_SEARCH_PROVIDER_ALIAS, ...pickerData?.search, }; } - pickerConfig.search!.requestArgs = { + // pass allowedContentTypes to the search request args + combinedPickerData.search!.requestArgs = { allowedContentTypes: args?.allowedContentTypes, ...pickerData?.search?.requestArgs, }; - super.openPicker(pickerConfig); + super.openPicker(combinedPickerData); } #pickableFilter = ( From e470350108728c123db9fc1238ed12a925e2d845 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 20 Jan 2025 14:29:25 +0100 Subject: [PATCH 08/38] allow for passing type --- .../src/packages/search/search-repository.interface.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/search/search-repository.interface.ts b/src/Umbraco.Web.UI.Client/src/packages/search/search-repository.interface.ts index d13705beb10b..bcd77f3773d6 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/search/search-repository.interface.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/search/search-repository.interface.ts @@ -1,6 +1,9 @@ import type { UmbSearchRequestArgs, UmbSearchResultItemModel } from './types.js'; import type { UmbRepositoryResponse, UmbPagedModel } from '@umbraco-cms/backoffice/repository'; -export interface UmbSearchRepository { - search(args: UmbSearchRequestArgs): Promise>>; +export interface UmbSearchRepository< + SearchResultItemType extends UmbSearchResultItemModel, + SearchRequestArgsType extends UmbSearchRequestArgs = UmbSearchRequestArgs, +> { + search(args: SearchRequestArgsType): Promise>>; } From 7eb9f5d2cd67ddd4b1e68649602a00a3a5599b31 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 20 Jan 2025 14:32:31 +0100 Subject: [PATCH 09/38] more type safety --- .../documents/search/document-search.repository.ts | 6 +++--- .../src/packages/documents/documents/search/types.ts | 6 ++++++ .../src/packages/search/search-data-source.interface.ts | 7 +++++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search.repository.ts index 3e34af40ff38..519d795a07fa 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search.repository.ts @@ -1,6 +1,6 @@ import { UmbDocumentSearchServerDataSource } from './document-search.server.data-source.js'; -import type { UmbDocumentSearchItemModel } from './types.js'; -import type { UmbSearchRepository, UmbSearchRequestArgs } from '@umbraco-cms/backoffice/search'; +import type { UmbDocumentSearchItemModel, UmbDocumentSearchRequestArgs } from './types.js'; +import type { UmbSearchRepository } from '@umbraco-cms/backoffice/search'; import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import type { UmbApi } from '@umbraco-cms/backoffice/extension-api'; @@ -17,7 +17,7 @@ export class UmbDocumentSearchRepository this.#dataSource = new UmbDocumentSearchServerDataSource(this); } - search(args: UmbSearchRequestArgs) { + search(args: UmbDocumentSearchRequestArgs) { return this.#dataSource.search(args); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/types.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/types.ts index ff91e7037c5c..a91e2196da4a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/types.ts @@ -1,5 +1,11 @@ import type { UmbDocumentItemModel } from '../repository/index.js'; +import type { UmbSearchRequestArgs } from '@umbraco-cms/backoffice/search'; +import type { UmbDocumentTypeEntityType } from '@umbraco-cms/backoffice/document-type'; export interface UmbDocumentSearchItemModel extends UmbDocumentItemModel { href: string; } + +export interface UmbDocumentSearchRequestArgs extends UmbSearchRequestArgs { + allowedContentTypes: Array<{ unique: string; entityType: UmbDocumentTypeEntityType }>; +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/search/search-data-source.interface.ts b/src/Umbraco.Web.UI.Client/src/packages/search/search-data-source.interface.ts index 7b54ac9237e5..5c9fff8d73f5 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/search/search-data-source.interface.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/search/search-data-source.interface.ts @@ -6,6 +6,9 @@ export interface UmbSearchDataSourceConstructor; } -export interface UmbSearchDataSource { - search(args: UmbSearchRequestArgs): Promise>>; +export interface UmbSearchDataSource< + SearchResultItemType extends UmbSearchResultItemModel, + RequestArgsType extends UmbSearchRequestArgs = UmbSearchRequestArgs, +> { + search(args: RequestArgsType): Promise>>; } From 3babe8ef8883520fe02a92c6f6db9090d6af96c1 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 20 Jan 2025 14:32:41 +0100 Subject: [PATCH 10/38] use correct types --- .../documents/search/document.search-provider.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document.search-provider.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document.search-provider.ts index 9fae721b4383..f28137a2f1a6 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document.search-provider.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document.search-provider.ts @@ -1,19 +1,15 @@ import { UmbDocumentSearchRepository } from './document-search.repository.js'; -import type { UmbDocumentSearchItemModel } from './types.js'; -import type { UmbSearchProvider, UmbSearchRequestArgs } from '@umbraco-cms/backoffice/search'; +import type { UmbDocumentSearchItemModel, UmbDocumentSearchRequestArgs } from './types.js'; +import type { UmbSearchProvider } from '@umbraco-cms/backoffice/search'; import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; -export interface UmbDocumentSearchRequestArgs extends UmbSearchRequestArgs { - allowedContentTypes: Array<{ unique: string }>; -} - export class UmbDocumentSearchProvider extends UmbControllerBase implements UmbSearchProvider { #repository = new UmbDocumentSearchRepository(this); - search(args: UmbSearchRequestArgs) { + search(args: UmbDocumentSearchRequestArgs) { return this.#repository.search(args); } From 884904d318c2ab334eeb3a67e65452a780d653ba Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 20 Jan 2025 14:32:57 +0100 Subject: [PATCH 11/38] use correct types --- .../search/document-search.server.data-source.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search.server.data-source.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search.server.data-source.ts index 961fdfd54da8..7bee14b8cf23 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search.server.data-source.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search.server.data-source.ts @@ -1,6 +1,6 @@ import { UMB_DOCUMENT_ENTITY_TYPE } from '../entity.js'; -import type { UmbDocumentSearchItemModel } from './types.js'; -import type { UmbSearchDataSource, UmbSearchRequestArgs } from '@umbraco-cms/backoffice/search'; +import type { UmbDocumentSearchItemModel, UmbDocumentSearchRequestArgs } from './types.js'; +import type { UmbSearchDataSource } from '@umbraco-cms/backoffice/search'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { DocumentService } from '@umbraco-cms/backoffice/external/backend-api'; import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; @@ -10,7 +10,9 @@ import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; * @class UmbDocumentSearchServerDataSource * @implements {RepositoryDetailDataSource} */ -export class UmbDocumentSearchServerDataSource implements UmbSearchDataSource { +export class UmbDocumentSearchServerDataSource + implements UmbSearchDataSource +{ #host: UmbControllerHost; /** @@ -24,16 +26,18 @@ export class UmbDocumentSearchServerDataSource implements UmbSearchDataSource Date: Mon, 20 Jan 2025 14:42:45 +0100 Subject: [PATCH 12/38] add js docs --- .../documents/search/document-search.repository.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search.repository.ts index 519d795a07fa..8f91f30397ff 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search.repository.ts @@ -4,6 +4,7 @@ import type { UmbSearchRepository } from '@umbraco-cms/backoffice/search'; import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import type { UmbApi } from '@umbraco-cms/backoffice/extension-api'; +import type { UmbPagedModel, UmbRepositoryResponse } from '@umbraco-cms/backoffice/repository'; export class UmbDocumentSearchRepository extends UmbControllerBase @@ -13,11 +14,18 @@ export class UmbDocumentSearchRepository constructor(host: UmbControllerHost) { super(host); - this.#dataSource = new UmbDocumentSearchServerDataSource(this); } - search(args: UmbDocumentSearchRequestArgs) { + /** + * Search for documents + * @param {UmbDocumentSearchRequestArgs} args - The arguments for the search + * @returns {Promise>>} - The search results + * @memberof UmbDocumentSearchRepository + */ + search( + args: UmbDocumentSearchRequestArgs, + ): Promise>> { return this.#dataSource.search(args); } } From d833239886c38de501badd544c1a484a856fed1e Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 20 Jan 2025 14:43:11 +0100 Subject: [PATCH 13/38] remove debugger + map to only pass id to server --- .../documents/search/document-search.server.data-source.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search.server.data-source.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search.server.data-source.ts index 7bee14b8cf23..b48be625b914 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search.server.data-source.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search.server.data-source.ts @@ -31,13 +31,12 @@ export class UmbDocumentSearchServerDataSource * @memberof UmbDocumentSearchServerDataSource */ async search(args: UmbDocumentSearchRequestArgs) { - debugger; const { data, error } = await tryExecuteAndNotify( this.#host, DocumentService.getItemDocumentSearch({ query: args.query, parentId: args.searchFrom?.unique ?? undefined, - allowedDocumentTypes: args.allowedContentTypes, + allowedDocumentTypes: args.allowedContentTypes.map((contentType) => contentType.unique), }), ); From b7d40537e90d3d88d141fc2aaf65dbceba890fb0 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 20 Jan 2025 14:46:59 +0100 Subject: [PATCH 14/38] add js docs --- .../search/document.search-provider.ts | 17 ++++++++++++++++- .../documents/documents/search/types.ts | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document.search-provider.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document.search-provider.ts index f28137a2f1a6..1dfb88a990e5 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document.search-provider.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document.search-provider.ts @@ -2,14 +2,29 @@ import { UmbDocumentSearchRepository } from './document-search.repository.js'; import type { UmbDocumentSearchItemModel, UmbDocumentSearchRequestArgs } from './types.js'; import type { UmbSearchProvider } from '@umbraco-cms/backoffice/search'; import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; +import type { UmbPagedModel, UmbRepositoryResponse } from '@umbraco-cms/backoffice/repository'; +/** + * The document search provider + * @class UmbDocumentSearchProvider + * @augments {UmbControllerBase} + * @implements {UmbSearchProvider} + */ export class UmbDocumentSearchProvider extends UmbControllerBase implements UmbSearchProvider { #repository = new UmbDocumentSearchRepository(this); - search(args: UmbDocumentSearchRequestArgs) { + /** + * Search for documents + * @param {UmbDocumentSearchRequestArgs} args - The arguments for the search + * @returns {Promise>>} - The search results + * @memberof UmbDocumentSearchProvider + */ + search( + args: UmbDocumentSearchRequestArgs, + ): Promise>> { return this.#repository.search(args); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/types.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/types.ts index a91e2196da4a..a63f89853bd7 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/types.ts @@ -7,5 +7,5 @@ export interface UmbDocumentSearchItemModel extends UmbDocumentItemModel { } export interface UmbDocumentSearchRequestArgs extends UmbSearchRequestArgs { - allowedContentTypes: Array<{ unique: string; entityType: UmbDocumentTypeEntityType }>; + allowedContentTypes?: Array<{ unique: string; entityType: UmbDocumentTypeEntityType }>; } From 8851e29510ab9265969939bb3ded9622bb508130 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 20 Jan 2025 14:51:04 +0100 Subject: [PATCH 15/38] align naming --- .../search/manager/picker-search.manager.ts | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts index 2997327f6aa5..4893d7fe70dd 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts @@ -12,16 +12,16 @@ import { debounce } from '@umbraco-cms/backoffice/utils'; * @class UmbPickerSearchManager * @augments {UmbControllerBase} * @template ResultItemType - * @template QueryType + * @template SearchRequestArgsType */ export class UmbPickerSearchManager< ResultItemType extends UmbSearchResultItemModel = UmbSearchResultItemModel, - QueryType extends UmbSearchRequestArgs = UmbSearchRequestArgs, + SearchRequestArgsType extends UmbSearchRequestArgs = UmbSearchRequestArgs, > extends UmbControllerBase { #searchable = new UmbBooleanState(false); public readonly searchable = this.#searchable.asObservable(); - #query = new UmbObjectState(undefined); + #query = new UmbObjectState(undefined); public readonly query = this.#query.asObservable(); #searching = new UmbBooleanState(false); @@ -34,7 +34,7 @@ export class UmbPickerSearchManager< public readonly resultTotalItems = this.#resultTotalItems.asObservable(); #config?: UmbPickerSearchManagerConfig; - #searchProvider?: UmbSearchProvider; + #searchProvider?: UmbSearchProvider; /** * Creates an instance of UmbPickerSearchManager. @@ -122,10 +122,10 @@ export class UmbPickerSearchManager< /** * Set the search query. - * @param {QueryType} query The search query. + * @param {SearchRequestArgsType} query The search query. * @memberof UmbPickerSearchManager */ - public setQuery(query: QueryType) { + public setQuery(query: SearchRequestArgsType) { if (this.getSearchable() === false) throw new Error('Search is not enabled'); if (!this.query) { this.clear(); @@ -138,19 +138,19 @@ export class UmbPickerSearchManager< /** * Get the current search query. * @memberof UmbPickerSearchManager - * @returns {QueryType | undefined} The current search query. + * @returns {SearchRequestArgsType | undefined} The current search query. */ - public getQuery(): QueryType | undefined { + public getQuery(): SearchRequestArgsType | undefined { return this.#query.getValue(); } /** * Update the current search query. - * @param {Partial} query + * @param {Partial} query * @memberof UmbPickerSearchManager */ - public updateQuery(query: Partial) { - const mergedQuery = { ...this.getQuery(), ...query } as QueryType; + public updateQuery(query: Partial) { + const mergedQuery = { ...this.getQuery(), ...query } as SearchRequestArgsType; this.#query.setValue(mergedQuery); } @@ -186,6 +186,7 @@ export class UmbPickerSearchManager< const args = { searchFrom: this.#config?.searchFrom, + ...this.#config?.requestArgs, ...query, }; From fd9e0ddea34dd666580c129dfe67507ffdd8188c Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 20 Jan 2025 15:18:17 +0100 Subject: [PATCH 16/38] add null check --- .../documents/search/document-search.server.data-source.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search.server.data-source.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search.server.data-source.ts index b48be625b914..bfb561c99fb5 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search.server.data-source.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search.server.data-source.ts @@ -36,7 +36,7 @@ export class UmbDocumentSearchServerDataSource DocumentService.getItemDocumentSearch({ query: args.query, parentId: args.searchFrom?.unique ?? undefined, - allowedDocumentTypes: args.allowedContentTypes.map((contentType) => contentType.unique), + allowedDocumentTypes: args.allowedContentTypes?.map((contentType) => contentType.unique), }), ); From 210b82ca648abe3b06887a8924f90d0e0dcb1d25 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 20 Jan 2025 15:18:28 +0100 Subject: [PATCH 17/38] align types --- .../member-picker-modal.token.ts | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/components/member-picker-modal/member-picker-modal.token.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/components/member-picker-modal/member-picker-modal.token.ts index 8da183eefebf..a49bce2f6180 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member/components/member-picker-modal/member-picker-modal.token.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/components/member-picker-modal/member-picker-modal.token.ts @@ -1,17 +1,10 @@ import type { UmbMemberItemModel } from '../../repository/index.js'; import { UMB_MEMBER_SEARCH_PROVIDER_ALIAS } from '../../search/constants.js'; -import type { UmbPickerModalSearchConfig } from '@umbraco-cms/backoffice/modal'; +import type { UmbPickerModalData, UmbPickerModalValue } from '@umbraco-cms/backoffice/modal'; import { UmbModalToken } from '@umbraco-cms/backoffice/modal'; -export interface UmbMemberPickerModalData { - multiple?: boolean; - filter?: (member: UmbMemberItemModel) => boolean; - search?: UmbPickerModalSearchConfig; -} - -export interface UmbMemberPickerModalValue { - selection: Array; -} +export type UmbMemberPickerModalData = UmbPickerModalData; +export type UmbMemberPickerModalValue = UmbPickerModalValue; export const UMB_MEMBER_PICKER_MODAL = new UmbModalToken( 'Umb.Modal.MemberPicker', From fa2c45cfdf68eee7badf32797e3a9a2a076e5ae4 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 20 Jan 2025 15:43:32 +0100 Subject: [PATCH 18/38] implement allowedContentTypes for member search --- .../input-member/input-member.context.ts | 57 ++++++++++++++++++- .../input-member/input-member.element.ts | 23 ++++---- .../member-search.server.data-source.ts | 8 ++- .../member/search/member.search-provider.ts | 15 +++-- .../packages/members/member/search/types.ts | 11 ++++ 5 files changed, 90 insertions(+), 24 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/members/member/search/types.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/components/input-member/input-member.context.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/components/input-member/input-member.context.ts index ca77c272acbf..a334d8b0904b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member/components/input-member/input-member.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/components/input-member/input-member.context.ts @@ -1,13 +1,64 @@ import type { UmbMemberItemModel } from '../../repository/index.js'; -import { UMB_MEMBER_PICKER_MODAL } from '../member-picker-modal/member-picker-modal.token.js'; -import { UMB_MEMBER_ITEM_REPOSITORY_ALIAS } from '../../constants.js'; +import { + UMB_MEMBER_PICKER_MODAL, + type UmbMemberPickerModalData, + type UmbMemberPickerModalValue, +} from '../member-picker-modal/member-picker-modal.token.js'; +import { UMB_MEMBER_ITEM_REPOSITORY_ALIAS, UMB_MEMBER_SEARCH_PROVIDER_ALIAS } from '../../constants.js'; import { UmbPickerInputContext } from '@umbraco-cms/backoffice/picker-input'; import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; +import type { UmbMemberTypeEntityType } from '@umbraco-cms/backoffice/member-type'; -export class UmbMemberPickerInputContext extends UmbPickerInputContext { +interface UmbInputMemberOpenPickerArgs { + allowedContentTypes?: Array<{ unique: string; entityType: UmbMemberTypeEntityType }>; +} + +export class UmbMemberPickerInputContext extends UmbPickerInputContext< + UmbMemberItemModel, + UmbMemberItemModel, + UmbMemberPickerModalData, + UmbMemberPickerModalValue +> { constructor(host: UmbControllerHostElement) { super(host, UMB_MEMBER_ITEM_REPOSITORY_ALIAS, UMB_MEMBER_PICKER_MODAL); } + + override async openPicker(pickerData?: Partial, args?: UmbInputMemberOpenPickerArgs) { + const combinedPickerData = { + ...pickerData, + }; + + // transform allowedContentTypes to a pickable filter + combinedPickerData.pickableFilter = (item) => this.#pickableFilter(item, args?.allowedContentTypes); + + // set default search data + if (!pickerData?.search) { + combinedPickerData.search = { + providerAlias: UMB_MEMBER_SEARCH_PROVIDER_ALIAS, + ...pickerData?.search, + }; + } + + // pass allowedContentTypes to the search request args + combinedPickerData.search!.requestArgs = { + allowedContentTypes: args?.allowedContentTypes, + ...pickerData?.search?.requestArgs, + }; + + super.openPicker(combinedPickerData); + } + + #pickableFilter = ( + item: UmbMemberItemModel, + allowedContentTypes?: Array<{ unique: string; entityType: UmbMemberTypeEntityType }>, + ): boolean => { + if (allowedContentTypes && allowedContentTypes.length > 0) { + return allowedContentTypes + .map((contentTypeReference) => contentTypeReference.unique) + .includes(item.memberType.unique); + } + return true; + }; } /** @deprecated Use `UmbMemberPickerInputContext` instead. This method will be removed in Umbraco 15. */ diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/components/input-member/input-member.element.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/components/input-member/input-member.element.ts index 9f782e9ea926..0186182e6336 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member/components/input-member/input-member.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/components/input-member/input-member.element.ts @@ -8,6 +8,7 @@ import { UMB_WORKSPACE_MODAL } from '@umbraco-cms/backoffice/workspace'; import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/router'; import { UmbSorterController } from '@umbraco-cms/backoffice/sorter'; import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; +import { UMB_MEMBER_TYPE_ENTITY_TYPE } from '@umbraco-cms/backoffice/member-type'; const elementName = 'umb-input-member'; @@ -159,18 +160,18 @@ export class UmbInputMemberElement extends UmbFormControlMixin (this._items = selectedItems), '_observeItems'); } - #pickableFilter = (item: UmbMemberItemModel): boolean => { - if (this.allowedContentTypeIds && this.allowedContentTypeIds.length > 0) { - return this.allowedContentTypeIds.includes(item.memberType.unique); - } - return true; - }; - #openPicker() { - this.#pickerContext.openPicker({ - filter: this.filter, - pickableFilter: this.#pickableFilter, - }); + this.#pickerContext.openPicker( + { + filter: this.filter, + }, + { + allowedContentTypes: this.allowedContentTypeIds?.map((id) => ({ + unique: id, + entityType: UMB_MEMBER_TYPE_ENTITY_TYPE, + })), + }, + ); } #onRemove(item: UmbMemberItemModel) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/search/member-search.server.data-source.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/search/member-search.server.data-source.ts index febcdd024c57..2c1a36a4bae3 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member/search/member-search.server.data-source.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/search/member-search.server.data-source.ts @@ -1,5 +1,6 @@ import { UMB_MEMBER_ENTITY_TYPE } from '../entity.js'; import type { UmbMemberSearchItemModel } from './member.search-provider.js'; +import type { UmbMemberSearchRequestArgs } from './types.js'; import type { UmbSearchDataSource, UmbSearchRequestArgs } from '@umbraco-cms/backoffice/search'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { MemberService } from '@umbraco-cms/backoffice/external/backend-api'; @@ -10,7 +11,9 @@ import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; * @class UmbMemberSearchServerDataSource * @implements {RepositoryDetailDataSource} */ -export class UmbMemberSearchServerDataSource implements UmbSearchDataSource { +export class UmbMemberSearchServerDataSource + implements UmbSearchDataSource +{ #host: UmbControllerHost; /** @@ -28,11 +31,12 @@ export class UmbMemberSearchServerDataSource implements UmbSearchDataSource memberReference.unique), }), ); diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/search/member.search-provider.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/search/member.search-provider.ts index ab714dca8ce7..01da79605afa 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member/search/member.search-provider.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/search/member.search-provider.ts @@ -1,16 +1,15 @@ -import type { UmbMemberItemModel } from '../repository/item/types.js'; import { UmbMemberSearchRepository } from './member-search.repository.js'; -import type { UmbSearchProvider, UmbSearchRequestArgs } from '@umbraco-cms/backoffice/search'; +import type { UmbMemberSearchItemModel, UmbMemberSearchRequestArgs } from './types.js'; +import type { UmbSearchProvider } from '@umbraco-cms/backoffice/search'; import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; -export interface UmbMemberSearchItemModel extends UmbMemberItemModel { - href: string; -} - -export class UmbMemberSearchProvider extends UmbControllerBase implements UmbSearchProvider { +export class UmbMemberSearchProvider + extends UmbControllerBase + implements UmbSearchProvider +{ #repository = new UmbMemberSearchRepository(this); - async search(args: UmbSearchRequestArgs) { + async search(args: UmbMemberSearchRequestArgs) { return this.#repository.search(args); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/search/types.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/search/types.ts new file mode 100644 index 000000000000..6ee8fceef593 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/search/types.ts @@ -0,0 +1,11 @@ +import type { UmbMemberItemModel } from '../repository/index.js'; +import type { UmbMemberTypeEntityType } from '@umbraco-cms/backoffice/member-type'; +import type { UmbSearchRequestArgs } from '@umbraco-cms/backoffice/search'; + +export interface UmbMemberSearchItemModel extends UmbMemberItemModel { + href: string; +} + +export interface UmbMemberSearchRequestArgs extends UmbSearchRequestArgs { + allowedContentTypes?: Array<{ unique: string; entityType: UmbMemberTypeEntityType }>; +} From 7b4c45092caf3589ee3413718a1c0fb3f22c995c Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 20 Jan 2025 16:11:45 +0100 Subject: [PATCH 19/38] fix imports --- .../members/member/search/member-search.repository.ts | 2 +- .../member/search/member-search.server.data-source.ts | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/search/member-search.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/search/member-search.repository.ts index 67e270b90d5d..8e0e4e884c83 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member/search/member-search.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/search/member-search.repository.ts @@ -1,5 +1,5 @@ import { UmbMemberSearchServerDataSource } from './member-search.server.data-source.js'; -import type { UmbMemberSearchItemModel } from './member.search-provider.js'; +import type { UmbMemberSearchItemModel } from './types.js'; import type { UmbSearchRepository, UmbSearchRequestArgs } from '@umbraco-cms/backoffice/search'; import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/search/member-search.server.data-source.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/search/member-search.server.data-source.ts index 2c1a36a4bae3..6a95cef4311f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member/search/member-search.server.data-source.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/search/member-search.server.data-source.ts @@ -1,7 +1,6 @@ import { UMB_MEMBER_ENTITY_TYPE } from '../entity.js'; -import type { UmbMemberSearchItemModel } from './member.search-provider.js'; -import type { UmbMemberSearchRequestArgs } from './types.js'; -import type { UmbSearchDataSource, UmbSearchRequestArgs } from '@umbraco-cms/backoffice/search'; +import type { UmbMemberSearchItemModel, UmbMemberSearchRequestArgs } from './types.js'; +import type { UmbSearchDataSource } from '@umbraco-cms/backoffice/search'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { MemberService } from '@umbraco-cms/backoffice/external/backend-api'; import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; From f987b3e2555d6c3322a1071725ad7b4a75414e34 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 20 Jan 2025 18:33:43 +0100 Subject: [PATCH 20/38] add types for media search --- .../media/media/search/media-search.repository.ts | 8 ++++---- .../search/media-search.server.data-source.ts | 14 +++++++++----- .../media/media/search/media.search-provider.ts | 11 +++++++---- .../src/packages/media/media/search/types.ts | 6 ++++++ 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/search/media-search.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/search/media-search.repository.ts index d47162bcbe7b..407dd494bed3 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/search/media-search.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/search/media-search.repository.ts @@ -1,13 +1,13 @@ import { UmbMediaSearchServerDataSource } from './media-search.server.data-source.js'; -import type { UmbMediaSearchItemModel } from './types.js'; -import type { UmbSearchRepository, UmbSearchRequestArgs } from '@umbraco-cms/backoffice/search'; +import type { UmbMediaSearchItemModel, UmbMediaSearchRequestArgs } from './types.js'; +import type { UmbSearchRepository } from '@umbraco-cms/backoffice/search'; import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import type { UmbApi } from '@umbraco-cms/backoffice/extension-api'; export class UmbMediaSearchRepository extends UmbControllerBase - implements UmbSearchRepository, UmbApi + implements UmbSearchRepository, UmbApi { #dataSource: UmbMediaSearchServerDataSource; @@ -17,7 +17,7 @@ export class UmbMediaSearchRepository this.#dataSource = new UmbMediaSearchServerDataSource(this); } - search(args: UmbSearchRequestArgs) { + search(args: UmbMediaSearchRequestArgs) { return this.#dataSource.search(args); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/search/media-search.server.data-source.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/search/media-search.server.data-source.ts index 5edc2a27373d..52881ba45576 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/search/media-search.server.data-source.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/search/media-search.server.data-source.ts @@ -1,6 +1,6 @@ import { UMB_MEDIA_ENTITY_TYPE } from '../entity.js'; -import type { UmbMediaSearchItemModel } from './types.js'; -import type { UmbSearchDataSource, UmbSearchRequestArgs } from '@umbraco-cms/backoffice/search'; +import type { UmbMediaSearchItemModel, UmbMediaSearchRequestArgs } from './types.js'; +import type { UmbSearchDataSource } from '@umbraco-cms/backoffice/search'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { MediaService } from '@umbraco-cms/backoffice/external/backend-api'; import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; @@ -10,7 +10,9 @@ import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; * @class UmbMediaSearchServerDataSource * @implements {RepositoryDetailDataSource} */ -export class UmbMediaSearchServerDataSource implements UmbSearchDataSource { +export class UmbMediaSearchServerDataSource + implements UmbSearchDataSource +{ #host: UmbControllerHost; /** @@ -24,16 +26,18 @@ export class UmbMediaSearchServerDataSource implements UmbSearchDataSource mediaReference.unique), }), ); diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/search/media.search-provider.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/search/media.search-provider.ts index fa9439674e67..bdf2ca08ac55 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/search/media.search-provider.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/search/media.search-provider.ts @@ -1,12 +1,15 @@ import { UmbMediaSearchRepository } from './media-search.repository.js'; -import type { UmbMediaSearchItemModel } from './types.js'; -import type { UmbSearchProvider, UmbSearchRequestArgs } from '@umbraco-cms/backoffice/search'; +import type { UmbMediaSearchItemModel, UmbMediaSearchRequestArgs } from './types.js'; +import type { UmbSearchProvider } from '@umbraco-cms/backoffice/search'; import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; -export class UmbMediaSearchProvider extends UmbControllerBase implements UmbSearchProvider { +export class UmbMediaSearchProvider + extends UmbControllerBase + implements UmbSearchProvider +{ #repository = new UmbMediaSearchRepository(this); - async search(args: UmbSearchRequestArgs) { + async search(args: UmbMediaSearchRequestArgs) { return this.#repository.search(args); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/search/types.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/search/types.ts index 610c12cfb4e0..246505347e95 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/search/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/search/types.ts @@ -1,5 +1,11 @@ import type { UmbMediaItemModel } from '../types.js'; +import type { UmbSearchRequestArgs } from '@umbraco-cms/backoffice/search'; +import type { UmbMediaTypeEntityType } from '@umbraco-cms/backoffice/media-type'; export interface UmbMediaSearchItemModel extends UmbMediaItemModel { href: string; } + +export interface UmbMediaSearchRequestArgs extends UmbSearchRequestArgs { + allowedContentTypes?: Array<{ unique: string; entityType: UmbMediaTypeEntityType }>; +} From 8782e90c22d223f79736d445156d57705b71af6b Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 20 Jan 2025 18:33:56 +0100 Subject: [PATCH 21/38] add and use const --- .../src/packages/media/media/search/constants.ts | 1 + .../src/packages/media/media/search/manifests.ts | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 src/Umbraco.Web.UI.Client/src/packages/media/media/search/constants.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/search/constants.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/search/constants.ts new file mode 100644 index 000000000000..8a888cf4ac07 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/search/constants.ts @@ -0,0 +1 @@ +export const UMB_MEDIA_SEARCH_PROVIDER_ALIAS = 'Umb.SearchProvider.Media'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/search/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/search/manifests.ts index 73a1508bf8b7..82e9d81d681f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/search/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/search/manifests.ts @@ -1,9 +1,10 @@ import { UMB_MEDIA_ENTITY_TYPE } from '../entity.js'; +import { UMB_MEDIA_SEARCH_PROVIDER_ALIAS } from './constants.js'; export const manifests: Array = [ { name: 'Media Search Provider', - alias: 'Umb.SearchProvider.Media', + alias: UMB_MEDIA_SEARCH_PROVIDER_ALIAS, type: 'searchProvider', api: () => import('./media.search-provider.js'), weight: 700, From d4959cd4c799da10350df1cd8bbd0f63eb7d9aa7 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 20 Jan 2025 18:34:19 +0100 Subject: [PATCH 22/38] align picker interfaces --- .../media-picker/media-picker-modal.token.ts | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.token.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.token.ts index 3e7cc803483b..aebece4e353d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.token.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.token.ts @@ -1,17 +1,11 @@ -import { UmbModalToken } from '@umbraco-cms/backoffice/modal'; +import type { UmbMediaItemModel } from '../../repository/types.js'; +import type { UmbTreePickerModalData } from '@umbraco-cms/backoffice/tree'; +import { UmbModalToken, type UmbPickerModalValue } from '@umbraco-cms/backoffice/modal'; -export interface UmbMediaPickerModalData { - startNode?: string | null; - multiple?: boolean; - pickableFilter?: (item: ItemType) => boolean; - filter?: (item: ItemType) => boolean; -} +export type UmbMediaPickerModalData = UmbTreePickerModalData; +export type UmbMediaPickerModalValue = UmbPickerModalValue; -export interface UmbMediaPickerModalValue { - selection: string[]; -} - -export const UMB_MEDIA_PICKER_MODAL = new UmbModalToken, UmbMediaPickerModalValue>( +export const UMB_MEDIA_PICKER_MODAL = new UmbModalToken( 'Umb.Modal.MediaPicker', { modal: { From e19645be7e40fe86e2b2b3ee012cb6983f0b4c53 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 20 Jan 2025 18:41:48 +0100 Subject: [PATCH 23/38] align models --- .../input-media/input-media.context.ts | 48 ++++++++++++++++++- .../input-media/input-media.element.ts | 30 ++++++------ .../input-rich-media.element.ts | 7 +-- .../image-cropper-editor-modal.element.ts | 9 +++- .../media-picker-modal.element.ts | 11 ++--- ...property-editor-ui-media-picker.element.ts | 8 +++- .../media-picker.tiptap-toolbar-api.ts | 5 ++ 7 files changed, 89 insertions(+), 29 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.context.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.context.ts index 44378fcebe50..21e13de8a26f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.context.ts @@ -2,16 +2,60 @@ import { UMB_MEDIA_ITEM_REPOSITORY_ALIAS } from '../../constants.js'; import { UMB_MEDIA_PICKER_MODAL } from '../../modals/index.js'; import type { UmbMediaItemModel } from '../../repository/item/types.js'; import type { UmbMediaPickerModalData, UmbMediaPickerModalValue } from '../../modals/index.js'; +import { UMB_MEDIA_SEARCH_PROVIDER_ALIAS } from '../../search/constants.js'; +import type { UmbMediaTreeItemModel } from '../../tree/types.js'; import { UmbPickerInputContext } from '@umbraco-cms/backoffice/picker-input'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import type { UmbMediaTypeEntityType } from '@umbraco-cms/backoffice/media-type'; + +interface UmbInputMediaOpenPickerArgs { + allowedContentTypes?: Array<{ unique: string; entityType: UmbMediaTypeEntityType }>; +} export class UmbMediaPickerInputContext extends UmbPickerInputContext< UmbMediaItemModel, - UmbMediaItemModel, - UmbMediaPickerModalData, + UmbMediaTreeItemModel, + UmbMediaPickerModalData, UmbMediaPickerModalValue > { constructor(host: UmbControllerHost) { super(host, UMB_MEDIA_ITEM_REPOSITORY_ALIAS, UMB_MEDIA_PICKER_MODAL); } + + override async openPicker(pickerData?: Partial, args?: UmbInputMediaOpenPickerArgs) { + const combinedPickerData = { + ...pickerData, + }; + + // transform allowedContentTypes to a pickable filter + combinedPickerData.pickableFilter = (item) => this.#pickableFilter(item, args?.allowedContentTypes); + + // set default search data + if (!pickerData?.search) { + combinedPickerData.search = { + providerAlias: UMB_MEDIA_SEARCH_PROVIDER_ALIAS, + ...pickerData?.search, + }; + } + + // pass allowedContentTypes to the search request args + combinedPickerData.search!.requestArgs = { + allowedContentTypes: args?.allowedContentTypes, + ...pickerData?.search?.requestArgs, + }; + + super.openPicker(combinedPickerData); + } + + #pickableFilter = ( + item: UmbMediaItemModel, + allowedContentTypes?: Array<{ unique: string; entityType: UmbMediaTypeEntityType }>, + ): boolean => { + if (allowedContentTypes && allowedContentTypes.length > 0) { + return allowedContentTypes + .map((contentTypeReference) => contentTypeReference.unique) + .includes(item.mediaType.unique); + } + return true; + }; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.element.ts index dc3b81e63c57..3f3a8c21d1c1 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.element.ts @@ -1,4 +1,4 @@ -import type { UmbMediaCardItemModel, UmbMediaItemModel } from '../../types.js'; +import type { UmbMediaCardItemModel } from '../../types.js'; import { UmbMediaPickerInputContext } from './input-media.context.js'; import { css, @@ -19,6 +19,7 @@ import { UMB_WORKSPACE_MODAL } from '@umbraco-cms/backoffice/workspace'; import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; import '@umbraco-cms/backoffice/imaging'; +import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; const elementName = 'umb-input-media'; @customElement(elementName) @@ -111,8 +112,8 @@ export class UmbInputMediaElement extends UmbFormControlMixin { - if (this.allowedContentTypeIds && this.allowedContentTypeIds.length > 0) { - return this.allowedContentTypeIds.includes(item.mediaType.unique); - } - return true; - }; - #openPicker() { - this.#pickerContext.openPicker({ - multiple: this.max > 1, - startNode: this.startNode, - pickableFilter: this.#pickableFilter, - }); + this.#pickerContext.openPicker( + { + multiple: this.max > 1, + startNode: this.startNode, + }, + { + allowedContentTypes: this.allowedContentTypeIds?.map((id) => ({ + unique: id, + })), + }, + ); } async #onRemove(item: UmbMediaCardItemModel) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-rich-media/input-rich-media.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-rich-media/input-rich-media.element.ts index cd9abf6633ac..9b7f19676074 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-rich-media/input-rich-media.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-rich-media/input-rich-media.element.ts @@ -15,6 +15,7 @@ import type { UmbModalRouteBuilder } from '@umbraco-cms/backoffice/router'; import type { UmbVariantId } from '@umbraco-cms/backoffice/variant'; import '@umbraco-cms/backoffice/imaging'; +import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; type UmbRichMediaCardModel = { unique: string; @@ -106,8 +107,8 @@ export class UmbInputRichMediaElement extends UUIFormControlMixin(UmbLitElement, @property({ type: Array }) allowedContentTypeIds?: string[] | undefined; - @property({ type: String }) - startNode = ''; + @property({ type: Object, attribute: false }) + startNode?: UmbTreeStartNode; @property({ type: Boolean }) multiple = false; @@ -307,7 +308,7 @@ export class UmbInputRichMediaElement extends UUIFormControlMixin(UmbLitElement, const data = await modalHandler?.onSubmit().catch(() => null); if (!data) return; - const selection = data.selection; + const selection = data.selection.filter((x) => x !== null) as string[]; this.#addItems(selection); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/image-cropper-editor/image-cropper-editor-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/image-cropper-editor/image-cropper-editor-modal.element.ts index 33a7bbfa082d..12016f52f422 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/image-cropper-editor/image-cropper-editor-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/image-cropper-editor/image-cropper-editor-modal.element.ts @@ -108,7 +108,14 @@ export class UmbImageCropperEditorModalElement extends UmbModalBaseElement< const data = await modal?.onSubmit().catch(() => null); if (!data) return; - this._unique = data.selection[0]; + const selected = data.selection[0]; + + if (!selected) { + throw new Error('No media selected'); + } + + this._unique = selected; + this.value = { ...this.value, unique: this._unique }; this.#getSrc(); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts index 6508d21c7a2f..6f667b181e22 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts @@ -31,10 +31,7 @@ const root: UmbMediaPathModel = { name: 'Media', unique: null, entityType: UMB_M // TODO: investigate how we can reuse the picker-search-field element, picker context etc. @customElement('umb-media-picker-modal') -export class UmbMediaPickerModalElement extends UmbModalBaseElement< - UmbMediaPickerModalData, - UmbMediaPickerModalValue -> { +export class UmbMediaPickerModalElement extends UmbModalBaseElement { #mediaTreeRepository = new UmbMediaTreeRepository(this); #mediaItemRepository = new UmbMediaItemRepository(this); #mediaSearchProvider = new UmbMediaSearchProvider(this); @@ -91,8 +88,10 @@ export class UmbMediaPickerModalElement extends UmbModalBaseElement< protected override async firstUpdated(_changedProperties: PropertyValues): Promise { super.firstUpdated(_changedProperties); - if (this.data?.startNode) { - const { data } = await this.#mediaItemRepository.requestItems([this.data.startNode]); + const startNode = this.data?.startNode; + + if (startNode) { + const { data } = await this.#mediaItemRepository.requestItems([startNode.unique]); this._startNode = data?.[0]; if (this._startNode) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/property-editor-ui-media-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/property-editor-ui-media-picker.element.ts index 281d3a47b804..8a1636ba7fea 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/property-editor-ui-media-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/property-editors/media-picker/property-editor-ui-media-picker.element.ts @@ -11,6 +11,8 @@ import type { } from '@umbraco-cms/backoffice/property-editor'; import '../../components/input-rich-media/input-rich-media.element.js'; +import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; +import { UMB_MEDIA_ENTITY_TYPE } from '../../entity.js'; const elementName = 'umb-property-editor-ui-media-picker'; @@ -29,7 +31,9 @@ export class UmbPropertyEditorUIMediaPickerElement extends UmbLitElement impleme this._focalPointEnabled = Boolean(config.getValueByAlias('enableLocalFocalPoint')); this._multiple = Boolean(config.getValueByAlias('multiple')); this._preselectedCrops = config?.getValueByAlias>('crops') ?? []; - this._startNode = config.getValueByAlias('startNodeId') ?? ''; + + const startNodeId = config.getValueByAlias('startNodeId') ?? ''; + this._startNode = startNodeId ? { unique: startNodeId, entityType: UMB_MEDIA_ENTITY_TYPE } : undefined; const minMax = config.getValueByAlias('validationLimit'); this._min = minMax?.min ?? 0; @@ -46,7 +50,7 @@ export class UmbPropertyEditorUIMediaPickerElement extends UmbLitElement impleme readonly = false; @state() - private _startNode: string = ''; + private _startNode?: UmbTreeStartNode; @state() private _focalPointEnabled: boolean = false; diff --git a/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/toolbar/media-picker.tiptap-toolbar-api.ts b/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/toolbar/media-picker.tiptap-toolbar-api.ts index e77af1787d44..ddbd215c82b6 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/toolbar/media-picker.tiptap-toolbar-api.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/tiptap/extensions/toolbar/media-picker.tiptap-toolbar-api.ts @@ -53,6 +53,11 @@ export default class UmbTiptapToolbarMediaPickerToolbarExtensionApi extends UmbT if (!selection?.length) return; const mediaGuid = selection[0]; + + if (!mediaGuid) { + throw new Error('No media selected'); + } + const media = await this.#showMediaCaptionAltText(mediaGuid, currentAltText, currentCaption); if (!media) return; From 8bb5681531edd8af09d15111aebab7ac3fb00d42 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 21 Jan 2025 12:31:17 +0100 Subject: [PATCH 24/38] add entity type --- .../media/media/components/input-media/input-media.element.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.element.ts index 3f3a8c21d1c1..919c456f1759 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.element.ts @@ -17,9 +17,10 @@ import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/rou import { UmbSorterController, UmbSorterResolvePlacementAsGrid } from '@umbraco-cms/backoffice/sorter'; import { UMB_WORKSPACE_MODAL } from '@umbraco-cms/backoffice/workspace'; import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation'; +import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; +import { UMB_MEDIA_TYPE_ENTITY_TYPE } from '@umbraco-cms/backoffice/media-type'; import '@umbraco-cms/backoffice/imaging'; -import type { UmbTreeStartNode } from '@umbraco-cms/backoffice/tree'; const elementName = 'umb-input-media'; @customElement(elementName) @@ -194,6 +195,7 @@ export class UmbInputMediaElement extends UmbFormControlMixin ({ unique: id, + entityType: UMB_MEDIA_TYPE_ENTITY_TYPE, })), }, ); From 31088c7a813e3e1ba39e7a086c00f1ee39a47170 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 21 Jan 2025 12:31:25 +0100 Subject: [PATCH 25/38] filter for null value --- .../components/input-markdown-editor/input-markdown.element.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/markdown-editor/components/input-markdown-editor/input-markdown.element.ts b/src/Umbraco.Web.UI.Client/src/packages/markdown-editor/components/input-markdown-editor/input-markdown.element.ts index 39e3004534f6..b85eb539fcb7 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/markdown-editor/components/input-markdown-editor/input-markdown.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/markdown-editor/components/input-markdown-editor/input-markdown.element.ts @@ -225,7 +225,7 @@ export class UmbInputMarkdownElement extends UmbFormControlMixin(UmbLitElement, .then(async (value) => { if (!value) return; - const uniques = value.selection; + const uniques = value.selection.filter((unique) => unique !== null) as Array; const { data: mediaUrls } = await this.#mediaUrlRepository.requestItems(uniques); const mediaUrl = mediaUrls?.length ? (mediaUrls[0].url ?? 'URL') : 'URL'; From 758a35623717a49a6dea64816470d93715725425 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 21 Jan 2025 12:35:19 +0100 Subject: [PATCH 26/38] explicit naming --- .../components/input-document/input-document.context.ts | 7 +++++-- .../media/components/input-media/input-media.context.ts | 4 ++-- .../member/components/input-member/input-member.context.ts | 7 +++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.context.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.context.ts index e08be7dc4c88..b3be5947f994 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.context.ts @@ -10,7 +10,7 @@ import { UmbPickerInputContext } from '@umbraco-cms/backoffice/picker-input'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import type { UmbDocumentTypeEntityType } from '@umbraco-cms/backoffice/document-type'; -interface UmbInputDocumentOpenPickerArgs { +interface UmbDocumentPickerInputContextOpenArgs { allowedContentTypes?: Array<{ unique: string; entityType: UmbDocumentTypeEntityType }>; } @@ -24,7 +24,10 @@ export class UmbDocumentPickerInputContext extends UmbPickerInputContext< super(host, UMB_DOCUMENT_ITEM_REPOSITORY_ALIAS, UMB_DOCUMENT_PICKER_MODAL, (entry) => entry.unique); } - override async openPicker(pickerData?: Partial, args?: UmbInputDocumentOpenPickerArgs) { + override async openPicker( + pickerData?: Partial, + args?: UmbDocumentPickerInputContextOpenArgs, + ) { const combinedPickerData = { ...pickerData, }; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.context.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.context.ts index 21e13de8a26f..cec366fae267 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.context.ts @@ -8,7 +8,7 @@ import { UmbPickerInputContext } from '@umbraco-cms/backoffice/picker-input'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import type { UmbMediaTypeEntityType } from '@umbraco-cms/backoffice/media-type'; -interface UmbInputMediaOpenPickerArgs { +interface UmbMediaPickerInputContextOpenArgs { allowedContentTypes?: Array<{ unique: string; entityType: UmbMediaTypeEntityType }>; } @@ -22,7 +22,7 @@ export class UmbMediaPickerInputContext extends UmbPickerInputContext< super(host, UMB_MEDIA_ITEM_REPOSITORY_ALIAS, UMB_MEDIA_PICKER_MODAL); } - override async openPicker(pickerData?: Partial, args?: UmbInputMediaOpenPickerArgs) { + override async openPicker(pickerData?: Partial, args?: UmbMediaPickerInputContextOpenArgs) { const combinedPickerData = { ...pickerData, }; diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/components/input-member/input-member.context.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/components/input-member/input-member.context.ts index a334d8b0904b..162cf4ee4a4f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member/components/input-member/input-member.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/components/input-member/input-member.context.ts @@ -9,7 +9,7 @@ import { UmbPickerInputContext } from '@umbraco-cms/backoffice/picker-input'; import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; import type { UmbMemberTypeEntityType } from '@umbraco-cms/backoffice/member-type'; -interface UmbInputMemberOpenPickerArgs { +interface UmbMemberPickerInputContextOpenArgs { allowedContentTypes?: Array<{ unique: string; entityType: UmbMemberTypeEntityType }>; } @@ -23,7 +23,10 @@ export class UmbMemberPickerInputContext extends UmbPickerInputContext< super(host, UMB_MEMBER_ITEM_REPOSITORY_ALIAS, UMB_MEMBER_PICKER_MODAL); } - override async openPicker(pickerData?: Partial, args?: UmbInputMemberOpenPickerArgs) { + override async openPicker( + pickerData?: Partial, + args?: UmbMemberPickerInputContextOpenArgs, + ) { const combinedPickerData = { ...pickerData, }; From 0ecfa22224b918e5e555050bf88e3bd190f48800 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 21 Jan 2025 12:37:34 +0100 Subject: [PATCH 27/38] rename field --- .../documents/search/document-search.server.data-source.ts | 2 +- .../src/packages/documents/documents/search/types.ts | 2 +- .../media/media/search/media-search.server.data-source.ts | 2 +- .../src/packages/media/media/search/types.ts | 2 +- .../members/member/search/member-search.server.data-source.ts | 2 +- .../src/packages/members/member/search/types.ts | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search.server.data-source.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search.server.data-source.ts index bfb561c99fb5..dc024b6ba37b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search.server.data-source.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search.server.data-source.ts @@ -36,7 +36,7 @@ export class UmbDocumentSearchServerDataSource DocumentService.getItemDocumentSearch({ query: args.query, parentId: args.searchFrom?.unique ?? undefined, - allowedDocumentTypes: args.allowedContentTypes?.map((contentType) => contentType.unique), + allowedDocumentTypes: args.contentTypes?.map((contentType) => contentType.unique), }), ); diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/types.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/types.ts index a63f89853bd7..d582e483683a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/types.ts @@ -7,5 +7,5 @@ export interface UmbDocumentSearchItemModel extends UmbDocumentItemModel { } export interface UmbDocumentSearchRequestArgs extends UmbSearchRequestArgs { - allowedContentTypes?: Array<{ unique: string; entityType: UmbDocumentTypeEntityType }>; + contentTypes?: Array<{ unique: string; entityType: UmbDocumentTypeEntityType }>; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/search/media-search.server.data-source.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/search/media-search.server.data-source.ts index 52881ba45576..b3623e68cd99 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/search/media-search.server.data-source.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/search/media-search.server.data-source.ts @@ -37,7 +37,7 @@ export class UmbMediaSearchServerDataSource MediaService.getItemMediaSearch({ query: args.query, parentId: args.searchFrom?.unique || undefined, - allowedMediaTypes: args.allowedContentTypes?.map((mediaReference) => mediaReference.unique), + allowedMediaTypes: args.contentTypes?.map((mediaReference) => mediaReference.unique), }), ); diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/search/types.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/search/types.ts index 246505347e95..8076450818d0 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/search/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/search/types.ts @@ -7,5 +7,5 @@ export interface UmbMediaSearchItemModel extends UmbMediaItemModel { } export interface UmbMediaSearchRequestArgs extends UmbSearchRequestArgs { - allowedContentTypes?: Array<{ unique: string; entityType: UmbMediaTypeEntityType }>; + contentTypes?: Array<{ unique: string; entityType: UmbMediaTypeEntityType }>; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/search/member-search.server.data-source.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/search/member-search.server.data-source.ts index 6a95cef4311f..f70e8ea87e49 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member/search/member-search.server.data-source.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/search/member-search.server.data-source.ts @@ -35,7 +35,7 @@ export class UmbMemberSearchServerDataSource this.#host, MemberService.getItemMemberSearch({ query: args.query, - allowedMemberTypes: args.allowedContentTypes?.map((memberReference) => memberReference.unique), + allowedMemberTypes: args.contentTypes?.map((memberReference) => memberReference.unique), }), ); diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/search/types.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/search/types.ts index 6ee8fceef593..10d43d5b6c43 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member/search/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/search/types.ts @@ -7,5 +7,5 @@ export interface UmbMemberSearchItemModel extends UmbMemberItemModel { } export interface UmbMemberSearchRequestArgs extends UmbSearchRequestArgs { - allowedContentTypes?: Array<{ unique: string; entityType: UmbMemberTypeEntityType }>; + contentTypes?: Array<{ unique: string; entityType: UmbMemberTypeEntityType }>; } From d236f1510c5a94eb06f9ac979385f22b3dac11dc Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 21 Jan 2025 13:01:01 +0100 Subject: [PATCH 28/38] use query params --- .../src/packages/core/modal/types.ts | 2 +- .../picker/search/manager/picker-search.manager.ts | 2 -- .../src/packages/core/picker/search/manager/types.ts | 4 +--- .../tree-picker-modal/tree-picker-modal.element.ts | 12 +++++++++--- .../input-document/input-document.context.ts | 6 +++--- .../components/input-media/input-media.context.ts | 6 +++--- .../components/input-member/input-member.context.ts | 6 +++--- 7 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts index 152977158da2..061086786c82 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/types.ts @@ -12,7 +12,7 @@ export interface UmbPickerModalData { export interface UmbPickerModalSearchConfig { providerAlias: string; - requestArgs?: object; + queryParams?: object; } export interface UmbPickerModalValue { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts index 4893d7fe70dd..bf9fffbb220f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/picker-search.manager.ts @@ -126,7 +126,6 @@ export class UmbPickerSearchManager< * @memberof UmbPickerSearchManager */ public setQuery(query: SearchRequestArgsType) { - if (this.getSearchable() === false) throw new Error('Search is not enabled'); if (!this.query) { this.clear(); return; @@ -186,7 +185,6 @@ export class UmbPickerSearchManager< const args = { searchFrom: this.#config?.searchFrom, - ...this.#config?.requestArgs, ...query, }; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/types.ts index 3b5cea857836..a8ef1e5a670d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/picker/search/manager/types.ts @@ -1,8 +1,6 @@ import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity'; -export interface UmbPickerSearchManagerConfig { +export interface UmbPickerSearchManagerConfig { providerAlias: string; - // TODO: searchFrom should have been part of the requestArgs object to make the type more flexible searchFrom?: UmbEntityModel; - requestArgs?: SearchRequestArgsType; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts index 7df964bb6fa4..e93efc11cd5a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts @@ -56,10 +56,16 @@ export class UmbTreePickerModalElement Date: Wed, 22 Jan 2025 12:04:00 +0100 Subject: [PATCH 29/38] Implement content type scoped search in item search controllers --- .../Item/SearchDocumentItemController.cs | 12 +++++-- .../Media/Item/SearchMediaItemController.cs | 10 ++++-- .../Member/Item/SearchMemberItemController.cs | 9 +++-- src/Umbraco.Cms.Api.Management/OpenApi.json | 33 +++++++++++++++++++ .../Services/IIndexedEntitySearchService.cs | 6 ++++ .../BackOfficeExamineSearcher.cs | 17 ++++++++++ .../Examine/IBackOfficeExamineSearcher.cs | 13 ++++++++ .../Implement/IndexedEntitySearchService.cs | 28 ++++++++++++++++ 8 files changed, 121 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Document/Item/SearchDocumentItemController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Document/Item/SearchDocumentItemController.cs index f3b7cb1caf9c..8b1c355d22c7 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Document/Item/SearchDocumentItemController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Document/Item/SearchDocumentItemController.cs @@ -1,4 +1,5 @@ -using Asp.Versioning; +using System.Text.Json.Serialization; +using Asp.Versioning; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Umbraco.Cms.Api.Management.Factories; @@ -26,12 +27,17 @@ public SearchDocumentItemController(IIndexedEntitySearchService indexedEntitySea public async Task Search(CancellationToken cancellationToken, string query, int skip = 0, int take = 100) => await SearchFromParent(cancellationToken, query, skip, take); + [NonAction] + [Obsolete("Scheduled to be removed in v16, use the non obsoleted method instead")] + public async Task SearchFromParent(CancellationToken cancellationToken, string query, int skip = 0, int take = 100, Guid? parentId = null) + => await SearchFromParentWithAllowedTypes(cancellationToken, query, skip, take, parentId); + [HttpGet("search")] [MapToApiVersion("1.0")] [ProducesResponseType(typeof(PagedModel), StatusCodes.Status200OK)] - public async Task SearchFromParent(CancellationToken cancellationToken, string query, int skip = 0, int take = 100, Guid? parentId = null) + public async Task SearchFromParentWithAllowedTypes(CancellationToken cancellationToken, string query, int skip = 0, int take = 100, Guid? parentId = null, [FromQuery]IEnumerable? allowedMediaTypes = null) { - PagedModel searchResult = _indexedEntitySearchService.Search(UmbracoObjectTypes.Document, query, parentId, skip, take); + PagedModel searchResult = _indexedEntitySearchService.Search(UmbracoObjectTypes.Document, query, parentId, allowedMediaTypes, skip, take); var result = new PagedModel { Items = searchResult.Items.OfType().Select(_documentPresentationFactory.CreateItemResponseModel), diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Media/Item/SearchMediaItemController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Media/Item/SearchMediaItemController.cs index 81d4f177481f..c7cccd0cea62 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Media/Item/SearchMediaItemController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Media/Item/SearchMediaItemController.cs @@ -26,12 +26,18 @@ public SearchMediaItemController(IIndexedEntitySearchService indexedEntitySearch public async Task Search(CancellationToken cancellationToken, string query, int skip = 0, int take = 100) => await SearchFromParent(cancellationToken, query, skip, take, null); + [NonAction] + [Obsolete("Scheduled to be removed in v16, use the non obsoleted method instead")] + [ProducesResponseType(typeof(PagedModel), StatusCodes.Status200OK)] + public async Task SearchFromParent(CancellationToken cancellationToken, string query, int skip = 0, int take = 100, Guid? parentId = null) + => await SearchFromParentWithAllowedTypes(cancellationToken, query, skip, take, parentId); + [HttpGet("search")] [MapToApiVersion("1.0")] [ProducesResponseType(typeof(PagedModel), StatusCodes.Status200OK)] - public async Task SearchFromParent(CancellationToken cancellationToken, string query, int skip = 0, int take = 100, Guid? parentId = null) + public async Task SearchFromParentWithAllowedTypes(CancellationToken cancellationToken, string query, int skip = 0, int take = 100, Guid? parentId = null, [FromQuery]IEnumerable? allowedMediaTypes = null) { - PagedModel searchResult = _indexedEntitySearchService.Search(UmbracoObjectTypes.Media, query, parentId, skip, take); + PagedModel searchResult = _indexedEntitySearchService.Search(UmbracoObjectTypes.Media, query, parentId, allowedMediaTypes, skip, take); var result = new PagedModel { Items = searchResult.Items.OfType().Select(_mediaPresentationFactory.CreateItemResponseModel), diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Member/Item/SearchMemberItemController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Member/Item/SearchMemberItemController.cs index 21b5b7fad507..187dc239b399 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Member/Item/SearchMemberItemController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Member/Item/SearchMemberItemController.cs @@ -21,12 +21,17 @@ public SearchMemberItemController(IIndexedEntitySearchService indexedEntitySearc _memberPresentationFactory = memberPresentationFactory; } + [NonAction] + [Obsolete("Scheduled to be removed in v16, use the non obsoleted method instead")] + public async Task Search(CancellationToken cancellationToken, string query, int skip = 0, int take = 100) + => await SearchWithAllowedTypes(cancellationToken, query, skip, take); + [HttpGet("search")] [MapToApiVersion("1.0")] [ProducesResponseType(typeof(PagedModel), StatusCodes.Status200OK)] - public async Task Search(CancellationToken cancellationToken, string query, int skip = 0, int take = 100) + public async Task SearchWithAllowedTypes(CancellationToken cancellationToken, string query, int skip = 0, int take = 100, [FromQuery]IEnumerable? allowedMemberTypes = null) { - PagedModel searchResult = _indexedEntitySearchService.Search(UmbracoObjectTypes.Member, query, skip, take); + PagedModel searchResult = _indexedEntitySearchService.Search(UmbracoObjectTypes.Member, query, null, allowedMemberTypes, skip, take); var result = new PagedModel { Items = searchResult.Items.OfType().Select(_memberPresentationFactory.CreateItemResponseModel), diff --git a/src/Umbraco.Cms.Api.Management/OpenApi.json b/src/Umbraco.Cms.Api.Management/OpenApi.json index 233486549181..c46477f29300 100644 --- a/src/Umbraco.Cms.Api.Management/OpenApi.json +++ b/src/Umbraco.Cms.Api.Management/OpenApi.json @@ -10086,6 +10086,17 @@ "type": "string", "format": "uuid" } + }, + { + "name": "allowedMediaTypes", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } } ], "responses": { @@ -15764,6 +15775,17 @@ "type": "string", "format": "uuid" } + }, + { + "name": "allowedMediaTypes", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } } ], "responses": { @@ -19638,6 +19660,17 @@ "format": "int32", "default": 100 } + }, + { + "name": "allowedMemberTypes", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } } ], "responses": { diff --git a/src/Umbraco.Core/Services/IIndexedEntitySearchService.cs b/src/Umbraco.Core/Services/IIndexedEntitySearchService.cs index 446373314656..12d4c3e72cfd 100644 --- a/src/Umbraco.Core/Services/IIndexedEntitySearchService.cs +++ b/src/Umbraco.Core/Services/IIndexedEntitySearchService.cs @@ -12,9 +12,15 @@ namespace Umbraco.Cms.Core.Services; /// public interface IIndexedEntitySearchService { + [Obsolete("Please use the method that accepts all parameters. Will be removed in V17.")] PagedModel Search(UmbracoObjectTypes objectType, string query, int skip = 0, int take = 100, bool ignoreUserStartNodes = false); // default implementation to avoid breaking changes falls back to old behaviour + [Obsolete("Please use the method that accepts all parameters. Will be removed in V17.")] PagedModel Search(UmbracoObjectTypes objectType, string query, Guid? parentId, int skip = 0, int take = 100, bool ignoreUserStartNodes = false) => Search(objectType,query, skip, take, ignoreUserStartNodes); + + // default implementation to avoid breaking changes falls back to old behaviour + PagedModel Search(UmbracoObjectTypes objectType, string query, Guid? parentId, IEnumerable? contentTypeIds, int skip = 0, int take = 100, bool ignoreUserStartNodes = false) + => Search(objectType,query, skip, take, ignoreUserStartNodes); } diff --git a/src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs b/src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs index 246df89e2a67..97bd8dd6ce29 100644 --- a/src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs +++ b/src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs @@ -52,6 +52,7 @@ public BackOfficeExamineSearcher( _publishedUrlProvider = publishedUrlProvider; } + [Obsolete("Please use the method that accepts all parameters. Will be removed in V17.")] public IEnumerable Search( string query, UmbracoEntityTypes entityType, @@ -60,6 +61,17 @@ public IEnumerable Search( out long totalFound, string? searchFrom = null, bool ignoreUserStartNodes = false) + => Search(query, entityType, pageSize, pageIndex, out totalFound, null, searchFrom, ignoreUserStartNodes); + + public IEnumerable Search( + string query, + UmbracoEntityTypes entityType, + int pageSize, + long pageIndex, + out long totalFound, + string[]? contentTypeAliases = null, + string? searchFrom = null, + bool ignoreUserStartNodes = false) { var sb = new StringBuilder(); @@ -141,6 +153,11 @@ public IEnumerable Search( entityType); } + if (contentTypeAliases?.Any() is true) + { + sb.Append($"+({string.Join(" ", contentTypeAliases.Select(alias => $"{ExamineFieldNames.ItemTypeFieldName}:{alias}"))}) "); + } + if (!_examineManager.TryGetIndex(indexName, out IIndex? index)) { throw new InvalidOperationException("No index found by name " + indexName); diff --git a/src/Umbraco.Infrastructure/Examine/IBackOfficeExamineSearcher.cs b/src/Umbraco.Infrastructure/Examine/IBackOfficeExamineSearcher.cs index eb6ce0f01c54..7bfde3ac4015 100644 --- a/src/Umbraco.Infrastructure/Examine/IBackOfficeExamineSearcher.cs +++ b/src/Umbraco.Infrastructure/Examine/IBackOfficeExamineSearcher.cs @@ -8,6 +8,7 @@ namespace Umbraco.Cms.Infrastructure.Examine; /// public interface IBackOfficeExamineSearcher { + [Obsolete("Please use the method that accepts all parameters. Will be removed in V17.")] IEnumerable Search( string query, UmbracoEntityTypes entityType, @@ -16,4 +17,16 @@ IEnumerable Search( out long totalFound, string? searchFrom = null, bool ignoreUserStartNodes = false); + + // default implementation to avoid breaking changes falls back to old behaviour + IEnumerable Search( + string query, + UmbracoEntityTypes entityType, + int pageSize, + long pageIndex, + out long totalFound, + string[]? contentTypeAliases = null, + string? searchFrom = null, + bool ignoreUserStartNodes = false) + => Search(query, entityType, pageSize, pageIndex, out totalFound, null, searchFrom, ignoreUserStartNodes); } diff --git a/src/Umbraco.Infrastructure/Services/Implement/IndexedEntitySearchService.cs b/src/Umbraco.Infrastructure/Services/Implement/IndexedEntitySearchService.cs index 0f097df26214..3eb4e74c1cbc 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/IndexedEntitySearchService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/IndexedEntitySearchService.cs @@ -1,5 +1,7 @@ using Examine; +using Microsoft.Extensions.DependencyInjection; using Umbraco.Cms.Core; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.ContentEditing; using Umbraco.Cms.Core.Models.Entities; @@ -12,11 +14,21 @@ internal sealed class IndexedEntitySearchService : IIndexedEntitySearchService { private readonly IBackOfficeExamineSearcher _backOfficeExamineSearcher; private readonly IEntityService _entityService; + private readonly IContentTypeService _contentTypeService; public IndexedEntitySearchService(IBackOfficeExamineSearcher backOfficeExamineSearcher, IEntityService entityService) + : this(backOfficeExamineSearcher, entityService, StaticServiceProvider.Instance.GetRequiredService()) + { + } + + public IndexedEntitySearchService( + IBackOfficeExamineSearcher backOfficeExamineSearcher, + IEntityService entityService, + IContentTypeService contentTypeService) { _backOfficeExamineSearcher = backOfficeExamineSearcher; _entityService = entityService; + _contentTypeService = contentTypeService; } public PagedModel Search(UmbracoObjectTypes objectType, string query, int skip = 0, int take = 100, bool ignoreUserStartNodes = false) @@ -29,6 +41,16 @@ public PagedModel Search( int skip = 0, int take = 100, bool ignoreUserStartNodes = false) + => Search(objectType, query, parentId, null, skip, take, ignoreUserStartNodes); + + public PagedModel Search( + UmbracoObjectTypes objectType, + string query, + Guid? parentId, + IEnumerable? contentTypeIds, + int skip = 0, + int take = 100, + bool ignoreUserStartNodes = false) { UmbracoEntityTypes entityType = objectType switch { @@ -40,12 +62,18 @@ public PagedModel Search( PaginationHelper.ConvertSkipTakeToPaging(skip, take, out var pageNumber, out var pageSize); + Guid[]? contentTypeIdsAsArray = contentTypeIds as Guid[] ?? contentTypeIds?.ToArray(); + var contentTypeAliases = contentTypeIdsAsArray?.Length > 0 + ? _contentTypeService.GetMany(contentTypeIdsAsArray).Select(x => x.Alias).ToArray() + : null; + IEnumerable searchResults = _backOfficeExamineSearcher.Search( query, entityType, pageSize, pageNumber, out var totalFound, + contentTypeAliases, ignoreUserStartNodes: ignoreUserStartNodes, searchFrom: parentId?.ToString()); From fd9e646f2f29fc5fefad623c71ea3419b2e809ea Mon Sep 17 00:00:00 2001 From: kjac Date: Thu, 23 Jan 2025 12:48:47 +0100 Subject: [PATCH 30/38] Fix bad naming --- .../Controllers/Document/Item/SearchDocumentItemController.cs | 4 ++-- src/Umbraco.Cms.Api.Management/OpenApi.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Document/Item/SearchDocumentItemController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Document/Item/SearchDocumentItemController.cs index 8b1c355d22c7..0ab15f0e7f66 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Document/Item/SearchDocumentItemController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Document/Item/SearchDocumentItemController.cs @@ -35,9 +35,9 @@ public async Task SearchFromParent(CancellationToken cancellation [HttpGet("search")] [MapToApiVersion("1.0")] [ProducesResponseType(typeof(PagedModel), StatusCodes.Status200OK)] - public async Task SearchFromParentWithAllowedTypes(CancellationToken cancellationToken, string query, int skip = 0, int take = 100, Guid? parentId = null, [FromQuery]IEnumerable? allowedMediaTypes = null) + public async Task SearchFromParentWithAllowedTypes(CancellationToken cancellationToken, string query, int skip = 0, int take = 100, Guid? parentId = null, [FromQuery]IEnumerable? allowedDocumentTypes = null) { - PagedModel searchResult = _indexedEntitySearchService.Search(UmbracoObjectTypes.Document, query, parentId, allowedMediaTypes, skip, take); + PagedModel searchResult = _indexedEntitySearchService.Search(UmbracoObjectTypes.Document, query, parentId, allowedDocumentTypes, skip, take); var result = new PagedModel { Items = searchResult.Items.OfType().Select(_documentPresentationFactory.CreateItemResponseModel), diff --git a/src/Umbraco.Cms.Api.Management/OpenApi.json b/src/Umbraco.Cms.Api.Management/OpenApi.json index c46477f29300..a76afe82a35d 100644 --- a/src/Umbraco.Cms.Api.Management/OpenApi.json +++ b/src/Umbraco.Cms.Api.Management/OpenApi.json @@ -10088,7 +10088,7 @@ } }, { - "name": "allowedMediaTypes", + "name": "allowedDocumentTypes", "in": "query", "schema": { "type": "array", From 78f97f88a2f6af33d9e6853a55ec03099429b9c6 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 23 Jan 2025 12:57:24 +0100 Subject: [PATCH 31/38] generate server models --- .../src/external/backend-api/src/sdk.gen.ts | 12 +++++++++--- .../src/external/backend-api/src/types.gen.ts | 3 +++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/sdk.gen.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/sdk.gen.ts index 851b36d512a3..0ac482a316d9 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/sdk.gen.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/sdk.gen.ts @@ -1494,6 +1494,7 @@ export class DocumentService { * @param data.skip * @param data.take * @param data.parentId + * @param data.allowedMediaTypes * @returns unknown OK * @throws ApiError */ @@ -1505,7 +1506,8 @@ export class DocumentService { query: data.query, skip: data.skip, take: data.take, - parentId: data.parentId + parentId: data.parentId, + allowedMediaTypes: data.allowedMediaTypes }, errors: { 401: 'The resource is protected and requires an authentication token' @@ -3497,6 +3499,7 @@ export class MediaService { * @param data.skip * @param data.take * @param data.parentId + * @param data.allowedMediaTypes * @returns unknown OK * @throws ApiError */ @@ -3508,7 +3511,8 @@ export class MediaService { query: data.query, skip: data.skip, take: data.take, - parentId: data.parentId + parentId: data.parentId, + allowedMediaTypes: data.allowedMediaTypes }, errors: { 401: 'The resource is protected and requires an authentication token' @@ -4703,6 +4707,7 @@ export class MemberService { * @param data.query * @param data.skip * @param data.take + * @param data.allowedMemberTypes * @returns unknown OK * @throws ApiError */ @@ -4713,7 +4718,8 @@ export class MemberService { query: { query: data.query, skip: data.skip, - take: data.take + take: data.take, + allowedMemberTypes: data.allowedMemberTypes }, errors: { 401: 'The resource is protected and requires an authentication token' diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/types.gen.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/types.gen.ts index 2f2dfa87e78d..495fa6f6d24e 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/types.gen.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/types.gen.ts @@ -3314,6 +3314,7 @@ export type GetItemDocumentData = { export type GetItemDocumentResponse = (Array<(DocumentItemResponseModel)>); export type GetItemDocumentSearchData = { + allowedMediaTypes?: Array<(string)>; parentId?: string; query?: string; skip?: number; @@ -3882,6 +3883,7 @@ export type GetItemMediaData = { export type GetItemMediaResponse = (Array<(MediaItemResponseModel)>); export type GetItemMediaSearchData = { + allowedMediaTypes?: Array<(string)>; parentId?: string; query?: string; skip?: number; @@ -4233,6 +4235,7 @@ export type GetItemMemberData = { export type GetItemMemberResponse = (Array<(MemberItemResponseModel)>); export type GetItemMemberSearchData = { + allowedMemberTypes?: Array<(string)>; query?: string; skip?: number; take?: number; From a0fb9592ba50bfa1e7f0fc3e51587eadbc4fd47f Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 23 Jan 2025 12:58:10 +0100 Subject: [PATCH 32/38] wire up backend --- .../tree-picker-modal/tree-picker-modal.element.ts | 2 +- .../input-document/input-document.context.ts | 2 +- .../search/document-search.server.data-source.ts | 2 +- .../packages/documents/documents/search/types.ts | 2 +- .../components/input-media/input-media.context.ts | 2 +- .../media-picker/media-picker-modal.element.ts | 6 +++++- .../search/media-search.server.data-source.ts | 3 +-- .../src/packages/media/media/search/types.ts | 2 +- .../input-member/input-member.context.ts | 2 +- .../member-picker-modal.element.ts | 14 +++++++++++++- .../search/member-search.server.data-source.ts | 2 +- .../src/packages/members/member/search/types.ts | 2 +- 12 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts index c6137509b442..a7b47cd0b69c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-picker-modal/tree-picker-modal.element.ts @@ -158,7 +158,7 @@ export class UmbTreePickerModalElement + ${this.#renderSearch()} ${this.#renderTree()} ${this.#renderActions()} diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.context.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.context.ts index 522ca88183fe..1fad7369cf28 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/components/input-document/input-document.context.ts @@ -45,7 +45,7 @@ export class UmbDocumentPickerInputContext extends UmbPickerInputContext< // pass allowedContentTypes to the search request args combinedPickerData.search!.queryParams = { - contentTypes: args?.allowedContentTypes, + allowedContentTypes: args?.allowedContentTypes, ...pickerData?.search?.queryParams, }; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search.server.data-source.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search.server.data-source.ts index dc024b6ba37b..4e3da56f8e3c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search.server.data-source.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search.server.data-source.ts @@ -36,7 +36,7 @@ export class UmbDocumentSearchServerDataSource DocumentService.getItemDocumentSearch({ query: args.query, parentId: args.searchFrom?.unique ?? undefined, - allowedDocumentTypes: args.contentTypes?.map((contentType) => contentType.unique), + allowedMediaTypes: args.allowedContentTypes?.map((contentType) => contentType.unique), }), ); diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/types.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/types.ts index d582e483683a..a63f89853bd7 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/types.ts @@ -7,5 +7,5 @@ export interface UmbDocumentSearchItemModel extends UmbDocumentItemModel { } export interface UmbDocumentSearchRequestArgs extends UmbSearchRequestArgs { - contentTypes?: Array<{ unique: string; entityType: UmbDocumentTypeEntityType }>; + allowedContentTypes?: Array<{ unique: string; entityType: UmbDocumentTypeEntityType }>; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.context.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.context.ts index 71f13d6069e6..80f62935f868 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-media/input-media.context.ts @@ -40,7 +40,7 @@ export class UmbMediaPickerInputContext extends UmbPickerInputContext< // pass allowedContentTypes to the search request args combinedPickerData.search!.queryParams = { - contentTypes: args?.allowedContentTypes, + allowedContentTypes: args?.allowedContentTypes, ...pickerData?.search?.queryParams, }; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts index 6f667b181e22..3a6477840bb2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts @@ -164,7 +164,11 @@ export class UmbMediaPickerModalElement extends UmbModalBaseElement mediaReference.unique), + allowedMediaTypes: args.allowedContentTypes?.map((mediaReference) => mediaReference.unique), }), ); diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/search/types.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/search/types.ts index 8076450818d0..246505347e95 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/search/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/search/types.ts @@ -7,5 +7,5 @@ export interface UmbMediaSearchItemModel extends UmbMediaItemModel { } export interface UmbMediaSearchRequestArgs extends UmbSearchRequestArgs { - contentTypes?: Array<{ unique: string; entityType: UmbMediaTypeEntityType }>; + allowedContentTypes?: Array<{ unique: string; entityType: UmbMediaTypeEntityType }>; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/components/input-member/input-member.context.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/components/input-member/input-member.context.ts index 2a791dc8dcba..b8c77827b967 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member/components/input-member/input-member.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/components/input-member/input-member.context.ts @@ -44,7 +44,7 @@ export class UmbMemberPickerInputContext extends UmbPickerInputContext< // pass allowedContentTypes to the search request args combinedPickerData.search!.queryParams = { - contentTypes: args?.allowedContentTypes, + allowedContentTypes: args?.allowedContentTypes, ...pickerData?.search?.queryParams, }; diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/components/member-picker-modal/member-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/components/member-picker-modal/member-picker-modal.element.ts index 1ed25c4d417d..189932894d56 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member/components/member-picker-modal/member-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/components/member-picker-modal/member-picker-modal.element.ts @@ -46,8 +46,20 @@ export class UmbMemberPickerModalElement extends UmbModalBaseElement< super.updated(_changedProperties); if (_changedProperties.has('data')) { - this.#pickerContext.search.updateConfig({ ...this.data?.search }); this.#pickerContext.selection.setMultiple(this.data?.multiple ?? false); + + if (this.data?.search) { + this.#pickerContext.search.updateConfig({ + ...this.data.search, + }); + + const searchQueryParams = this.data.search.queryParams; + if (searchQueryParams) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + //@ts-ignore - TODO wire up types + this.#pickerContext.search.setQuery(searchQueryParams); + } + } } if (_changedProperties.has('value')) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/search/member-search.server.data-source.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/search/member-search.server.data-source.ts index f70e8ea87e49..6a95cef4311f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member/search/member-search.server.data-source.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/search/member-search.server.data-source.ts @@ -35,7 +35,7 @@ export class UmbMemberSearchServerDataSource this.#host, MemberService.getItemMemberSearch({ query: args.query, - allowedMemberTypes: args.contentTypes?.map((memberReference) => memberReference.unique), + allowedMemberTypes: args.allowedContentTypes?.map((memberReference) => memberReference.unique), }), ); diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/search/types.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/search/types.ts index 10d43d5b6c43..6ee8fceef593 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member/search/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/search/types.ts @@ -7,5 +7,5 @@ export interface UmbMemberSearchItemModel extends UmbMemberItemModel { } export interface UmbMemberSearchRequestArgs extends UmbSearchRequestArgs { - contentTypes?: Array<{ unique: string; entityType: UmbMemberTypeEntityType }>; + allowedContentTypes?: Array<{ unique: string; entityType: UmbMemberTypeEntityType }>; } From 8ab7e205c3a358c6fb7790a789cdf4f188267603 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 23 Jan 2025 13:04:48 +0100 Subject: [PATCH 33/38] generate server models --- .../src/external/backend-api/src/sdk.gen.ts | 4 ++-- .../src/external/backend-api/src/types.gen.ts | 2 +- .../documents/search/document-search.server.data-source.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/sdk.gen.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/sdk.gen.ts index 0ac482a316d9..773300fc9dd1 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/sdk.gen.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/sdk.gen.ts @@ -1494,7 +1494,7 @@ export class DocumentService { * @param data.skip * @param data.take * @param data.parentId - * @param data.allowedMediaTypes + * @param data.allowedDocumentTypes * @returns unknown OK * @throws ApiError */ @@ -1507,7 +1507,7 @@ export class DocumentService { skip: data.skip, take: data.take, parentId: data.parentId, - allowedMediaTypes: data.allowedMediaTypes + allowedDocumentTypes: data.allowedDocumentTypes }, errors: { 401: 'The resource is protected and requires an authentication token' diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/types.gen.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/types.gen.ts index 495fa6f6d24e..aa36d5167a3f 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/types.gen.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/types.gen.ts @@ -3314,7 +3314,7 @@ export type GetItemDocumentData = { export type GetItemDocumentResponse = (Array<(DocumentItemResponseModel)>); export type GetItemDocumentSearchData = { - allowedMediaTypes?: Array<(string)>; + allowedDocumentTypes?: Array<(string)>; parentId?: string; query?: string; skip?: number; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search.server.data-source.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search.server.data-source.ts index 4e3da56f8e3c..bfb561c99fb5 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search.server.data-source.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/search/document-search.server.data-source.ts @@ -36,7 +36,7 @@ export class UmbDocumentSearchServerDataSource DocumentService.getItemDocumentSearch({ query: args.query, parentId: args.searchFrom?.unique ?? undefined, - allowedMediaTypes: args.allowedContentTypes?.map((contentType) => contentType.unique), + allowedDocumentTypes: args.allowedContentTypes?.map((contentType) => contentType.unique), }), ); From 73f70a151f0f052ac737601bc761f62cbe0bc719 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 23 Jan 2025 13:22:30 +0100 Subject: [PATCH 34/38] add selectable filter to member picker --- .../member-picker-modal.element.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/components/member-picker-modal/member-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/components/member-picker-modal/member-picker-modal.element.ts index 189932894d56..f0fbf149b798 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member/components/member-picker-modal/member-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/components/member-picker-modal/member-picker-modal.element.ts @@ -14,11 +14,14 @@ export class UmbMemberPickerModalElement extends UmbModalBaseElement< UmbMemberPickerModalValue > { @state() - private _members: Array = []; + private _members: Array = []; @state() private _searchQuery?: string; + @state() + private _selectableFilter: (item: UmbMemberItemModel) => boolean = () => true; + #collectionRepository = new UmbMemberCollectionRepository(this); #pickerContext = new UmbCollectionItemPickerContext(this); @@ -48,6 +51,10 @@ export class UmbMemberPickerModalElement extends UmbModalBaseElement< if (_changedProperties.has('data')) { this.#pickerContext.selection.setMultiple(this.data?.multiple ?? false); + if (this.data?.pickableFilter) { + this._selectableFilter = this.data?.pickableFilter; + } + if (this.data?.search) { this.#pickerContext.search.updateConfig({ ...this.data.search, @@ -108,10 +115,13 @@ export class UmbMemberPickerModalElement extends UmbModalBaseElement< } #renderMemberItem(item: UmbMemberItemModel | UmbMemberDetailModel) { + const selectable = this._selectableFilter(item); + return html` this.#pickerContext.selection.select(item.unique)} @deselected=${() => this.#pickerContext.selection.deselect(item.unique)} ?selected=${this.#pickerContext.selection.isSelected(item.unique)}> From 76142ad657b650c7e53fff35e8e06a5051e41a0b Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 23 Jan 2025 13:38:51 +0100 Subject: [PATCH 35/38] Update member-picker-modal.element.ts --- .../member-picker-modal/member-picker-modal.element.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/components/member-picker-modal/member-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/components/member-picker-modal/member-picker-modal.element.ts index f0fbf149b798..89571c3eaf1c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member/components/member-picker-modal/member-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/components/member-picker-modal/member-picker-modal.element.ts @@ -115,6 +115,8 @@ export class UmbMemberPickerModalElement extends UmbModalBaseElement< } #renderMemberItem(item: UmbMemberItemModel | UmbMemberDetailModel) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore - TODO: MemberDetailModel does not have a name. It should have so we ignore this for now. const selectable = this._selectableFilter(item); return html` From 3a721986e69c6660c6d48a3ea34b68be4adfde4f Mon Sep 17 00:00:00 2001 From: kjac Date: Fri, 24 Jan 2025 10:33:08 +0100 Subject: [PATCH 36/38] Fix indexed search for specific member and media types --- .../Implement/IndexedEntitySearchService.cs | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Infrastructure/Services/Implement/IndexedEntitySearchService.cs b/src/Umbraco.Infrastructure/Services/Implement/IndexedEntitySearchService.cs index 3eb4e74c1cbc..5ac85ad0fd4c 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/IndexedEntitySearchService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/IndexedEntitySearchService.cs @@ -15,20 +15,31 @@ internal sealed class IndexedEntitySearchService : IIndexedEntitySearchService private readonly IBackOfficeExamineSearcher _backOfficeExamineSearcher; private readonly IEntityService _entityService; private readonly IContentTypeService _contentTypeService; + private readonly IMediaTypeService _mediaTypeService; + private readonly IMemberTypeService _memberTypeService; public IndexedEntitySearchService(IBackOfficeExamineSearcher backOfficeExamineSearcher, IEntityService entityService) - : this(backOfficeExamineSearcher, entityService, StaticServiceProvider.Instance.GetRequiredService()) + : this( + backOfficeExamineSearcher, + entityService, + StaticServiceProvider.Instance.GetRequiredService(), + StaticServiceProvider.Instance.GetRequiredService(), + StaticServiceProvider.Instance.GetRequiredService()) { } public IndexedEntitySearchService( IBackOfficeExamineSearcher backOfficeExamineSearcher, IEntityService entityService, - IContentTypeService contentTypeService) + IContentTypeService contentTypeService, + IMediaTypeService mediaTypeService, + IMemberTypeService memberTypeService) { _backOfficeExamineSearcher = backOfficeExamineSearcher; _entityService = entityService; _contentTypeService = contentTypeService; + _mediaTypeService = mediaTypeService; + _memberTypeService = memberTypeService; } public PagedModel Search(UmbracoObjectTypes objectType, string query, int skip = 0, int take = 100, bool ignoreUserStartNodes = false) @@ -64,7 +75,13 @@ public PagedModel Search( Guid[]? contentTypeIdsAsArray = contentTypeIds as Guid[] ?? contentTypeIds?.ToArray(); var contentTypeAliases = contentTypeIdsAsArray?.Length > 0 - ? _contentTypeService.GetMany(contentTypeIdsAsArray).Select(x => x.Alias).ToArray() + ? (entityType switch + { + UmbracoEntityTypes.Document => _contentTypeService.GetMany(contentTypeIdsAsArray).Select(x => x.Alias), + UmbracoEntityTypes.Media => _mediaTypeService.GetMany(contentTypeIdsAsArray).Select(x => x.Alias), + UmbracoEntityTypes.Member => _memberTypeService.GetMany(contentTypeIdsAsArray).Select(x => x.Alias), + _ => throw new NotSupportedException("This service only supports searching for documents, media and members") + }).ToArray() : null; IEnumerable searchResults = _backOfficeExamineSearcher.Search( From 2bd9ae335098ce182f49bcfe57f7ea6463f577e2 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 27 Jan 2025 09:29:16 +0100 Subject: [PATCH 37/38] export consts --- src/Umbraco.Web.UI.Client/src/packages/media/media/constants.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/constants.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/constants.ts index ef2d8e44dfe8..e258a81e1833 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/constants.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/constants.ts @@ -7,6 +7,7 @@ export * from './modals/constants.js'; export * from './recycle-bin/constants.js'; export * from './reference/constants.js'; export * from './repository/constants.js'; +export * from './search/constants.js'; export * from './tree/constants.js'; export * from './workspace/constants.js'; From 3f9e5144d340f8f1c5efd89128914b8a405750a4 Mon Sep 17 00:00:00 2001 From: kjac Date: Wed, 29 Jan 2025 08:47:56 +0100 Subject: [PATCH 38/38] Fix ambiguous constructor --- src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs | 2 +- .../Examine/IBackOfficeExamineSearcher.cs | 2 +- .../UmbracoExamine/BackOfficeExamineSearcherTests.cs | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs b/src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs index 97bd8dd6ce29..937d8f530959 100644 --- a/src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs +++ b/src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs @@ -69,7 +69,7 @@ public IEnumerable Search( int pageSize, long pageIndex, out long totalFound, - string[]? contentTypeAliases = null, + string[]? contentTypeAliases, string? searchFrom = null, bool ignoreUserStartNodes = false) { diff --git a/src/Umbraco.Infrastructure/Examine/IBackOfficeExamineSearcher.cs b/src/Umbraco.Infrastructure/Examine/IBackOfficeExamineSearcher.cs index 7bfde3ac4015..555059e3855b 100644 --- a/src/Umbraco.Infrastructure/Examine/IBackOfficeExamineSearcher.cs +++ b/src/Umbraco.Infrastructure/Examine/IBackOfficeExamineSearcher.cs @@ -25,7 +25,7 @@ IEnumerable Search( int pageSize, long pageIndex, out long totalFound, - string[]? contentTypeAliases = null, + string[]? contentTypeAliases, string? searchFrom = null, bool ignoreUserStartNodes = false) => Search(query, entityType, pageSize, pageIndex, out totalFound, null, searchFrom, ignoreUserStartNodes); diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Examine.Lucene/UmbracoExamine/BackOfficeExamineSearcherTests.cs b/tests/Umbraco.Tests.Integration/Umbraco.Examine.Lucene/UmbracoExamine/BackOfficeExamineSearcherTests.cs index 3313d83cd389..7df133a3bada 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Examine.Lucene/UmbracoExamine/BackOfficeExamineSearcherTests.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Examine.Lucene/UmbracoExamine/BackOfficeExamineSearcherTests.cs @@ -78,6 +78,8 @@ private IEnumerable BackOfficeExamineSearch(string query, int pag pageSize, pageIndex, out _, + null, + null, ignoreUserStartNodes: true); private async Task SetupUserIdentity(string userId)