@c8y/ngx-components 1022.26.1 → 1022.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/core/search/inventory-search.service.d.ts +4 -3
  2. package/core/search/inventory-search.service.d.ts.map +1 -1
  3. package/core/search/search-input.component.d.ts +5 -2
  4. package/core/search/search-input.component.d.ts.map +1 -1
  5. package/core/search/search.model.d.ts +4 -0
  6. package/core/search/search.model.d.ts.map +1 -1
  7. package/core/search/search.service.d.ts +2 -1
  8. package/core/search/search.service.d.ts.map +1 -1
  9. package/core/select/typeahead.component.d.ts +2 -1
  10. package/core/select/typeahead.component.d.ts.map +1 -1
  11. package/device-grid/device-grid.component.d.ts.map +1 -1
  12. package/device-grid/device-grid.service.d.ts +4 -3
  13. package/device-grid/device-grid.service.d.ts.map +1 -1
  14. package/echart/charts.component.d.ts.map +1 -1
  15. package/ecosystem/application-plugins/application-plugins.component.d.ts +3 -0
  16. package/ecosystem/application-plugins/application-plugins.component.d.ts.map +1 -1
  17. package/fesm2022/c8y-ngx-components-assets-navigator.mjs +2 -2
  18. package/fesm2022/c8y-ngx-components-assets-navigator.mjs.map +1 -1
  19. package/fesm2022/c8y-ngx-components-datapoint-selector.mjs +1 -1
  20. package/fesm2022/c8y-ngx-components-datapoint-selector.mjs.map +1 -1
  21. package/fesm2022/c8y-ngx-components-device-grid.mjs +21 -13
  22. package/fesm2022/c8y-ngx-components-device-grid.mjs.map +1 -1
  23. package/fesm2022/c8y-ngx-components-device-profile.mjs +1 -1
  24. package/fesm2022/c8y-ngx-components-device-profile.mjs.map +1 -1
  25. package/fesm2022/c8y-ngx-components-echart.mjs +22 -70
  26. package/fesm2022/c8y-ngx-components-echart.mjs.map +1 -1
  27. package/fesm2022/c8y-ngx-components-ecosystem-application-plugins.mjs +41 -21
  28. package/fesm2022/c8y-ngx-components-ecosystem-application-plugins.mjs.map +1 -1
  29. package/fesm2022/c8y-ngx-components-ecosystem-shared.mjs +1 -1
  30. package/fesm2022/c8y-ngx-components-ecosystem-shared.mjs.map +1 -1
  31. package/fesm2022/c8y-ngx-components-ecosystem.mjs +1 -1
  32. package/fesm2022/c8y-ngx-components-ecosystem.mjs.map +1 -1
  33. package/fesm2022/c8y-ngx-components-operations-stepper-bulk-type-configuration.mjs +1 -1
  34. package/fesm2022/c8y-ngx-components-operations-stepper-bulk-type-configuration.mjs.map +1 -1
  35. package/fesm2022/c8y-ngx-components-operations-stepper-bulk-type-device-profile.mjs +1 -1
  36. package/fesm2022/c8y-ngx-components-operations-stepper-bulk-type-device-profile.mjs.map +1 -1
  37. package/fesm2022/c8y-ngx-components-operations-stepper-bulk-type-software.mjs +1 -1
  38. package/fesm2022/c8y-ngx-components-operations-stepper-bulk-type-software.mjs.map +1 -1
  39. package/fesm2022/c8y-ngx-components-protocol-lpwan.mjs +2 -2
  40. package/fesm2022/c8y-ngx-components-protocol-lpwan.mjs.map +1 -1
  41. package/fesm2022/c8y-ngx-components-repository-configuration.mjs +1 -1
  42. package/fesm2022/c8y-ngx-components-repository-configuration.mjs.map +1 -1
  43. package/fesm2022/c8y-ngx-components-repository-firmware.mjs +2 -2
  44. package/fesm2022/c8y-ngx-components-repository-firmware.mjs.map +1 -1
  45. package/fesm2022/c8y-ngx-components-repository-shared.mjs +2 -2
  46. package/fesm2022/c8y-ngx-components-repository-shared.mjs.map +1 -1
  47. package/fesm2022/c8y-ngx-components-repository-software.mjs +1 -1
  48. package/fesm2022/c8y-ngx-components-repository-software.mjs.map +1 -1
  49. package/fesm2022/c8y-ngx-components-search.mjs +328 -210
  50. package/fesm2022/c8y-ngx-components-search.mjs.map +1 -1
  51. package/fesm2022/c8y-ngx-components-sub-assets.mjs +36 -16
  52. package/fesm2022/c8y-ngx-components-sub-assets.mjs.map +1 -1
  53. package/fesm2022/c8y-ngx-components.mjs +7390 -7345
  54. package/fesm2022/c8y-ngx-components.mjs.map +1 -1
  55. package/locales/de.po +5 -0
  56. package/locales/es.po +5 -0
  57. package/locales/fr.po +5 -0
  58. package/locales/ja_JP.po +4 -0
  59. package/locales/ko.po +5 -0
  60. package/locales/locales.pot +24 -0
  61. package/locales/nl.po +5 -0
  62. package/locales/pl.po +5 -0
  63. package/locales/pt_BR.po +5 -0
  64. package/locales/zh_CN.po +5 -0
  65. package/locales/zh_TW.po +5 -0
  66. package/package.json +1 -1
  67. package/search/columns/asset-type-search-grid-column.d.ts.map +1 -1
  68. package/search/search-action.component.d.ts +12 -8
  69. package/search/search-action.component.d.ts.map +1 -1
  70. package/search/search-custom-filters.component.d.ts +18 -4
  71. package/search/search-custom-filters.component.d.ts.map +1 -1
  72. package/search/search-grid.component.d.ts +14 -14
  73. package/search/search-grid.component.d.ts.map +1 -1
  74. package/search/search-results.component.d.ts +3 -1
  75. package/search/search-results.component.d.ts.map +1 -1
  76. package/search/search.module.d.ts.map +1 -1
  77. package/search/search.service.d.ts +14 -6
  78. package/search/search.service.d.ts.map +1 -1
  79. package/sub-assets/sub-assets.service.d.ts +9 -5
  80. package/sub-assets/sub-assets.service.d.ts.map +1 -1
  81. package/echart/services/custom-measurements.service.d.ts +0 -12
  82. package/echart/services/custom-measurements.service.d.ts.map +0 -1
@@ -1,33 +1,37 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, InjectionToken, EventEmitter, ViewChild, Input, Output, Optional, Inject, Component, NgModule } from '@angular/core';
3
- import * as i3 from '@c8y/client';
4
- import { QueriesUtil } from '@c8y/client';
5
- import * as i2$2 from '@c8y/ngx-components';
6
- import { getBasicInputArrayFormFieldConfig, gettext, SearchFilters, BuiltInActionType, FilteringActionType, DataGridComponent, ColumnDirective, EmptyStateComponent, C8yTranslatePipe, UserPreferencesConfigurationStrategy, DATA_GRID_CONFIGURATION_STRATEGY, DATA_GRID_CONFIGURATION_CONTEXT_PROVIDER, Status, TitleComponent, C8yTranslateDirective, SearchInputComponent, CoreModule, CoreSearchModule, hookRoute, hookSearch } from '@c8y/ngx-components';
7
- import * as i2 from '@c8y/ngx-components/assets-navigator';
8
- import * as i1 from '@c8y/ngx-components/device-grid';
9
- import { NameDeviceGridColumn, ModelDeviceGridColumn, SerialNumberDeviceGridColumn, RegistrationDateDeviceGridColumn, SystemIdDeviceGridColumn, ImeiDeviceGridColumn, AlarmsDeviceGridColumn, DeviceGridModule } from '@c8y/ngx-components/device-grid';
10
- import { BehaviorSubject, Subject } from 'rxjs';
11
- import * as i1$1 from '@angular/router';
12
- import { takeUntil } from 'rxjs/operators';
13
- import * as i4 from '@c8y/ngx-components/sub-assets';
14
- import { DeleteAssetsModalComponent } from '@c8y/ngx-components/sub-assets';
15
- import * as i2$1 from 'ngx-bootstrap/modal';
2
+ import { inject, Injectable, InjectionToken, EventEmitter, Output, Input, Component, ViewChild, NgModule } from '@angular/core';
3
+ import { QueriesUtil, SmartGroupsService } from '@c8y/client';
4
+ import * as i2 from '@c8y/ngx-components';
5
+ import { PreviewService, ContextRouteService, WILDCARD_SEARCH_FEATURE_KEY, gettext, SearchFilters, ViewContext, C8yTranslatePipe, TabsOutletComponent, TabComponent, RouterService, SearchInputComponent, getBasicInputArrayFormFieldConfig, BuiltInActionType, FilteringActionType, DataGridComponent, ColumnDirective, EmptyStateComponent, UserPreferencesConfigurationStrategy, DATA_GRID_CONFIGURATION_STRATEGY, DATA_GRID_CONFIGURATION_CONTEXT_PROVIDER, Status, TitleComponent, C8yTranslateDirective, CoreModule, CoreSearchModule, hookRoute, hookSearch } from '@c8y/ngx-components';
6
+ import { AssetNodeService } from '@c8y/ngx-components/assets-navigator';
7
+ import { DeviceGridService, NameDeviceGridColumn, ModelDeviceGridColumn, SerialNumberDeviceGridColumn, RegistrationDateDeviceGridColumn, SystemIdDeviceGridColumn, ImeiDeviceGridColumn, AlarmsDeviceGridColumn, DeviceGridModule } from '@c8y/ngx-components/device-grid';
8
+ import { BehaviorSubject, firstValueFrom, catchError, of, lastValueFrom, Subject } from 'rxjs';
16
9
  import { AssetTypeGridColumn, AssetTypeCellRendererComponent } from '@c8y/ngx-components/data-grid-columns/asset-type';
