From 9760da5bbbc1eb34645edd613dc4170b20044d4f Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Thu, 9 Apr 2026 17:54:01 +0300 Subject: [PATCH] feat(iot-hub): add Vendor filter for Device Library browse Add Vendor as the first filter for DEVICE type in browse page: - Text input with debounced search (400ms) - Clear button when filter is active - Passes vendor param to IoT Hub API query - Included in filter count and clearAllFilters - Positioned above Hardware Type and Connectivity filters --- .../iot-hub/iot-hub-browse.component.html | 17 +++++++++++ .../iot-hub/iot-hub-browse.component.scss | 5 ++++ .../iot-hub/iot-hub-browse.component.ts | 28 +++++++++++++++++-- .../assets/locale/locale.constant-en_US.json | 2 ++ 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.html b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.html index d8c67197f4..921ea238f5 100644 --- a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.html +++ b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.html @@ -72,6 +72,23 @@ @if (!fixedSubType && getSubtypeMap()) {
} + + + {{ 'iot-hub.vendor' | translate }} + + + + @if (vendorFilter) { + + } + + +
{{ 'iot-hub.hardware-type' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.scss b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.scss index 56730ec3a6..b9b1076f72 100644 --- a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.scss +++ b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.scss @@ -197,6 +197,11 @@ } } + .tb-vendor-filter-field { + width: 100%; + margin-top: 4px; + } + .tb-iot-hub-filter-group-label { font-size: 12px; font-weight: 500; diff --git a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.ts b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.ts index 6a2aba27cc..fd7be964a3 100644 --- a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.ts +++ b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.ts @@ -96,6 +96,8 @@ export class TbIotHubBrowseComponent implements OnInit, OnDestroy { activeRuleChainTypes = new Set(); activeConnectivity = new Set(); activeHardwareTypes = new Set(); + vendorFilter = ''; + private vendorDebounceTimer: any; sortOptions: SortOption[] = [ { value: 'totalInstallCount', label: 'iot-hub.sort-most-installed', direction: Direction.DESC }, @@ -181,6 +183,7 @@ export class TbIotHubBrowseComponent implements OnInit, OnDestroy { this.activeRuleChainTypes.clear(); this.activeConnectivity.clear(); this.activeHardwareTypes.clear(); + this.vendorFilter = ''; this.updateCategories(); this.pageIndex = 0; if (type === ItemType.WIDGET) { @@ -319,6 +322,22 @@ export class TbIotHubBrowseComponent implements OnInit, OnDestroy { return this.activeHardwareTypes.has(value); } + onVendorInput(event: Event): void { + const value = (event.target as HTMLInputElement).value?.trim() || ''; + this.vendorFilter = value; + clearTimeout(this.vendorDebounceTimer); + this.vendorDebounceTimer = setTimeout(() => { + this.pageIndex = 0; + this.loadItems(); + }, 400); + } + + clearVendorFilter(): void { + this.vendorFilter = ''; + this.pageIndex = 0; + this.loadItems(); + } + getActiveConnectivityArray(): string[] { return Array.from(this.activeConnectivity); } @@ -423,6 +442,7 @@ export class TbIotHubBrowseComponent implements OnInit, OnDestroy { this.activeRuleChainTypes.clear(); this.activeConnectivity.clear(); this.activeHardwareTypes.clear(); + this.vendorFilter = ''; if (this.fixedSubType) { this.getActiveSubtypes()?.add(this.fixedSubType); } @@ -435,14 +455,15 @@ export class TbIotHubBrowseComponent implements OnInit, OnDestroy { get activeFilterCount(): number { const subtypeCount = this.fixedSubType ? this.getActiveSubtypesArray().length : (this.getActiveSubtypes()?.size || 0); return subtypeCount + this.activeCategories.size + this.activeUseCases.size + - this.activeConnectivity.size + this.activeHardwareTypes.size; + this.activeConnectivity.size + this.activeHardwareTypes.size + (this.vendorFilter ? 1 : 0); } hasActiveDropdownFilters(): boolean { const subtypeCount = this.fixedSubType ? this.getActiveSubtypesArray().length : (this.getActiveSubtypes()?.size || 0); return this.activeCategories.size > 0 || this.activeUseCases.size > 0 || subtypeCount > 0 || - this.activeConnectivity.size > 0 || this.activeHardwareTypes.size > 0; + this.activeConnectivity.size > 0 || this.activeHardwareTypes.size > 0 || + !!this.vendorFilter; } hasActiveFilters(): boolean { @@ -600,7 +621,8 @@ export class TbIotHubBrowseComponent implements OnInit, OnDestroy { this.activeRuleChainTypes.size > 0 ? Array.from(this.activeRuleChainTypes) : undefined, undefined, this.activeHardwareTypes.size > 0 ? Array.from(this.activeHardwareTypes) : undefined, - this.activeConnectivity.size > 0 ? Array.from(this.activeConnectivity) : undefined + this.activeConnectivity.size > 0 ? Array.from(this.activeConnectivity) : undefined, + this.vendorFilter || undefined ); this.iotHubApiService.getPublishedVersions( query, diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 3282836af5..ad0074f20b 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -3758,6 +3758,8 @@ "type-filter-label": "Type", "category": "Category", "use-case": "Use case", + "vendor": "Vendor", + "vendor-placeholder": "Filter by vendor...", "hardware-type": "Hardware Type", "connectivity": "Connectivity", "clear-all-filters": "Clear all filters",