Skip to content

Commit 57bec51

Browse files
kjacnielslyngsoemadsrasmussen
authored
Add culture awareness to the backoffice search APIs (#19322)
* Added culture parameter to search APIs and propagated it to the indexed entity search service * Variant Culture aware search in Document and Media Pickers (#19336) * generate types * enable selection of entity-item-ref elements * Update input-document.element.ts * add culture to document search args * pass culture param to search end point * get variant context in document picker * add variant context * set culture in variant context when changing app language * set variant context when swithing variant in a workspace * Update content-detail-workspace-base.ts * clean up * remove from split view manager * Update property-dataset-base-context.ts * change name to fallbackCulture * simplify * get context instead of consuming * make all methods async * implement for media * Update current-user-action.extension.ts * allow null until we reach the server * remove log --------- Co-authored-by: Niels Lyngsø <[email protected]> * remove console.log * add display culture * opt-in inheritance * set observe alias to observeAppCulture * stop inheritance if specific cultures are set * remove unused import * include culture for document and media global search * await value for get methods * include orderCulture for document collections * Update document-collection.context.ts * Update document-collection.context.ts * fix self import --------- Co-authored-by: Niels Lyngsø <[email protected]> Co-authored-by: Mads Rasmussen <[email protected]>
1 parent afed7b0 commit 57bec51

File tree

37 files changed

+450
-63
lines changed

37 files changed

+450
-63
lines changed

src/Umbraco.Cms.Api.Management/Controllers/Document/Item/SearchDocumentItemController.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,13 @@ public async Task<IActionResult> SearchWithTrashed(
2828
CancellationToken cancellationToken,
2929
string query,
3030
bool? trashed = null,
31+
string? culture = null,
3132
int skip = 0,
3233
int take = 100,
3334
Guid? parentId = null,
3435
[FromQuery] IEnumerable<Guid>? allowedDocumentTypes = null)
3536
{
36-
PagedModel<IEntitySlim> searchResult = await _indexedEntitySearchService.SearchAsync(UmbracoObjectTypes.Document, query, parentId, allowedDocumentTypes, trashed, skip, take);
37+
PagedModel<IEntitySlim> searchResult = await _indexedEntitySearchService.SearchAsync(UmbracoObjectTypes.Document, query, parentId, allowedDocumentTypes, trashed, culture, skip, take);
3738
var result = new PagedModel<DocumentItemResponseModel>
3839
{
3940
Items = searchResult.Items.OfType<IDocumentEntitySlim>().Select(_documentPresentationFactory.CreateItemResponseModel),

src/Umbraco.Cms.Api.Management/Controllers/Media/Item/SearchMediaItemController.cs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,20 @@ public SearchMediaItemController(IIndexedEntitySearchService indexedEntitySearch
2121
_mediaPresentationFactory = mediaPresentationFactory;
2222
}
2323

24-
[NonAction]
25-
[Obsolete("Scheduled to be removed in v16, use the non obsoleted method instead")]
26-
public Task<IActionResult> SearchFromParentWithAllowedTypes(CancellationToken cancellationToken, string query, int skip = 0, int take = 100, Guid? parentId = null, [FromQuery]IEnumerable<Guid>? allowedMediaTypes = null)
27-
=> SearchFromParentWithAllowedTypes(cancellationToken, query, null, skip, take, parentId);
28-
2924
[HttpGet("search")]
3025
[MapToApiVersion("1.0")]
3126
[ProducesResponseType(typeof(PagedModel<MediaItemResponseModel>), StatusCodes.Status200OK)]
32-
public async Task<IActionResult> SearchFromParentWithAllowedTypes(CancellationToken cancellationToken, string query, bool? trashed = null, int skip = 0, int take = 100, Guid? parentId = null, [FromQuery]IEnumerable<Guid>? allowedMediaTypes = null)
27+
public async Task<IActionResult> SearchFromParentWithAllowedTypes(
28+
CancellationToken cancellationToken,
29+
string query,
30+
bool? trashed = null,
31+
string? culture = null,
32+
int skip = 0,
33+
int take = 100,
34+
Guid? parentId = null,
35+
[FromQuery]IEnumerable<Guid>? allowedMediaTypes = null)
3336
{
34-
PagedModel<IEntitySlim> searchResult = await _indexedEntitySearchService.SearchAsync(UmbracoObjectTypes.Media, query, parentId, allowedMediaTypes, trashed, skip, take);
37+
PagedModel<IEntitySlim> searchResult = await _indexedEntitySearchService.SearchAsync(UmbracoObjectTypes.Media, query, parentId, allowedMediaTypes, trashed, culture, skip, take);
3538
var result = new PagedModel<MediaItemResponseModel>
3639
{
3740
Items = searchResult.Items.OfType<IMediaEntitySlim>().Select(_mediaPresentationFactory.CreateItemResponseModel),

src/Umbraco.Cms.Api.Management/OpenApi.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10159,6 +10159,13 @@
1015910159
"type": "boolean"
1016010160
}
1016110161
},
10162+
{
10163+
"name": "culture",
10164+
"in": "query",
10165+
"schema": {
10166+
"type": "string"
10167+
}
10168+
},
1016210169
{
1016310170
"name": "skip",
1016410171
"in": "query",
@@ -15918,6 +15925,13 @@
1591815925
"type": "boolean"
1591915926
}
1592015927
},
15928+
{
15929+
"name": "culture",
15930+
"in": "query",
15931+
"schema": {
15932+
"type": "string"
15933+
}
15934+
},
1592115935
{
1592215936
"name": "skip",
1592315937
"in": "query",

src/Umbraco.Core/Services/IIndexedEntitySearchService.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,15 @@ PagedModel<IEntitySlim> Search(
3535
int skip = 0,
3636
int take = 100,
3737
bool ignoreUserStartNodes = false)
38-
=> Search(objectType,query, skip, take, ignoreUserStartNodes);
38+
=> Search(objectType, query, skip, take, ignoreUserStartNodes);
3939

4040
Task<PagedModel<IEntitySlim>> SearchAsync(
4141
UmbracoObjectTypes objectType,
4242
string query,
4343
Guid? parentId,
4444
IEnumerable<Guid>? contentTypeIds,
4545
bool? trashed,
46+
string? culture = null,
4647
int skip = 0,
4748
int take = 100,
4849
bool ignoreUserStartNodes = false);

src/Umbraco.Infrastructure/Services/Implement/IndexedEntitySearchService.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,15 @@ public PagedModel<IEntitySlim> Search(
7373
int skip = 0,
7474
int take = 100,
7575
bool ignoreUserStartNodes = false)
76-
=> SearchAsync(objectType, query, parentId, contentTypeIds, trashed, skip, take, ignoreUserStartNodes).GetAwaiter().GetResult();
76+
=> SearchAsync(objectType, query, parentId, contentTypeIds, trashed, null, skip, take, ignoreUserStartNodes).GetAwaiter().GetResult();
7777

7878
public Task<PagedModel<IEntitySlim>> SearchAsync(
7979
UmbracoObjectTypes objectType,
8080
string query,
8181
Guid? parentId,
8282
IEnumerable<Guid>? contentTypeIds,
8383
bool? trashed,
84+
string? culture = null,
8485
int skip = 0,
8586
int take = 100,
8687
bool ignoreUserStartNodes = false)

src/Umbraco.Web.UI.Client/src/packages/content/content/property-dataset-context/element-property-dataset.context.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export abstract class UmbElementPropertyDatasetContext<
4747
protected _readOnly = new UmbBooleanState(false);
4848
public readOnly = this._readOnly.asObservable();
4949

50-
#variantContext = new UmbVariantContext(this);
50+
#variantContext = new UmbVariantContext(this).inherit();
5151

5252
getEntityType(): string {
5353
return this._dataOwner.getEntityType();

src/Umbraco.Web.UI.Client/src/packages/core/backend-api/types.gen.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6700,6 +6700,7 @@ export type GetItemDocumentSearchData = {
67006700
query?: {
67016701
query?: string;
67026702
trashed?: boolean;
6703+
culture?: string;
67036704
skip?: number;
67046705
take?: number;
67056706
parentId?: string;
@@ -8991,6 +8992,7 @@ export type GetItemMediaSearchData = {
89918992
query?: {
89928993
query?: string;
89938994
trashed?: boolean;
8995+
culture?: string;
89948996
skip?: number;
89958997
take?: number;
89968998
parentId?: string;

src/Umbraco.Web.UI.Client/src/packages/core/collection/default/collection-default.context.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,10 @@ export class UmbDefaultCollectionContext<
283283
this.requestCollection();
284284
}
285285

286+
public updateFilter(filter: Partial<FilterModelType>) {
287+
this._filter.setValue({ ...this._filter.getValue(), ...filter });
288+
}
289+
286290
public getLastSelectedView(unique: string | undefined): string | undefined {
287291
if (!unique) return;
288292

src/Umbraco.Web.UI.Client/src/packages/core/entity-item/entity-item-ref/entity-item-ref.element.ts

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { UmbRoutePathAddendumContext } from '@umbraco-cms/backoffice/router';
88
import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity';
99

1010
import './default-item-ref.element.js';
11+
import { UmbDeselectedEvent, UmbSelectedEvent } from '@umbraco-cms/backoffice/event';
1112

1213
@customElement('umb-entity-item-ref')
1314
export class UmbEntityItemRefElement extends UmbLitElement {
@@ -41,7 +42,7 @@ export class UmbEntityItemRefElement extends UmbLitElement {
4142
}
4243

4344
#readonly = false;
44-
@property({ type: Boolean, attribute: 'readonly' })
45+
@property({ type: Boolean, reflect: true })
4546
public get readonly() {
4647
return this.#readonly;
4748
}
@@ -54,7 +55,7 @@ export class UmbEntityItemRefElement extends UmbLitElement {
5455
}
5556

5657
#standalone = false;
57-
@property({ type: Boolean, attribute: 'standalone' })
58+
@property({ type: Boolean, reflect: true })
5859
public get standalone() {
5960
return this.#standalone;
6061
}
@@ -66,8 +67,74 @@ export class UmbEntityItemRefElement extends UmbLitElement {
6667
}
6768
}
6869

70+
#selectOnly = false;
71+
@property({ type: Boolean, attribute: 'select-only', reflect: true })
72+
public get selectOnly() {
73+
return this.#selectOnly;
74+
}
75+
public set selectOnly(value) {
76+
this.#selectOnly = value;
77+
78+
if (this._component) {
79+
this._component.selectOnly = this.#selectOnly;
80+
}
81+
}
82+
83+
#selectable = false;
84+
@property({ type: Boolean, reflect: true })
85+
public get selectable() {
86+
return this.#selectable;
87+
}
88+
public set selectable(value) {
89+
this.#selectable = value;
90+
91+
if (this._component) {
92+
this._component.selectable = this.#selectable;
93+
}
94+
}
95+
96+
#selected = false;
97+
@property({ type: Boolean, reflect: true })
98+
public get selected() {
99+
return this.#selected;
100+
}
101+
public set selected(value) {
102+
this.#selected = value;
103+
104+
if (this._component) {
105+
this._component.selected = this.#selected;
106+
}
107+
}
108+
109+
#disabled = false;
110+
@property({ type: Boolean, reflect: true })
111+
public get disabled() {
112+
return this.#disabled;
113+
}
114+
public set disabled(value) {
115+
this.#disabled = value;
116+
117+
if (this._component) {
118+
this._component.disabled = this.#disabled;
119+
}
120+
}
121+
69122
#pathAddendum = new UmbRoutePathAddendumContext(this);
70123

124+
#onSelected(event: UmbSelectedEvent) {
125+
event.stopPropagation();
126+
const unique = this.#item?.unique;
127+
if (!unique) throw new Error('No unique id found for item');
128+
this.dispatchEvent(new UmbSelectedEvent(unique));
129+
}
130+
131+
#onDeselected(event: UmbDeselectedEvent) {
132+
event.stopPropagation();
133+
const unique = this.#item?.unique;
134+
if (!unique) throw new Error('No unique id found for item');
135+
this.dispatchEvent(new UmbDeselectedEvent(unique));
136+
}
137+
71138
protected override firstUpdated(_changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void {
72139
super.firstUpdated(_changedProperties);
73140
this.setAttribute(UMB_MARK_ATTRIBUTE_NAME, 'entity-item-ref');
@@ -91,6 +158,13 @@ export class UmbEntityItemRefElement extends UmbLitElement {
91158
component.item = this.#item;
92159
component.readonly = this.readonly;
93160
component.standalone = this.standalone;
161+
component.selectOnly = this.selectOnly;
162+
component.selectable = this.selectable;
163+
component.selected = this.selected;
164+
component.disabled = this.disabled;
165+
166+
component.addEventListener(UmbSelectedEvent.TYPE, this.#onSelected.bind(this));
167+
component.addEventListener(UmbDeselectedEvent.TYPE, this.#onDeselected.bind(this));
94168

95169
// Proxy the actions slot to the component
96170
const slotElement = document.createElement('slot');
@@ -110,6 +184,12 @@ export class UmbEntityItemRefElement extends UmbLitElement {
110184
return html`${this._component}`;
111185
}
112186

187+
override destroy(): void {
188+
this._component?.removeEventListener(UmbSelectedEvent.TYPE, this.#onSelected.bind(this));
189+
this._component?.removeEventListener(UmbDeselectedEvent.TYPE, this.#onDeselected.bind(this));
190+
super.destroy();
191+
}
192+
113193
static override styles = [
114194
css`
115195
:host {

src/Umbraco.Web.UI.Client/src/packages/core/picker/search/picker-search-result.element.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ export class UmbPickerSearchResultElement extends UmbLitElement {
6868
}
6969

7070
#renderResultItem(item: UmbEntityModel) {
71-
console.log('pickableFilter', this.pickableFilter(item));
7271
return html`
7372
<umb-extension-with-api-slot
7473
type="pickerSearchResultItem"

0 commit comments

Comments
 (0)