17
- import { NgFor, NgIf } from '@angular/common';
10
+ import { NgFor, AsyncPipe, NgIf } from '@angular/common';
11
+ import * as i1$1 from '@angular/router';
12
+ import { Router, ActivationEnd } from '@angular/router';
13
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
14
+ import * as i1 from '@angular/forms';
15
+ import { FormsModule } from '@angular/forms';
16
+ import { filter, map, startWith, catchError as catchError$1, takeUntil } from 'rxjs/operators';
17
+ import { SubAssetsService, DeleteAssetsModalComponent } from '@c8y/ngx-components/sub-assets';
18
+ import { BsModalService } from 'ngx-bootstrap/modal';
18
19
 
19
20
  class AssetSearchService {
20
- constructor(deviceGridService, assetNodeService) {
21
- this.deviceGridService = deviceGridService;
22
- this.assetNodeService = assetNodeService;
21
+ constructor() {
23
22
  this.GRID_CONFIG_STORAGE_KEY = 'search-grid-config';
24
23
  this.DEFAULT_PAGE_SIZE = 50;
25
24
  this.getGlobalSearchData = this.getSearchData.bind(this);
26
25
  this.appliedFilters$ = new BehaviorSubject({
27
26
  allFilters: true,
28
27
  onlyDevices: true,
29
- onlyGroupsAndAssets: true
28
+ onlyGroupsAndAssets: true,
29
+ currentHierarchy: false
30
30
  });
31
+ this.previewService = inject(PreviewService);
32
+ this.deviceGridService = inject(DeviceGridService);
33
+ this.assetNodeService = inject(AssetNodeService);
34
+ this.contextRouteService = inject(ContextRouteService);
31
35
  this.queriesUtil = new QueriesUtil();
32
36
  }
33
37
  /**
@@ -38,7 +42,8 @@ class AssetSearchService {
38
42
  this.appliedFilters$.next({
39
43
  allFilters: true,
40
44
  onlyDevices: true,
41
- onlyGroupsAndAssets: true
45
+ onlyGroupsAndAssets: true,
46
+ currentHierarchy: false
42
47
  });
43
48
  }
44
49
  buildCombinedRootQueryFilter(columns, pagination) {
@@ -53,11 +58,24 @@ class AssetSearchService {
53
58
  const queryPart = this.queriesUtil.addOrderbys(rootQuery, userQuery.__orderby, 'append');
54
59
  const fullQuery = this.queriesUtil.addAndFilter(queryPart, userQuery.__filter);
55
60
  const queryWithSearch = this.queriesUtil.addAndFilter(fullQuery, searchQuery);
56
- return this.queriesUtil.buildQuery(queryWithSearch);
61
+ return queryWithSearch;
57
62
  }
58
63
  async getData(columns, pagination, text) {
59
64
  const query = this.buildCombinedRootQueryFilter(columns, pagination);
60
- return this.assetNodeService.getAllInventories({ ...pagination, query, text });
65
+ if (await this.isWildcardSearchEnabled()) {
66
+ const wildcardQuery = this.queriesUtil.addAndFilter(query, {
67
+ name: `*${text.trim().replace(/\s+/g, '*')}*`
68
+ });
69
+ return this.assetNodeService.getAllInventories({
70
+ ...pagination,
71
+ query: this.queriesUtil.buildQuery(wildcardQuery)
72
+ });
73
+ }
74
+ return this.assetNodeService.getAllInventories({
75
+ ...pagination,
76
+ query: this.queriesUtil.buildQuery(query),
77
+ text
78
+ });
61
79
  }
62
80
  getDefaultColumns() {
63
81
  const defaultColumns = [
@@ -83,6 +101,9 @@ class AssetSearchService {
83
101
  currentPage: 1
84
102
  };
85
103
  }
104
+ async isWildcardSearchEnabled() {
105
+ return firstValueFrom(this.previewService.getState$(WILDCARD_SEARCH_FEATURE_KEY).pipe(catchError(() => of(true))));
106
+ }
86
107
  buildSearchQuery(model) {
87
108
  const filter = {};
88
109
  const ors = [];
@@ -96,18 +117,45 @@ class AssetSearchService {
96
117
  ors.push({ __has: 'c8y_IsDynamicGroup' });
97
118
  ors.push({ __has: 'c8y_IsDeviceGroup' });
98
119
  }
120
+ if (!model.onlyDevices && !model.onlyGroupsAndAssets) {
121
+ ors.push([
122
+ { __has: 'c8y_IsDeviceGroup' },
123
+ { __has: 'c8y_IsDevice' },
124
+ { __has: 'c8y_IsAsset' }
125
+ ]);
126
+ }
99
127
  if (ors.length) {
100
128
  filter.__or = ors;
101
129
  }
130
+ if (model.currentHierarchy && this.contextRouteService.activatedContextData?.contextData?.id) {
131
+ filter.__and = [
132
+ { __isinhierarchyof: this.contextRouteService.activatedContextData.contextData.id }
133
+ ];
134
+ }
102
135
  return filter;
103
136
  }
137
+ /**
138
+ * Get search data based on the provided text and pagination.
139
+ * @param text The search text.
140
+ * @param pagination The pagination options.
141
+ * @returns The search results.
142
+ */
104
143
  async getSearchData(text, pagination = { currentPage: 1, pageSize: this.DEFAULT_PAGE_SIZE }) {
105
- const { onlyDevices, onlyGroupsAndAssets } = this.appliedFilters$.value;
106
- const query = this.buildSearchQuery({ onlyDevices, onlyGroupsAndAssets });
144
+ const { onlyDevices, onlyGroupsAndAssets, currentHierarchy } = this.appliedFilters$.value;
145
+ const query = this.buildSearchQuery({ onlyDevices, onlyGroupsAndAssets, currentHierarchy });
107
146
  const queryString = this.queriesUtil.buildQuery(query);
147
+ if (await this.isWildcardSearchEnabled()) {
148
+ const wildcardQuery = this.queriesUtil.addAndFilter(query, {
149
+ name: `*${text.trim().replace(/\s+/g, '*')}*`
150
+ });
151
+ return this.assetNodeService.getAllInventories({
152
+ ...pagination,
153
+ query: this.queriesUtil.buildQuery(wildcardQuery)
154
+ });
155
+ }
108
156
  return this.assetNodeService.getAllInventories({ ...pagination, query: queryString, text });
109
157
  }
110
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AssetSearchService, deps: [{ token: i1.DeviceGridService }, { token: i2.AssetNodeService }], target: i0.ɵɵFactoryTarget.Injectable }); }
158
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AssetSearchService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
111
159
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AssetSearchService, providedIn: 'root' }); }
112
160
  }
