@ -54,95 +54,216 @@
<!-- Filter panel template (reused in sidebar and drawer) -->
<!-- Filter panel template (reused in sidebar and drawer) -->
< ng-template # filterPanelContent >
< ng-template # filterPanelContent >
< div class = "tb-iot-hub-filters-inner" >
< div class = "tb-iot-hub-filters-inner" >
@if (!fixedSubType & & getSubtypeMap(); as subtypeMap ) {
@if (!fixedSubType & & subtypeOptions.length > 0 ) {
< mat-expansion-panel [ expanded ] = " true " class = "tb-iot-hub-filter-panel" >
< mat-expansion-panel [ expanded ] = " true " class = "tb-iot-hub-filter-panel" >
< mat-expansion-panel-header >
< mat-expansion-panel-header >
< mat-panel-title > {{ 'iot-hub.type-filter-label' | translate }}< / mat-panel-title >
< mat-panel-title > {{ 'iot-hub.type-filter-label' | translate }}< / mat-panel-title >
< / mat-expansion-panel-header >
< / mat-expansion-panel-header >
@for (entry of subtypeMap | keyvalue; track entry.key) {
@if (subtypeOptions.length >= 10) {
< mat-checkbox [ checked ] = " isSubtypeActive ( entry . key ) "
< div class = "tb-iot-hub-filter-search" >
(change)="onSubtypeToggle(entry.key)">
< mat-icon > search< / mat-icon >
{{ entry.value | translate }}
< input [ placeholder ] = " ' iot-hub . search ' | translate "
< / mat-checkbox >
[ngModel]="filterSearch['subtype']"
(ngModelChange)="filterSearch['subtype'] = $event">
@if (filterSearch['subtype']) {
< button mat-icon-button class = "tb-iot-hub-filter-search-clear" ( click ) = " filterSearch [ ' subtype ' ] = ' ' " >
< mat-icon > close< / mat-icon >
< / button >
}
< / div >
}
}
< div class = "tb-iot-hub-filter-items" [ class . scrollable ] = " getFilteredItems ( subtypeOptions , ' subtype ' ) . length > 8"
(mouseenter)="getFilteredItems(subtypeOptions, 'subtype').length > 8 & & (filterItemsHovered = true)"
(mouseleave)="filterItemsHovered = false">
@for (opt of getFilteredItems(subtypeOptions, 'subtype'); track opt.key) {
< mat-checkbox [ checked ] = " isSubtypeActive ( opt . key ) "
(change)="onSubtypeToggle(opt.key)">
{{ getSubtypeLabel(opt.key) }}
< / mat-checkbox >
}
< / div >
< / mat-expansion-panel >
< / mat-expansion-panel >
}
}
@if (activeType === ItemType.DEVICE) {
@if (activeType === ItemType.DEVICE) {
@if (!fixedSubType & & getSubtypeMap()) {
@if (!fixedSubType & & subtypeOptions.length > 0 ) {
< div class = "tb-iot-hub-filter-divider" > < / div >
< div class = "tb-iot-hub-filter-divider" > < / div >
}
}
< mat-expansion-panel [ expanded ] = " true " class = "tb-iot-hub-filter-panel" >
@if (vendorOptions.length > 0) {
< mat-expansion-panel-header >
< mat-expansion-panel [ expanded ] = " true " class = "tb-iot-hub-filter-panel" >
< mat-panel-title > {{ 'iot-hub.vendor' | translate }}< / mat-panel-title >
< mat-expansion-panel-header >
< / mat-expansion-panel-header >
< mat-panel-title > {{ 'iot-hub.vendor' | translate }}< / mat-panel-title >
@for (v of availableVendors; track v) {
< / mat-expansion-panel-header >
< mat-checkbox [ checked ] = " isVendorActive ( v ) "
@if (vendorOptions.length >= 10) {
(change)="onVendorToggle(v)">
< div class = "tb-iot-hub-filter-search" >
{{ v }}
< mat-icon > search< / mat-icon >
< / mat-checkbox >
< input [ placeholder ] = " ' iot-hub . search ' | translate "
}
[ngModel]="filterSearch['vendor']"
< / mat-expansion-panel >
(ngModelChange)="filterSearch['vendor'] = $event">
< div class = "tb-iot-hub-filter-divider" > < / div >
@if (filterSearch['vendor']) {
< mat-expansion-panel [ expanded ] = " true " class = "tb-iot-hub-filter-panel" >
< button mat-icon-button class = "tb-iot-hub-filter-search-clear" ( click ) = " filterSearch [ ' vendor ' ] = ' ' " >
< mat-expansion-panel-header >
< mat-icon > close< / mat-icon >
< mat-panel-title > {{ 'iot-hub.hardware-type' | translate }}< / mat-panel-title >
< / button >
< / mat-expansion-panel-header >
}
@for (ht of hardwareTypes; track ht) {
< / div >
< mat-checkbox [ checked ] = " isHardwareTypeActive ( ht ) "
(change)="onHardwareTypeToggle(ht)">
{{ ht }}
< / mat-checkbox >
}
< / mat-expansion-panel >
< div class = "tb-iot-hub-filter-divider" > < / div >
< mat-expansion-panel [ expanded ] = " false " class = "tb-iot-hub-filter-panel" >
< mat-expansion-panel-header >
< mat-panel-title > {{ 'iot-hub.connectivity' | translate }}< / mat-panel-title >
< / mat-expansion-panel-header >
@for (group of connectivityGroups; track group.label) {
< div class = "tb-iot-hub-filter-group-label" > {{ group.label }}< / div >
@for (val of group.values; track val) {
< mat-checkbox [ checked ] = " isConnectivityActive ( val ) "
(change)="onConnectivityToggle(val)">
{{ val }}
< / mat-checkbox >
}
}
}
< div class = "tb-iot-hub-filter-items" [ class . scrollable ] = " getFilteredItems ( vendorOptions , ' vendor ' ) . length > 8"
< / mat-expansion-panel >
(mouseenter)="getFilteredItems(vendorOptions, 'vendor').length > 8 & & (filterItemsHovered = true)"
(mouseleave)="filterItemsHovered = false">
@for (group of getGroupedFilterItems(vendorOptions, 'vendor'); track group.label) {
@if (group.label) {
< div class = "tb-iot-hub-filter-group-label" > {{ group.label | translate }}< / div >
}
@for (v of group.items; track v.key) {
< mat-checkbox [ checked ] = " isVendorActive ( v . key ) "
(change)="onVendorToggle(v.key)">
{{ v.key }}
< / mat-checkbox >
}
}
< / div >
< / mat-expansion-panel >
< div class = "tb-iot-hub-filter-divider" > < / div >
}
@if (hardwareTypeOptions.length > 0) {
< mat-expansion-panel [ expanded ] = " true " class = "tb-iot-hub-filter-panel" >
< mat-expansion-panel-header >
< mat-panel-title > {{ 'iot-hub.hardware-type' | translate }}< / mat-panel-title >
< / mat-expansion-panel-header >
@if (hardwareTypeOptions.length >= 10) {
< div class = "tb-iot-hub-filter-search" >
< mat-icon > search< / mat-icon >
< input [ placeholder ] = " ' iot-hub . search ' | translate "
[ngModel]="filterSearch['hardwareType']"
(ngModelChange)="filterSearch['hardwareType'] = $event">
@if (filterSearch['hardwareType']) {
< button mat-icon-button class = "tb-iot-hub-filter-search-clear" ( click ) = " filterSearch [ ' hardwareType ' ] = ' ' " >
< mat-icon > close< / mat-icon >
< / button >
}
< / div >
}
< div class = "tb-iot-hub-filter-items" [ class . scrollable ] = " getFilteredItems ( hardwareTypeOptions , ' hardwareType ' ) . length > 8"
(mouseenter)="getFilteredItems(hardwareTypeOptions, 'hardwareType').length > 8 & & (filterItemsHovered = true)"
(mouseleave)="filterItemsHovered = false">
@for (ht of getFilteredItems(hardwareTypeOptions, 'hardwareType'); track ht.key) {
< mat-checkbox [ checked ] = " isHardwareTypeActive ( ht . key ) "
(change)="onHardwareTypeToggle(ht.key)">
{{ ht.key }}
< / mat-checkbox >
}
< / div >
< / mat-expansion-panel >
< div class = "tb-iot-hub-filter-divider" > < / div >
}
@if (connectivityGroups.length > 0) {
< mat-expansion-panel [ expanded ] = " false " class = "tb-iot-hub-filter-panel" >
< mat-expansion-panel-header >
< mat-panel-title > {{ 'iot-hub.connectivity' | translate }}< / mat-panel-title >
< / mat-expansion-panel-header >
@if (allConnectivityCount >= 10) {
< div class = "tb-iot-hub-filter-search" >
< mat-icon > search< / mat-icon >
< input [ placeholder ] = " ' iot-hub . search ' | translate "
[ngModel]="filterSearch['connectivity']"
(ngModelChange)="filterSearch['connectivity'] = $event">
@if (filterSearch['connectivity']) {
< button mat-icon-button class = "tb-iot-hub-filter-search-clear" ( click ) = " filterSearch [ ' connectivity ' ] = ' ' " >
< mat-icon > close< / mat-icon >
< / button >
}
< / div >
}
< div class = "tb-iot-hub-filter-items" [ class . scrollable ] = " allConnectivityCount > 8"
(mouseenter)="allConnectivityCount > 8 & & (filterItemsHovered = true)"
(mouseleave)="filterItemsHovered = false">
@for (group of getFilteredConnectivityGroups('connectivity'); track group.group) {
< div class = "tb-iot-hub-filter-group-label" > {{ group.group }}< / div >
@for (val of group.values; track val.key) {
< mat-checkbox [ checked ] = " isConnectivityActive ( val . key ) "
(change)="onConnectivityToggle(val.key)">
{{ val.key }}
< / mat-checkbox >
}
}
< / div >
< / mat-expansion-panel >
}
} @else {
} @else {
@if (categories.size > 0) {
@if (categoryOptions.length > 0) {
@if (!fixedSubType & & getSubtypeMap()) {
@if (!fixedSubType & & subtypeOptions.length > 0 ) {
< div class = "tb-iot-hub-filter-divider" > < / div >
< div class = "tb-iot-hub-filter-divider" > < / div >
}
}
< mat-expansion-panel [ expanded ] = " true " class = "tb-iot-hub-filter-panel" >
< mat-expansion-panel [ expanded ] = " true " class = "tb-iot-hub-filter-panel" >
< mat-expansion-panel-header >
< mat-expansion-panel-header >
< mat-panel-title > {{ 'iot-hub.category' | translate }}< / mat-panel-title >
< mat-panel-title > {{ 'iot-hub.category' | translate }}< / mat-panel-title >
< / mat-expansion-panel-header >
< / mat-expansion-panel-header >
@for (entry of categories | keyvalue; track entry.key) {
@if (categoryOptions.length >= 10) {
< mat-checkbox [ checked ] = " isCategoryActive ( entry . key ) "
< div class = "tb-iot-hub-filter-search" >
(change)="onCategoryToggle(entry.key)">
< mat-icon > search< / mat-icon >
{{ entry.value | translate }}
< input [ placeholder ] = " ' iot-hub . search ' | translate "
< / mat-checkbox >
[ngModel]="filterSearch['category']"
(ngModelChange)="filterSearch['category'] = $event">
@if (filterSearch['category']) {
< button mat-icon-button class = "tb-iot-hub-filter-search-clear" ( click ) = " filterSearch [ ' category ' ] = ' ' " >
< mat-icon > close< / mat-icon >
< / button >
}
< / div >
}
}
< div class = "tb-iot-hub-filter-items" [ class . scrollable ] = " getFilteredItems ( categoryOptions , ' category ' ) . length > 8"
(mouseenter)="getFilteredItems(categoryOptions, 'category').length > 8 & & (filterItemsHovered = true)"
(mouseleave)="filterItemsHovered = false">
@for (cat of getFilteredItems(categoryOptions, 'category'); track cat.key) {
< mat-checkbox [ checked ] = " isCategoryActive ( cat . key ) "
(change)="onCategoryToggle(cat.key)">
{{ cat.key }}
< / mat-checkbox >
}
< / div >
< / mat-expansion-panel >
< / mat-expansion-panel >
}
}
}
}
@if (activeType === ItemType.DEVICE || (!fixedSubType & & getSubtypeMap()) || categories.size > 0) {
@if (useCaseOptions.length > 0) {
@if (activeType === ItemType.DEVICE || (!fixedSubType & & subtypeOptions.length > 0) || categoryOptions.length > 0) {
< div class = "tb-iot-hub-filter-divider" > < / div >
}
< mat-expansion-panel [ expanded ] = " false " class = "tb-iot-hub-filter-panel" >
< mat-expansion-panel-header >
< mat-panel-title > {{ 'iot-hub.use-case' | translate }}< / mat-panel-title >
< / mat-expansion-panel-header >
@if (useCaseOptions.length >= 10) {
< div class = "tb-iot-hub-filter-search" >
< mat-icon > search< / mat-icon >
< input [ placeholder ] = " ' iot-hub . search ' | translate "
[ngModel]="filterSearch['useCase']"
(ngModelChange)="filterSearch['useCase'] = $event">
@if (filterSearch['useCase']) {
< button mat-icon-button class = "tb-iot-hub-filter-search-clear" ( click ) = " filterSearch [ ' useCase ' ] = ' ' " >
< mat-icon > close< / mat-icon >
< / button >
}
< / div >
}
< div class = "tb-iot-hub-filter-items" [ class . scrollable ] = " getFilteredItems ( useCaseOptions , ' useCase ' ) . length > 8"
(mouseenter)="getFilteredItems(useCaseOptions, 'useCase').length > 8 & & (filterItemsHovered = true)"
(mouseleave)="filterItemsHovered = false">
@for (group of getGroupedFilterItems(useCaseOptions, 'useCase'); track group.label) {
@if (group.label) {
< div class = "tb-iot-hub-filter-group-label" > {{ group.label | translate }}< / div >
}
@for (uc of group.items; track uc.key) {
< mat-checkbox [ checked ] = " isUseCaseActive ( uc . key ) "
(change)="onUseCaseToggle(uc.key)">
{{ uc.key }}
< / mat-checkbox >
}
}
< / div >
< / mat-expansion-panel >
< div class = "tb-iot-hub-filter-divider" > < / div >
< div class = "tb-iot-hub-filter-divider" > < / div >
}
}
< mat-expansion-panel [ expanded ] = " false " class = "tb-iot-hub-filter-panel" >
< mat-expansion-panel-header >
< mat-panel-title > {{ 'iot-hub.use-case' | translate }}< / mat-panel-title >
< / mat-expansion-panel-header >
@for (uc of useCaseValues; track uc) {
< mat-checkbox [ checked ] = " isUseCaseActive ( uc ) "
(change)="onUseCaseToggle(uc)">
{{ uc }}
< / mat-checkbox >
}
< / mat-expansion-panel >
< / div >
< / div >
< / ng-template >
< / ng-template >
@ -169,7 +290,7 @@
}
}
@for (key of getActiveCategoriesArray(); track key) {
@for (key of getActiveCategoriesArray(); track key) {
< mat-chip ( removed ) = " onCategoryToggle ( key ) " >
< mat-chip ( removed ) = " onCategoryToggle ( key ) " >
{{ getCategoryLabel( key) }}
{{ key }}
< mat-icon matChipRemove > close< / mat-icon >
< mat-icon matChipRemove > close< / mat-icon >
< / mat-chip >
< / mat-chip >
}
}
@ -193,7 +314,7 @@
}
}
@for (key of getActiveUseCasesArray(); track key) {
@for (key of getActiveUseCasesArray(); track key) {
< mat-chip ( removed ) = " onUseCaseToggle ( key ) " >
< mat-chip ( removed ) = " onUseCaseToggle ( key ) " >
{{ getUseCaseLabel( key) }}
{{ key }}
< mat-icon matChipRemove > close< / mat-icon >
< mat-icon matChipRemove > close< / mat-icon >
< / mat-chip >
< / mat-chip >
}
}
@ -204,7 +325,7 @@
< / div >
< / div >
}
}
< div class = "tb-iot-hub-filter-divider" > < / div >
< div class = "tb-iot-hub-filter-divider" > < / div >
< div class = "tb-iot-hub-filter-drawer-body" >
< div class = "tb-iot-hub-filter-drawer-body" [ class . filter-items-hovered ] = " filterItemsHovered " >
< ng-container * ngTemplateOutlet = "filterPanelContent" > < / ng-container >
< ng-container * ngTemplateOutlet = "filterPanelContent" > < / ng-container >
< / div >
< / div >
< / mat-drawer >
< / mat-drawer >
@ -212,7 +333,7 @@
< mat-drawer-content class = "tb-iot-hub-drawer-content" >
< mat-drawer-content class = "tb-iot-hub-drawer-content" >
<!-- Left sidebar filters (visible on large screens) -->
<!-- Left sidebar filters (visible on large screens) -->
< div class = "tb-iot-hub-filters tb-iot-hub-filters-desktop" >
< div class = "tb-iot-hub-filters tb-iot-hub-filters-desktop" >
< div class = "tb-iot-hub-filters-wrapper" >
< div class = "tb-iot-hub-filters-wrapper" [ class . filter-items-hovered ] = " filterItemsHovered " >
< ng-container * ngTemplateOutlet = "filterPanelContent" > < / ng-container >
< ng-container * ngTemplateOutlet = "filterPanelContent" > < / ng-container >
< / div >
< / div >
< / div >
< / div >
@ -259,7 +380,7 @@
}
}
@for (key of getActiveCategoriesArray(); track key) {
@for (key of getActiveCategoriesArray(); track key) {
< mat-chip ( removed ) = " onCategoryToggle ( key ) " >
< mat-chip ( removed ) = " onCategoryToggle ( key ) " >
{{ getCategoryLabel( key) }}
{{ key }}
< mat-icon matChipRemove > close< / mat-icon >
< mat-icon matChipRemove > close< / mat-icon >
< / mat-chip >
< / mat-chip >
}
}
@ -283,7 +404,7 @@
}
}
@for (key of getActiveUseCasesArray(); track key) {
@for (key of getActiveUseCasesArray(); track key) {
< mat-chip ( removed ) = " onUseCaseToggle ( key ) " >
< mat-chip ( removed ) = " onUseCaseToggle ( key ) " >
{{ getUseCaseLabel( key) }}
{{ key }}
< mat-icon matChipRemove > close< / mat-icon >
< mat-icon matChipRemove > close< / mat-icon >
< / mat-chip >
< / mat-chip >
}
}