@@ -47,6 +47,7 @@ import { MatButton, MatIconButton } from '@angular/material/button'
4747import { MatToolbar } from '@angular/material/toolbar'
4848import { MatSort } from '@angular/material/sort'
4949import { MatInput } from '@angular/material/input'
50+ import { MatTabGroup , MatTab } from '@angular/material/tabs'
5051import { TranslatePipe , TranslateService } from '@ngx-translate/core'
5152
5253@Component ( {
@@ -86,6 +87,8 @@ import { TranslatePipe, TranslateService } from '@ngx-translate/core'
8687 MatPaginator ,
8788 MatHint ,
8889 RouterModule ,
90+ MatTabGroup ,
91+ MatTab ,
8992 TranslatePipe
9093 ]
9194} )
@@ -108,6 +111,46 @@ export class DevicesComponent implements OnInit, AfterViewInit {
108111 public powerStates : any
109112 public isCloudMode : boolean = environment . cloud
110113
114+ public activeTab = signal ( 0 )
115+ public allDevicesData : Device [ ] = [ ]
116+ private serverTotalCount = 0
117+
118+ get activatedCount ( ) : number {
119+ return this . allDevicesData . filter (
120+ ( d ) => d . deviceInfo ?. currentMode != null && d . deviceInfo . currentMode !== 'not activated'
121+ ) . length
122+ }
123+
124+ get discoveredCount ( ) : number {
125+ return this . allDevicesData . filter ( ( d ) => d . deviceInfo ?. discovered === true ) . length
126+ }
127+
128+ onTabChange ( index : number ) : void {
129+ this . activeTab . set ( index )
130+ this . applyTabFilter ( )
131+ }
132+
133+ private applyTabFilter ( ) : void {
134+ let filtered : Device [ ]
135+ switch ( this . activeTab ( ) ) {
136+ case 1 :
137+ filtered = this . allDevicesData . filter (
138+ ( d ) => d . deviceInfo ?. currentMode != null && d . deviceInfo . currentMode !== 'not activated'
139+ )
140+ this . totalCount . set ( filtered . length )
141+ break
142+ case 2 :
143+ filtered = this . allDevicesData . filter ( ( d ) => d . deviceInfo ?. discovered === true )
144+ this . totalCount . set ( filtered . length )
145+ break
146+ default :
147+ filtered = this . allDevicesData
148+ this . totalCount . set ( this . serverTotalCount )
149+ break
150+ }
151+ this . devices . data = filtered
152+ }
153+
111154 get deleteDeviceLabel ( ) : string {
112155 return this . isCloudMode
113156 ? this . translate . instant ( 'devices.actions.deactivateCloud.value' )
@@ -119,6 +162,7 @@ export class DevicesComponent implements OnInit, AfterViewInit {
119162 'hostname' ,
120163 'guid' ,
121164 'status' ,
165+ 'productType' ,
122166 'tags' ,
123167 'actions' ,
124168 'notification'
@@ -140,6 +184,7 @@ export class DevicesComponent implements OnInit, AfterViewInit {
140184 this . displayedColumns = [
141185 'select' ,
142186 'hostname' ,
187+ 'productType' ,
143188 'tags' ,
144189 'actions' ,
145190 'notification'
@@ -211,6 +256,7 @@ export class DevicesComponent implements OnInit, AfterViewInit {
211256 . pipe (
212257 switchMap ( ( res ) => {
213258 this . totalCount . set ( res . totalCount )
259+ this . serverTotalCount = res . totalCount
214260
215261 if ( ! environment . cloud ) {
216262 return of ( res . data ) // Return as-is for non-cloud
@@ -251,7 +297,8 @@ export class DevicesComponent implements OnInit, AfterViewInit {
251297 } )
252298 )
253299 . subscribe ( ( devices ) => {
254- this . devices . data = devices
300+ this . allDevicesData = devices
301+ this . applyTabFilter ( )
255302
256303 // Restore selection state on data retrieval
257304 this . selectedDevices . clear ( )
@@ -342,6 +389,16 @@ export class DevicesComponent implements OnInit, AfterViewInit {
342389 await this . router . navigate ( [ `/devices/${ path } ` ] )
343390 }
344391
392+ getProductType ( device : Device ) : string {
393+ const skuNum = parseInt ( device . deviceInfo ?. fwSku ?? '' , 10 )
394+ if ( isNaN ( skuNum ) ) return ''
395+ const isISM = ( skuNum & 0x10 ) > 0
396+ const isVPro = ( skuNum & 0x08 ) > 0
397+ if ( isISM ) return 'ISM'
398+ if ( isVPro ) return 'vPro'
399+ return ''
400+ }
401+
345402 translateConnectionStatus ( status ?: boolean ) : string {
346403 switch ( status ) {
347404 case false :
0 commit comments