113
161
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AssetSearchService, decorators: [{
@@ -115,7 +163,210 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
115
163
  args: [{
116
164
  providedIn: 'root'
117
165
  }]
118
- }], ctorParameters: () => [{ type: i1.DeviceGridService }, { type: i2.AssetNodeService }] });
166
+ }], ctorParameters: () => [] });
167
+
168
+ const SEARCH_CONFIG = new InjectionToken('SearchConfig');
169
+
170
+ class SearchCustomFiltersComponent {
171
+ constructor() {
172
+ this.useTabs = false;
173
+ this.customDataQuery = new EventEmitter();
174
+ this.refresh = new EventEmitter();
175
+ this.tabNames = {
176
+ all: gettext('All'),
177
+ devices: gettext('Devices'),
178
+ groupsAndAssets: gettext('Groups and assets')
179
+ };
180
+ this.selectedTab = this.tabNames.all;
181
+ this.checkboxesState = [
182
+ {
183
+ label: gettext('All'),
184
+ name: SearchFilters.ALL_FILTERS,
185
+ value: true,
186
+ indeterminate: false,
187
+ isDisabled: true
188
+ },
189
+ { label: gettext('Show only devices'), name: SearchFilters.ONLY_DEVICES, value: true },
190
+ {
191
+ label: gettext('Show only groups and assets'),
192
+ name: SearchFilters.ONLY_GROUPS_AND_ASSETS,
193
+ value: true
194
+ }
195
+ ];
196
+ this.isOnlyHierarchyQuery = false;
197
+ this.isOnlyHierarchyQueryChange = new EventEmitter();
198
+ this.assetSearchService = inject(AssetSearchService);
199
+ this.contextRouteService = inject(ContextRouteService);
200
+ this.router = inject(Router);
201
+ this.contextRouteData$ = this.router.events.pipe(filter(event => event instanceof ActivationEnd), map((routeData) => {
202
+ const data = this.contextRouteService.getContextData(routeData.snapshot);
203
+ if (data?.context === ViewContext.Group) {
204
+ return data;
205
+ }
206
+ return null;
207
+ }), takeUntilDestroyed());
208
+ this.context$ = this.contextRouteData$.pipe(startWith(this.contextRouteService.activatedContextData), takeUntilDestroyed());
209
+ }
210
+ ngOnInit() {
211
+ this.customDataQuery.next(this.assetSearchService.getGlobalSearchData);
212
+ }
213
+ onCheckboxChange(event, checkbox) {
214
+ const { checked } = event.target;
215
+ if (checked == undefined) {
216
+ return;
217
+ }
218
+ switch (checkbox.name) {
219
+ case SearchFilters.ALL_FILTERS:
220
+ this.onSelectAll(checkbox, checked);
221
+ break;
222
+ case SearchFilters.ONLY_DEVICES:
223
+ this.onAllDevices(checkbox, checked);
224
+ break;
225
+ case SearchFilters.ONLY_GROUPS_AND_ASSETS:
226
+ this.onGroupsAndAssets(checkbox, checked);
227
+ break;
228
+ }
229
+ // Handle allFilters checkbox when ONLY_GROUPS_AND_ASSETS and ONLY_DEVICES are selected
230
+ if (this.getCheckbox(SearchFilters.ONLY_DEVICES).value &&
231
+ this.getCheckbox(SearchFilters.ONLY_GROUPS_AND_ASSETS).value) {
232
+ Object.assign(this.getCheckbox(SearchFilters.ALL_FILTERS), {
233
+ indeterminate: false,
234
+ isDisabled: true,
235
+ value: true
236
+ });
237
+ }
238
+ this.onSearchFilterChange(this.getCheckbox(SearchFilters.ALL_FILTERS).value, this.getCheckbox(SearchFilters.ONLY_DEVICES).value, this.getCheckbox(SearchFilters.ONLY_GROUPS_AND_ASSETS).value);
239
+ this.refresh.next(null);
240
+ }
241
+ onTabChange(tabName = this.tabNames.all) {
242
+ this.selectedTab = tabName;
243
+ this.onSearchFilterChange(tabName === this.tabNames.all, tabName === this.tabNames.devices, tabName === this.tabNames.groupsAndAssets, this.isOnlyHierarchyQuery);
244
+ }
245
+ onHierarchyQueryChange(checked) {
246
+ this.isOnlyHierarchyQuery = checked;
247
+ this.isOnlyHierarchyQueryChange.next(checked);
248
+ this.onSearchFilterChange(this.selectedTab === this.tabNames.all, this.selectedTab === this.tabNames.devices, this.selectedTab === this.tabNames.groupsAndAssets, checked);
249
+ }
250
+ onSearchFilterChange(all, devices, groupsAndAssets, currentHierarchy = false) {
251
+ this.assetSearchService.appliedFilters$.next({
252
+ [SearchFilters.ALL_FILTERS]: all,
253
+ [SearchFilters.ONLY_DEVICES]: devices,
254
+ [SearchFilters.ONLY_GROUPS_AND_ASSETS]: groupsAndAssets,
255
+ [SearchFilters.CURRENT_HIERARCHY]: currentHierarchy
256
+ });
257
+ this.refresh.next(null);
258
+ }
259
+ saveCheckboxValue(checkbox, value) {
260
+ checkbox.value = value;
261
+ }
262
+ onSelectAll(currentCheckbox, checked) {
263
+ // Block unchecked state
264
+ if (checked) {
265
+ this.saveCheckboxValue(currentCheckbox, checked);
266
+ }
267
+ this.getCheckbox(SearchFilters.ALL_FILTERS).isDisabled = true;
268
+ this.getCheckbox(SearchFilters.ONLY_DEVICES).value = true;
269
+ this.getCheckbox(SearchFilters.ONLY_GROUPS_AND_ASSETS).value = true;
270
+ }
271
+ onAllDevices(currentCheckbox, checked) {
272
+ this.saveCheckboxValue(currentCheckbox, checked);
273
+ Object.assign(this.getCheckbox(SearchFilters.ALL_FILTERS), {
274
+ indeterminate: true,
275
+ isDisabled: false,
276
+ value: null
277
+ });
278
+ this.getCheckbox(SearchFilters.ONLY_GROUPS_AND_ASSETS).value = true;
279
+ }
280
+ onGroupsAndAssets(currentCheckbox, checked) {
281
+ this.saveCheckboxValue(currentCheckbox, checked);
282
+ Object.assign(this.getCheckbox(SearchFilters.ALL_FILTERS), {
283
+ indeterminate: true,
284
+ isDisabled: false,
285
+ value: null
286
+ });
287
+ this.getCheckbox(SearchFilters.ONLY_DEVICES).value = true;
288
+ }
289
+ getCheckbox(checkboxName) {
290
+ return this.checkboxesState.find(checkbox => checkbox.name === checkboxName);
291
+ }
292
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SearchCustomFiltersComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
293
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: SearchCustomFiltersComponent, isStandalone: true, selector: "c8y-search-custom-filters", inputs: { useTabs: "useTabs", isOnlyHierarchyQuery: "isOnlyHierarchyQuery" }, outputs: { customDataQuery: "customDataQuery", refresh: "refresh", isOnlyHierarchyQueryChange: "isOnlyHierarchyQueryChange" }, ngImport: i0, template: "<div class=\"d-flex gap-16 p-l-4 p-l-24 p-r-24\">\n <div\n class=\"p-b-8 separator-bottom sticky-top p-t-4\"\n *ngIf=\"!useTabs\"\n >\n <label\n class=\"c8y-checkbox\"\n *ngFor=\"let checkbox of checkboxesState\"\n >\n <input\n type=\"checkbox\"\n [checked]=\"checkbox.value\"\n [indeterminate]=\"checkbox.indeterminate\"\n (click)=\"onCheckboxChange($event, checkbox)\"\n [attr.disabled]=\"checkbox.isDisabled ? true : null\"\n />\n <span></span>\n <span>{{ checkbox.label | translate }}</span>\n </label>\n </div>\n</div>\n\n<c8y-tabs-outlet\n class=\"elevation-none\"\n *ngIf=\"useTabs\"\n outletName=\"searchTabs\"\n orientation=\"horizontal\"\n></c8y-tabs-outlet>\n\n<c8y-tab\n [icon]=\"'asterisk-key'\"\n [title]=\"'All devices, assets and groups' | translate\"\n [isActive]=\"selectedTab === tabNames.all\"\n [tabsOutlet]=\"'searchTabs'\"\n [label]=\"tabNames.all | translate\"\n [priority]=\"1000\"\n (onSelect)=\"onTabChange(tabNames.all)\"\n></c8y-tab>\n<c8y-tab\n [icon]=\"'exchange'\"\n [title]=\"'Devices only' | translate\"\n [isActive]=\"selectedTab === tabNames.devices\"\n [tabsOutlet]=\"'searchTabs'\"\n [label]=\"tabNames.devices | translate\"\n [priority]=\"750\"\n (onSelect)=\"onTabChange(tabNames.devices)\"\n></c8y-tab>\n<c8y-tab\n [icon]=\"'c8y-modules'\"\n [title]=\"'Assets and groups only' | translate\"\n [isActive]=\"selectedTab === tabNames.groupsAndAssets\"\n [tabsOutlet]=\"'searchTabs'\"\n [label]=\"tabNames.groupsAndAssets | translate\"\n [priority]=\"500\"\n (onSelect)=\"onTabChange(tabNames.groupsAndAssets)\"\n></c8y-tab>\n\n<div\n class=\"p-l-48 p-t-8 d-flex a-i-center\"\n *ngIf=\"useTabs && (context$ | async)?.contextData?.name\"\n>\n <span translate>Search only in</span>\n <span class=\"text-bold p-l-4\">{{ (context$ | async)?.contextData?.name }}</span>\n <label\n class=\"m-l-8 c8y-switch c8y-switch--inline\"\n [title]=\"'Search only within the current group or asset hierarchy' | translate\"\n >\n <input\n type=\"checkbox\"\n [ngModel]=\"isOnlyHierarchyQuery\"\n [attr.aria-label]=\"'Search only within the current group or asset hierarchy' | translate\"\n (ngModelChange)=\"onHierarchyQueryChange($event)\"\n />\n <span></span>\n </label>\n</div>\n", dependencies: [{ kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "component", type: TabsOutletComponent, selector: "c8y-tabs-outlet,c8y-ui-tabs", inputs: ["tabs", "orientation", "navigatorOpen", "outletName", "context", "openFirstTab", "hasHeader"] }, { kind: "component", type: TabComponent, selector: "c8y-tab", inputs: ["path", "label", "icon", "priority", "orientation", "injector", "tabsOutlet", "isActive", "showAlways"], outputs: ["onSelect"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] }); }
294
+ }
295
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SearchCustomFiltersComponent, decorators: [{
296
+ type: Component,
297
+ args: [{ selector: 'c8y-search-custom-filters', imports: [
298
+ NgFor,
299
+ C8yTranslatePipe,
300
+ TabsOutletComponent,
301
+ TabComponent,
302
+ AsyncPipe,
303
+ NgIf,
304
+ FormsModule
305
+ ], template: "<div class=\"d-flex gap-16 p-l-4 p-l-24 p-r-24\">\n <div\n class=\"p-b-8 separator-bottom sticky-top p-t-4\"\n *ngIf=\"!useTabs\"\n >\n <label\n class=\"c8y-checkbox\"\n *ngFor=\"let checkbox of checkboxesState\"\n >\n <input\n type=\"checkbox\"\n [checked]=\"checkbox.value\"\n [indeterminate]=\"checkbox.indeterminate\"\n (click)=\"onCheckboxChange($event, checkbox)\"\n [attr.disabled]=\"checkbox.isDisabled ? true : null\"\n />\n <span></span>\n <span>{{ checkbox.label | translate }}</span>\n </label>\n </div>\n</div>\n\n<c8y-tabs-outlet\n class=\"elevation-none\"\n *ngIf=\"useTabs\"\n outletName=\"searchTabs\"\n orientation=\"horizontal\"\n></c8y-tabs-outlet>\n\n<c8y-tab\n [icon]=\"'asterisk-key'\"\n [title]=\"'All devices, assets and groups' | translate\"\n [isActive]=\"selectedTab === tabNames.all\"\n [tabsOutlet]=\"'searchTabs'\"\n [label]=\"tabNames.all | translate\"\n [priority]=\"1000\"\n (onSelect)=\"onTabChange(tabNames.all)\"\n></c8y-tab>\n<c8y-tab\n [icon]=\"'exchange'\"\n [title]=\"'Devices only' | translate\"\n [isActive]=\"selectedTab === tabNames.devices\"\n [tabsOutlet]=\"'searchTabs'\"\n [label]=\"tabNames.devices | translate\"\n [priority]=\"750\"\n (onSelect)=\"onTabChange(tabNames.devices)\"\n></c8y-tab>\n<c8y-tab\n [icon]=\"'c8y-modules'\"\n [title]=\"'Assets and groups only' | translate\"\n [isActive]=\"selectedTab === tabNames.groupsAndAssets\"\n [tabsOutlet]=\"'searchTabs'\"\n [label]=\"tabNames.groupsAndAssets | translate\"\n [priority]=\"500\"\n (onSelect)=\"onTabChange(tabNames.groupsAndAssets)\"\n></c8y-tab>\n\n<div\n class=\"p-l-48 p-t-8 d-flex a-i-center\"\n *ngIf=\"useTabs && (context$ | async)?.contextData?.name\"\n>\n <span translate>Search only in</span>\n <span class=\"text-bold p-l-4\">{{ (context$ | async)?.contextData?.name }}</span>\n <label\n class=\"m-l-8 c8y-switch c8y-switch--inline\"\n [title]=\"'Search only within the current group or asset hierarchy' | translate\"\n >\n <input\n type=\"checkbox\"\n [ngModel]=\"isOnlyHierarchyQuery\"\n [attr.aria-label]=\"'Search only within the current group or asset hierarchy' | translate\"\n (ngModelChange)=\"onHierarchyQueryChange($event)\"\n />\n <span></span>\n </label>\n</div>\n" }]
306
+ }], propDecorators: { useTabs: [{
307
+ type: Input
308
+ }], customDataQuery: [{
309
+ type: Output
310
+ }], refresh: [{
311
+ type: Output
312
+ }], isOnlyHierarchyQuery: [{
313
+ type: Input
314
+ }], isOnlyHierarchyQueryChange: [{
315
+ type: Output
316
+ }] } });
317
+
318
+ class SearchActionComponent {
319
+ constructor() {
320
+ this.typeaheadReload = new EventEmitter();
321
+ this.previewService = inject(PreviewService);
322
+ this.isWildcardSearchEnabled$ = this.previewService
323
+ .getState$(WILDCARD_SEARCH_FEATURE_KEY)
324
+ .pipe(catchError(() => of(true)));
325
+ this.c8yRouter = inject(RouterService);
326
+ this.router = inject(Router);
327
+ this.moduleConfig = inject(SEARCH_CONFIG, { optional: true });
328
+ this.isOnlyHierarchyQuery = false;
329
+ this.showAdvancedFilters = this.moduleConfig?.showAdvancedFilters ?? true;
330
+ this.customPlaceholder = this.moduleConfig?.placeholder;
331
+ }
332
+ triggerDataLoad() {
333
+ this.typeaheadReload.next(null);
334
+ }
335
+ onOpenChange(isOpen) {
336
+ if (isOpen) {
337
+ this.triggerDataLoad();
338
+ }
339
+ }
340
+ async onSearch(on) {
341
+ if (await lastValueFrom(this.isWildcardSearchEnabled$)) {
342
+ return;
343
+ }
344
+ this.navigate(['/assetsearch'], {
345
+ queryParams: { search: on },
346
+ replaceUrl: true
347
+ });
348
+ }
349
+ onFilter(on) {
350
+ this.navigate(['/assetsearch'], {
351
+ queryParams: { filter: on },
352
+ replaceUrl: true
353
+ });
354
+ }
355
+ onClick(mo) {
356
+ this.router.navigateByUrl(this.c8yRouter.getHref(mo, '/'));
357
+ }
358
+ navigate(commands, extras) {
359
+ this.router
360
+ .navigateByUrl('/', { skipLocationChange: true })
361
+ .then(() => this.router.navigate(commands, extras));
362
+ }
363
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SearchActionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
364
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: SearchActionComponent, isStandalone: true, selector: "c8y-search-action", ngImport: i0, template: "<c8y-search-input\n #input\n (filter)=\"onFilter($event)\"\n (search)=\"onSearch($event)\"\n (onClick)=\"onClick($event)\"\n (onOpenToggle)=\"onOpenChange($event)\"\n [enableCustomTemplatePlaceholder]=\"true\"\n [customPlaceholder]=\"customPlaceholder\"\n [customDataQuery]=\"customQuery\"\n [externalTerm]=\"typeaheadReload\"\n [mode]=\"(isWildcardSearchEnabled$ | async) ? 'wildcardsearch' : 'search'\"\n>\n <c8y-search-custom-filters\n *ngIf=\"showAdvancedFilters && input.term.length > 0\"\n (refresh)=\"triggerDataLoad()\"\n [useTabs]=\"isWildcardSearchEnabled$ | async\"\n [(isOnlyHierarchyQuery)]=\"isOnlyHierarchyQuery\"\n (customDataQuery)=\"customQuery = $event\"\n ></c8y-search-custom-filters>\n</c8y-search-input>\n", dependencies: [{ kind: "component", type: SearchInputComponent, selector: "c8y-search-input", inputs: ["mode", "enableCustomTemplatePlaceholder", "customPlaceholder", "externalTerm", "customDataQuery", "container", "groupsOnly"], outputs: ["filter", "search", "reset", "onClick", "onOpenToggle"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: SearchCustomFiltersComponent, selector: "c8y-search-custom-filters", inputs: ["useTabs", "isOnlyHierarchyQuery"], outputs: ["customDataQuery", "refresh", "isOnlyHierarchyQueryChange"] }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
365
+ }
366
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SearchActionComponent, decorators: [{
367
+ type: Component,
368
+ args: [{ selector: 'c8y-search-action', imports: [SearchInputComponent, NgIf, SearchCustomFiltersComponent, AsyncPipe], template: "<c8y-search-input\n #input\n (filter)=\"onFilter($event)\"\n (search)=\"onSearch($event)\"\n (onClick)=\"onClick($event)\"\n (onOpenToggle)=\"onOpenChange($event)\"\n [enableCustomTemplatePlaceholder]=\"true\"\n [customPlaceholder]=\"customPlaceholder\"\n [customDataQuery]=\"customQuery\"\n [externalTerm]=\"typeaheadReload\"\n [mode]=\"(isWildcardSearchEnabled$ | async) ? 'wildcardsearch' : 'search'\"\n>\n <c8y-search-custom-filters\n *ngIf=\"showAdvancedFilters && input.term.length > 0\"\n (refresh)=\"triggerDataLoad()\"\n [useTabs]=\"isWildcardSearchEnabled$ | async\"\n [(isOnlyHierarchyQuery)]=\"isOnlyHierarchyQuery\"\n (customDataQuery)=\"customQuery = $event\"\n ></c8y-search-custom-filters>\n</c8y-search-input>\n" }]
369
+ }], ctorParameters: () => [] });
119
370
 
120
371
  class AssetTypeSearchGridColumn extends AssetTypeGridColumn {
121
372
  constructor(hideExtendedFilters, initialColumnConfig, assetSearchService, customPlaceholder) {
@@ -152,7 +403,8 @@ class AssetTypeSearchGridColumn extends AssetTypeGridColumn {
152
403
  assetSearchService.appliedFilters$.next({
153
404
  [SearchFilters.ALL_FILTERS]: checked,
154
405
  [SearchFilters.ONLY_DEVICES]: true,
155
- [SearchFilters.ONLY_GROUPS_AND_ASSETS]: true
406
+ [SearchFilters.ONLY_GROUPS_AND_ASSETS]: true,
407
+ [SearchFilters.CURRENT_HIERARCHY]: null
156
408
  });
157
409
  }
158
410
  }
@@ -214,7 +466,8 @@ class AssetTypeSearchGridColumn extends AssetTypeGridColumn {
214
466
  assetSearchService.appliedFilters$.next({
215
467
  [SearchFilters.ALL_FILTERS]: null,
216
468
  [SearchFilters.ONLY_GROUPS_AND_ASSETS]: true,
217
- [SearchFilters.ONLY_DEVICES]: checked
469
+ [SearchFilters.ONLY_DEVICES]: checked,
470
+ [SearchFilters.CURRENT_HIERARCHY]: null
218
471
  });
219
472
  }
220
473
  },
@@ -254,7 +507,8 @@ class AssetTypeSearchGridColumn extends AssetTypeGridColumn {
254
507
  assetSearchService.appliedFilters$.next({
255
508
  [SearchFilters.ALL_FILTERS]: null,
256
509
  [SearchFilters.ONLY_GROUPS_AND_ASSETS]: checked,
257
- [SearchFilters.ONLY_DEVICES]: true
510
+ [SearchFilters.ONLY_DEVICES]: true,
511
+ [SearchFilters.CURRENT_HIERARCHY]: false
258
512
  });
259
513
  }
260
514
  },
@@ -285,9 +539,31 @@ class AssetTypeSearchGridColumn extends AssetTypeGridColumn {
285
539
  }
286
540
  }
287
541
 
288
- const SEARCH_CONFIG = new InjectionToken('SearchConfig');
289
-
290
542
  class SearchGridComponent {
543
+ constructor() {
544
+ this.title = '';
545
+ this.loadingItemsLabel = gettext('Loading results…');
546
+ this.selectable = false;
547
+ this.onColumnsChange = new EventEmitter();
548
+ this.searchText = '';
549
+ this.moduleConfig = inject(SEARCH_CONFIG, { optional: true });
550
+ this.showAdvancedFilters = this.moduleConfig?.showAdvancedFilters ?? false;
551
+ this.customPlaceholder = this.moduleConfig?.placeholder ?? undefined;
552
+ this.assetSearchService = inject(AssetSearchService);
553
+ this.pagination = this.assetSearchService.getDefaultPagination();
554
+ this.bulkActionControls = this.assetSearchService.getDefaultBulkActionControls();
555
+ this.refresh = new EventEmitter();
556
+ this.previewService = inject(PreviewService);
557
+ this.isWildcardSearchEnabled$ = this.previewService
558
+ .getState$(WILDCARD_SEARCH_FEATURE_KEY)
559
+ .pipe(catchError(() => of(true)));
560
+ this.wildcardSearchTitle = gettext('Asset data');
561
+ this.fullTextSearchTitle = gettext('Search results');
562
+ this.sizeCount = 0;
563
+ this.bsModalService = inject(BsModalService);
564
+ this.smartGroupsService = inject(SmartGroupsService);
565
+ this.subAssetsGridService = inject(SubAssetsService);
566
+ }
291
567
  set _columns(value) {
292
568
  if (value) {
293
569
  this.columns = value;
@@ -317,24 +593,6 @@ class SearchGridComponent {
317
593
  this.bulkActionControls = this.assetSearchService.getDefaultBulkActionControls();
318
594
  }
319
595
  }
320
- constructor(assetSearchService, bsModalService, smartGroupsService, subAssetsGridService, moduleConfig) {
321
- this.assetSearchService = assetSearchService;
322
- this.bsModalService = bsModalService;
323
- this.smartGroupsService = smartGroupsService;
324
- this.subAssetsGridService = subAssetsGridService;
325
- this.moduleConfig = moduleConfig;
326
- this.title = '';
327
- this.loadingItemsLabel = gettext('Loading results…');
328
- this.selectable = false;
329
- this.onColumnsChange = new EventEmitter();
330
- this.searchText = '';
331
- this.pagination = this.assetSearchService.getDefaultPagination();
332
- this.bulkActionControls = this.assetSearchService.getDefaultBulkActionControls();
333
- this.refresh = new EventEmitter();
334
- this.sizeCount = 0;
335
- this.showAdvancedFilters = moduleConfig?.showAdvancedFilters ?? false;
336
- this.customPlaceholder = moduleConfig?.placeholder ?? undefined;
337
- }
338
596
  getGridConfigContext() {
339
597
  return { key: this.columnsConfigKey || this.assetSearchService.GRID_CONFIG_STORAGE_KEY };
340
598
  }
@@ -450,7 +708,7 @@ class SearchGridComponent {
450
708
  });
451
709
  }
452
710
  }
453
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SearchGridComponent, deps: [{ token: AssetSearchService }, { token: i2$1.BsModalService }, { token: i3.SmartGroupsService }, { token: i4.SubAssetsService }, { token: SEARCH_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
711
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SearchGridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
454
712
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: SearchGridComponent, isStandalone: true, selector: "c8y-search-grid", inputs: { parentGroup: ["parent-group", "parentGroup"], title: "title", loadingItemsLabel: "loadingItemsLabel", _columns: ["columns", "_columns"], _pagination: ["pagination", "_pagination"], _actionControls: ["actionControls", "_actionControls"], selectable: "selectable", _bulkActionControls: ["bulkActionControls", "_bulkActionControls"], searchText: "searchText", filteringName: "filteringName", columnsConfigKey: "columnsConfigKey" }, outputs: { onColumnsChange: "onColumnsChange" }, providers: [
455
713
  {
456
714
  provide: DATA_GRID_CONFIGURATION_STRATEGY,
@@ -460,7 +718,7 @@ class SearchGridComponent {
460
718
  provide: DATA_GRID_CONFIGURATION_CONTEXT_PROVIDER,
461
719
  useExisting: SearchGridComponent
462
720
  }
463
- ], viewQueries: [{ propertyName: "dataGrid", first: true, predicate: DataGridComponent, descendants: true, static: true }], ngImport: i0, template: "<div class=\"card--grid--fullpage border-top border-bottom\">\n <c8y-data-grid\n [title]=\"'Search results' | translate\"\n [loadingItemsLabel]=\"loadingItemsLabel\"\n [columns]=\"columns\"\n [pagination]=\"pagination\"\n [actionControls]=\"actionControls\"\n [selectable]=\"selectable\"\n [bulkActionControls]=\"bulkActionControls\"\n [serverSideDataCallback]=\"serverSideDataCallback\"\n [infiniteScroll]=\"'auto'\"\n [showSearch]=\"true\"\n [searchText]=\"searchText\"\n [refresh]=\"refresh\"\n (onColumnFilterReset)=\"onColumnFilterReset($event)\"\n >\n <ng-container *ngFor=\"let column of columns; trackBy: trackByName\">\n <c8y-column [name]=\"column.name\"></c8y-column>\n </ng-container>\n\n <c8y-ui-empty-state\n [icon]=\"'search'\"\n [title]=\"'No results to display.' | translate\"\n [subtitle]=\"'Refine your search terms or check your spelling.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n </c8y-data-grid>\n</div>", dependencies: [{ kind: "component", type: DataGridComponent, selector: "c8y-data-grid", inputs: ["title", "loadMoreItemsLabel", "loadingItemsLabel", "showSearch", "refresh", "columns", "rows", "pagination", "childNodePagination", "infiniteScroll", "serverSideDataCallback", "selectable", "singleSelection", "selectionPrimaryKey", "displayOptions", "actionControls", "bulkActionControls", "headerActionControls", "searchText", "configureColumnsEnabled", "showCounterWarning", "activeClassName", "expandableRows", "treeGrid", "hideReload", "childNodesProperty", "parentNodeLabelProperty"], outputs: ["rowMouseOver", "rowMouseLeave", "rowClick", "onConfigChange", "onBeforeFilter", "onBeforeSearch", "onFilter", "itemsSelect", "onReload", "onAddCustomColumn", "onRemoveCustomColumn", "onColumnFilterReset", "onSort", "onPageSizeChange", "onColumnReordered", "onColumnVisibilityChange"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: ColumnDirective, selector: "c8y-column", inputs: ["name"] }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
721
+ ], viewQueries: [{ propertyName: "dataGrid", first: true, predicate: DataGridComponent, descendants: true, static: true }], ngImport: i0, template: "<div class=\"card--grid--fullpage border-top border-bottom\">\n <c8y-data-grid\n [title]=\"\n ((isWildcardSearchEnabled$ | async) ? wildcardSearchTitle : fullTextSearchTitle) | translate\n \"\n [loadingItemsLabel]=\"loadingItemsLabel\"\n [columns]=\"columns\"\n [pagination]=\"pagination\"\n [actionControls]=\"actionControls\"\n [selectable]=\"selectable\"\n [bulkActionControls]=\"bulkActionControls\"\n [serverSideDataCallback]=\"serverSideDataCallback\"\n [infiniteScroll]=\"'auto'\"\n [showSearch]=\"true\"\n [searchText]=\"searchText\"\n [refresh]=\"refresh\"\n (onColumnFilterReset)=\"onColumnFilterReset($event)\"\n >\n <ng-container *ngFor=\"let column of columns; trackBy: trackByName\">\n <c8y-column [name]=\"column.name\"></c8y-column>\n </ng-container>\n\n <c8y-ui-empty-state\n [icon]=\"'search'\"\n [title]=\"'No results to display.' | translate\"\n [subtitle]=\"'Refine your search terms or check your spelling.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n </c8y-data-grid>\n</div>\n", dependencies: [{ kind: "component", type: DataGridComponent, selector: "c8y-data-grid", inputs: ["title", "loadMoreItemsLabel", "loadingItemsLabel", "showSearch", "refresh", "columns", "rows", "pagination", "childNodePagination", "infiniteScroll", "serverSideDataCallback", "selectable", "singleSelection", "selectionPrimaryKey", "displayOptions", "actionControls", "bulkActionControls", "headerActionControls", "searchText", "configureColumnsEnabled", "showCounterWarning", "activeClassName", "expandableRows", "treeGrid", "hideReload", "childNodesProperty", "parentNodeLabelProperty"], outputs: ["rowMouseOver", "rowMouseLeave", "rowClick", "onConfigChange", "onBeforeFilter", "onBeforeSearch", "onFilter", "itemsSelect", "onReload", "onAddCustomColumn", "onRemoveCustomColumn", "onColumnFilterReset", "onSort", "onPageSizeChange", "onColumnReordered", "onColumnVisibilityChange"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: ColumnDirective, selector: "c8y-column", inputs: ["name"] }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
464
722
  }
465
723
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SearchGridComponent, decorators: [{
466
724
  type: Component,
@@ -473,13 +731,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
473
731
  provide: DATA_GRID_CONFIGURATION_CONTEXT_PROVIDER,
474
732
  useExisting: SearchGridComponent
475
733
  }
476
- ], imports: [DataGridComponent, NgFor, ColumnDirective, EmptyStateComponent, C8yTranslatePipe], template: "<div class=\"card--grid--fullpage border-top border-bottom\">\n <c8y-data-grid\n [title]=\"'Search results' | translate\"\n [loadingItemsLabel]=\"loadingItemsLabel\"\n [columns]=\"columns\"\n [pagination]=\"pagination\"\n [actionControls]=\"actionControls\"\n [selectable]=\"selectable\"\n [bulkActionControls]=\"bulkActionControls\"\n [serverSideDataCallback]=\"serverSideDataCallback\"\n [infiniteScroll]=\"'auto'\"\n [showSearch]=\"true\"\n [searchText]=\"searchText\"\n [refresh]=\"refresh\"\n (onColumnFilterReset)=\"onColumnFilterReset($event)\"\n >\n <ng-container *ngFor=\"let column of columns; trackBy: trackByName\">\n <c8y-column [name]=\"column.name\"></c8y-column>\n </ng-container>\n\n <c8y-ui-empty-state\n [icon]=\"'search'\"\n [title]=\"'No results to display.' | translate\"\n [subtitle]=\"'Refine your search terms or check your spelling.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n </c8y-data-grid>\n</div>" }]
477
- }], ctorParameters: () => [{ type: AssetSearchService }, { type: i2$1.BsModalService }, { type: i3.SmartGroupsService }, { type: i4.SubAssetsService }, { type: undefined, decorators: [{
478
- type: Optional
479
- }, {
480
- type: Inject,
481
- args: [SEARCH_CONFIG]
482
- }] }], propDecorators: { parentGroup: [{
734
+ ], imports: [
735
+ DataGridComponent,
736
+ NgFor,
737
+ ColumnDirective,
738
+ EmptyStateComponent,
739
+ C8yTranslatePipe,
740
+ AsyncPipe
741
+ ], template: "<div class=\"card--grid--fullpage border-top border-bottom\">\n <c8y-data-grid\n [title]=\"\n ((isWildcardSearchEnabled$ | async) ? wildcardSearchTitle : fullTextSearchTitle) | translate\n \"\n [loadingItemsLabel]=\"loadingItemsLabel\"\n [columns]=\"columns\"\n [pagination]=\"pagination\"\n [actionControls]=\"actionControls\"\n [selectable]=\"selectable\"\n [bulkActionControls]=\"bulkActionControls\"\n [serverSideDataCallback]=\"serverSideDataCallback\"\n [infiniteScroll]=\"'auto'\"\n [showSearch]=\"true\"\n [searchText]=\"searchText\"\n [refresh]=\"refresh\"\n (onColumnFilterReset)=\"onColumnFilterReset($event)\"\n >\n <ng-container *ngFor=\"let column of columns; trackBy: trackByName\">\n <c8y-column [name]=\"column.name\"></c8y-column>\n </ng-container>\n\n <c8y-ui-empty-state\n [icon]=\"'search'\"\n [title]=\"'No results to display.' | translate\"\n [subtitle]=\"'Refine your search terms or check your spelling.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n </c8y-data-grid>\n</div>\n" }]
742
+ }], propDecorators: { parentGroup: [{
483
743
  type: Input,
484
744
  args: ['parent-group']
485
745
  }], title: [{
@@ -519,6 +779,10 @@ class SearchResultsComponent {
519
779
  this.alert = alert;
520
780
  this.filter = '';
521
781
  this.searchText = '';
782
+ this.previewService = inject(PreviewService);
783
+ this.isWildcardSearchEnabled$ = this.previewService
784
+ .getState$(WILDCARD_SEARCH_FEATURE_KEY)
785
+ .pipe(catchError$1(() => of(true)));
522
786
  this.WARNING_TIMEOUT_TIME = 3000;
523
787
  this.unsubscribe$ = new Subject();
524
788
  }
@@ -583,164 +847,17 @@ class SearchResultsComponent {
583
847
  });
584
848
  return true;
585
849
  }
586
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SearchResultsComponent, deps: [{ token: i1$1.ActivatedRoute }, { token: i2$2.AlertService }], target: i0.ɵɵFactoryTarget.Component }); }
587
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: SearchResultsComponent, isStandalone: true, selector: "c8y-search-results", viewQueries: [{ propertyName: "searchGrid", first: true, predicate: SearchGridComponent, descendants: true, static: true }], ngImport: i0, template: "<c8y-title>\n <span translate class=\"p-r-4\">Search</span>\n <small\n ngNonBindable\n translate\n *ngIf=\"searchText\"\n [translateParams]=\"{\n searchHint: searchText\n }\"\n >searching \"{{ searchHint }}\"</small\n >\n <small\n ngNonBindable\n translate\n *ngIf=\"filter\"\n [translateParams]=\"{\n filterHint: filter\n }\"\n >filtered by \"{{ filterHint }}\"</small\n >\n</c8y-title>\n\n<c8y-search-grid [searchText]=\"searchText\" [filteringName]=\"filteringName\"></c8y-search-grid>\n", dependencies: [{ kind: "component", type: TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: SearchGridComponent, selector: "c8y-search-grid", inputs: ["parent-group", "title", "loadingItemsLabel", "columns", "pagination", "actionControls", "selectable", "bulkActionControls", "searchText", "filteringName", "columnsConfigKey"], outputs: ["onColumnsChange"] }] }); }
850
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SearchResultsComponent, deps: [{ token: i1$1.ActivatedRoute }, { token: i2.AlertService }], target: i0.ɵɵFactoryTarget.Component }); }
851
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: SearchResultsComponent, isStandalone: true, selector: "c8y-search-results", viewQueries: [{ propertyName: "searchGrid", first: true, predicate: SearchGridComponent, descendants: true, static: true }], ngImport: i0, template: "<c8y-title *ngIf=\"isWildcardSearchEnabled$ | async\">\n <span\n class=\"p-r-4\"\n translate\n >\n Search\n </span>\n <small\n ngNonBindable\n translate\n *ngIf=\"searchText\"\n [translateParams]=\"{\n searchHint: searchText\n }\"\n >\n searching \"{{ searchHint }}\"\n </small>\n <small\n ngNonBindable\n translate\n *ngIf=\"filter\"\n [translateParams]=\"{\n filterHint: filter\n }\"\n >\n filtered by \"{{ filterHint }}\"\n </small>\n</c8y-title>\n\n<c8y-title\n *ngIf=\"isWildcardSearchEnabled$ | async\"\n translate\n>\n Asset table\n</c8y-title>\n\n<c8y-search-grid\n [searchText]=\"searchText\"\n [filteringName]=\"filteringName\"\n></c8y-search-grid>\n", dependencies: [{ kind: "component", type: TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: SearchGridComponent, selector: "c8y-search-grid", inputs: ["parent-group", "title", "loadingItemsLabel", "columns", "pagination", "actionControls", "selectable", "bulkActionControls", "searchText", "filteringName", "columnsConfigKey"], outputs: ["onColumnsChange"] }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
588
852
  }
589
853
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SearchResultsComponent, decorators: [{
590
854
  type: Component,
591
- args: [{ selector: 'c8y-search-results', imports: [TitleComponent, C8yTranslateDirective, NgIf, SearchGridComponent], template: "<c8y-title>\n <span translate class=\"p-r-4\">Search</span>\n <small\n ngNonBindable\n translate\n *ngIf=\"searchText\"\n [translateParams]=\"{\n searchHint: searchText\n }\"\n >searching \"{{ searchHint }}\"</small\n >\n <small\n ngNonBindable\n translate\n *ngIf=\"filter\"\n [translateParams]=\"{\n filterHint: filter\n }\"\n >filtered by \"{{ filterHint }}\"</small\n >\n</c8y-title>\n\n<c8y-search-grid [searchText]=\"searchText\" [filteringName]=\"filteringName\"></c8y-search-grid>\n" }]
592
- }], ctorParameters: () => [{ type: i1$1.ActivatedRoute }, { type: i2$2.AlertService }], propDecorators: { searchGrid: [{
855
+ args: [{ selector: 'c8y-search-results', imports: [TitleComponent, C8yTranslateDirective, NgIf, SearchGridComponent, AsyncPipe], template: "<c8y-title *ngIf=\"isWildcardSearchEnabled$ | async\">\n <span\n class=\"p-r-4\"\n translate\n >\n Search\n </span>\n <small\n ngNonBindable\n translate\n *ngIf=\"searchText\"\n [translateParams]=\"{\n searchHint: searchText\n }\"\n >\n searching \"{{ searchHint }}\"\n </small>\n <small\n ngNonBindable\n translate\n *ngIf=\"filter\"\n [translateParams]=\"{\n filterHint: filter\n }\"\n >\n filtered by \"{{ filterHint }}\"\n </small>\n</c8y-title>\n\n<c8y-title\n *ngIf=\"isWildcardSearchEnabled$ | async\"\n translate\n>\n Asset table\n</c8y-title>\n\n<c8y-search-grid\n [searchText]=\"searchText\"\n [filteringName]=\"filteringName\"\n></c8y-search-grid>\n" }]
856
+ }], ctorParameters: () => [{ type: i1$1.ActivatedRoute }, { type: i2.AlertService }], propDecorators: { searchGrid: [{
593
857
  type: ViewChild,
594
858
  args: [SearchGridComponent, { static: true }]
595
859
  }] } });
596
860
 
597
- class SearchCustomFiltersComponent {
598
- constructor(assetSearchService) {
599
- this.assetSearchService = assetSearchService;
600
- this.customDataQuery = new EventEmitter();
601
- this.refresh = new EventEmitter();
602
- this.checkboxesState = [
603
- {
604
- label: gettext('All'),
605
- name: SearchFilters.ALL_FILTERS,
606
- value: true,
607
- indeterminate: false,
608
- isDisabled: true
609
- },
610
- { label: gettext('Show only devices'), name: SearchFilters.ONLY_DEVICES, value: true },
611
- {
612
- label: gettext('Show only groups and assets'),
613
- name: SearchFilters.ONLY_GROUPS_AND_ASSETS,
614
- value: true
615
- }
616
- ];
617
- }
618
- ngOnInit() {
619
- this.customDataQuery.next(this.assetSearchService.getGlobalSearchData);
620
- }
621
- onCheckboxChange(event, checkbox) {
622
- const { checked } = event.target;
623
- if (checked == undefined) {
624
- return;
625
- }
626
- switch (checkbox.name) {
627
- case SearchFilters.ALL_FILTERS:
628
- this.onSelectAll(checkbox, checked);
629
- break;
630
- case SearchFilters.ONLY_DEVICES:
631
- this.onAllDevices(checkbox, checked);
632
- break;
633
- case SearchFilters.ONLY_GROUPS_AND_ASSETS:
634
- this.onGroupsAndAssets(checkbox, checked);
635
- break;
636
- }
637
- // Handle allFilters checkbox when ONLY_GROUPS_AND_ASSETS and ONLY_DEVICES are selected
638
- if (this.getCheckbox(SearchFilters.ONLY_DEVICES).value &&
639
- this.getCheckbox(SearchFilters.ONLY_GROUPS_AND_ASSETS).value) {
640
- Object.assign(this.getCheckbox(SearchFilters.ALL_FILTERS), {
641
- indeterminate: false,
642
- isDisabled: true,
643
- value: true
644
- });
645
- }
646
- this.assetSearchService.appliedFilters$.next({
647
- [SearchFilters.ALL_FILTERS]: this.getCheckbox(SearchFilters.ALL_FILTERS).value,
648
- [SearchFilters.ONLY_DEVICES]: this.getCheckbox(SearchFilters.ONLY_DEVICES).value,
649
- [SearchFilters.ONLY_GROUPS_AND_ASSETS]: this.getCheckbox(SearchFilters.ONLY_GROUPS_AND_ASSETS)
650
- .value
651
- });
652
- this.refresh.next(null);
653
- }
654
- saveCheckboxValue(checkbox, value) {
655
- checkbox.value = value;
656
- }
657
- onSelectAll(currentCheckbox, checked) {
658
- // Block unchecked state
659
- if (checked) {
660
- this.saveCheckboxValue(currentCheckbox, checked);
661
- }
662
- this.getCheckbox(SearchFilters.ALL_FILTERS).isDisabled = true;
663
- this.getCheckbox(SearchFilters.ONLY_DEVICES).value = true;
664
- this.getCheckbox(SearchFilters.ONLY_GROUPS_AND_ASSETS).value = true;
665
- }
666
- onAllDevices(currentCheckbox, checked) {
667
- this.saveCheckboxValue(currentCheckbox, checked);
668
- Object.assign(this.getCheckbox(SearchFilters.ALL_FILTERS), {
669
- indeterminate: true,
670
- isDisabled: false,
671
- value: null
672
- });
673
- this.getCheckbox(SearchFilters.ONLY_GROUPS_AND_ASSETS).value = true;
674
- }
675
- onGroupsAndAssets(currentCheckbox, checked) {
676
- this.saveCheckboxValue(currentCheckbox, checked);
677
- Object.assign(this.getCheckbox(SearchFilters.ALL_FILTERS), {
678
- indeterminate: true,
679
- isDisabled: false,
680
- value: null
681
- });
682
- this.getCheckbox(SearchFilters.ONLY_DEVICES).value = true;
683
- }
684
- getCheckbox(checkboxName) {
685
- return this.checkboxesState.find(checkbox => checkbox.name === checkboxName);
686
- }
687
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SearchCustomFiltersComponent, deps: [{ token: AssetSearchService }], target: i0.ɵɵFactoryTarget.Component }); }
688
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: SearchCustomFiltersComponent, isStandalone: true, selector: "c8y-search-custom-filters", outputs: { customDataQuery: "customDataQuery", refresh: "refresh" }, ngImport: i0, template: "<label class=\"c8y-checkbox\" *ngFor=\"let checkbox of checkboxesState\">\n <input\n type=\"checkbox\"\n [checked]=\"checkbox.value\"\n [indeterminate]=\"checkbox.indeterminate\"\n (click)=\"onCheckboxChange($event, checkbox)\"\n [attr.disabled]=\"checkbox.isDisabled ? true : null\"\n />\n <span></span>\n <span>{{ checkbox.label | translate }}</span>\n</label>\n", dependencies: [{ kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
689
- }
690
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SearchCustomFiltersComponent, decorators: [{
691
- type: Component,
692
- args: [{ selector: 'c8y-search-custom-filters', imports: [NgFor, C8yTranslatePipe], template: "<label class=\"c8y-checkbox\" *ngFor=\"let checkbox of checkboxesState\">\n <input\n type=\"checkbox\"\n [checked]=\"checkbox.value\"\n [indeterminate]=\"checkbox.indeterminate\"\n (click)=\"onCheckboxChange($event, checkbox)\"\n [attr.disabled]=\"checkbox.isDisabled ? true : null\"\n />\n <span></span>\n <span>{{ checkbox.label | translate }}</span>\n</label>\n" }]
693
- }], ctorParameters: () => [{ type: AssetSearchService }], propDecorators: { customDataQuery: [{
694
- type: Output
695
- }], refresh: [{
696
- type: Output
697
- }] } });
698
-
699
- class SearchActionComponent {
700
- constructor(c8yRouter, router, moduleConfig) {
701
- this.c8yRouter = c8yRouter;
702
- this.router = router;
703
- this.moduleConfig = moduleConfig;
704
- this.typeaheadReload = new EventEmitter();
705
- this.showAdvancedFilters = moduleConfig?.showAdvancedFilters ?? true;
706
- this.customPlaceholder = moduleConfig?.placeholder;
707
- }
708
- triggerDataLoad() {
709
- this.typeaheadReload.next(null);
710
- }
711
- onSearch(on) {
712
- this.navigate(['/assetsearch'], {
713
- queryParams: { search: on },
714
- replaceUrl: true
715
- });
716
- }
717
- onFilter(on) {
718
- this.navigate(['/assetsearch'], {
719
- queryParams: { filter: on },
720
- replaceUrl: true
721
- });
722
- }
723
- onClick(mo) {
724
- this.router.navigateByUrl(this.c8yRouter.getHref(mo, '/'));
725
- }
726
- navigate(commands, extras) {
727
- this.router
728
- .navigateByUrl('/', { skipLocationChange: true })
729
- .then(() => this.router.navigate(commands, extras));
730
- }
731
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SearchActionComponent, deps: [{ token: i2$2.RouterService }, { token: i1$1.Router }, { token: SEARCH_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
732
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: SearchActionComponent, isStandalone: true, selector: "c8y-search-action", ngImport: i0, template: "<c8y-search-input\n (filter)=\"onFilter($event)\"\n (search)=\"onSearch($event)\"\n (onClick)=\"onClick($event)\"\n [enableCustomTemplatePlaceholder]=\"true\"\n [customPlaceholder]=\"customPlaceholder\"\n [customDataQuery]=\"customQuery\"\n [externalTerm]=\"typeaheadReload\"\n>\n <c8y-search-custom-filters\n *ngIf=\"showAdvancedFilters\"\n class=\"d-flex gap-16 p-l-4 p-l-24 p-r-24\"\n (refresh)=\"triggerDataLoad()\"\n (customDataQuery)=\"customQuery = $event\"\n ></c8y-search-custom-filters>\n</c8y-search-input>\n", dependencies: [{ kind: "component", type: SearchInputComponent, selector: "c8y-search-input", inputs: ["mode", "enableCustomTemplatePlaceholder", "customPlaceholder", "externalTerm", "customDataQuery", "container", "groupsOnly"], outputs: ["filter", "search", "reset", "onClick"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: SearchCustomFiltersComponent, selector: "c8y-search-custom-filters", outputs: ["customDataQuery", "refresh"] }] }); }
733
- }
734
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SearchActionComponent, decorators: [{
735
- type: Component,
736
- args: [{ selector: 'c8y-search-action', imports: [SearchInputComponent, NgIf, SearchCustomFiltersComponent], template: "<c8y-search-input\n (filter)=\"onFilter($event)\"\n (search)=\"onSearch($event)\"\n (onClick)=\"onClick($event)\"\n [enableCustomTemplatePlaceholder]=\"true\"\n [customPlaceholder]=\"customPlaceholder\"\n [customDataQuery]=\"customQuery\"\n [externalTerm]=\"typeaheadReload\"\n>\n <c8y-search-custom-filters\n *ngIf=\"showAdvancedFilters\"\n class=\"d-flex gap-16 p-l-4 p-l-24 p-r-24\"\n (refresh)=\"triggerDataLoad()\"\n (customDataQuery)=\"customQuery = $event\"\n ></c8y-search-custom-filters>\n</c8y-search-input>\n" }]
737
- }], ctorParameters: () => [{ type: i2$2.RouterService }, { type: i1$1.Router }, { type: undefined, decorators: [{
738
- type: Optional
739
- }, {
740
- type: Inject,
741
- args: [SEARCH_CONFIG]
742
- }] }] });
743
-
744
861
  class SearchModule {
745
862
  static config(config = {}) {
746
863
  return {
@@ -778,7 +895,8 @@ class SearchModule {
778
895
  AssetTypeCellRendererComponent,
779
896
  SearchResultsComponent,
780
897
  SearchGridComponent,
781
- SearchActionComponent] }); }
898
+ SearchActionComponent,
899
+ SearchCustomFiltersComponent] }); }
782
900
  }
783
901
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SearchModule, decorators: [{
784
902
  type: NgModule,