@ -15,141 +15,171 @@
limitations under the License.
-->
< div class = "tb-iot-hub-installed-items-container" >
< a class = "tb-iot-hub-back-link" ( click ) = " navigateToMarketplace ( ) " >
< mat-icon > arrow_back< / mat-icon >
{{ 'iot-hub.back-to-marketplace' | translate }}
< / a >
< div class = "tb-iot-hub-installed-items-header" >
< h2 > {{ 'iot-hub.installed-items' | translate }}< / h2 >
@if (!updatesChecked) {
< button mat-flat-button color = "primary"
[disabled]="isCheckingUpdates"
(click)="checkForUpdates()">
@if (isCheckingUpdates) {
< mat-spinner diameter = "18" class = "tb-iot-hub-inline-spinner" > < / mat-spinner >
} @else {
< mat-icon > update< / mat-icon >
}
{{ 'iot-hub.check-for-updates' | translate }}
< / button >
}
< div class = "tb-installed-items-page" >
<!-- Back link -->
< button mat-button color = "primary" class = "tb-installed-back-btn" ( click ) = " navigateToMarketplace ( ) " >
< mat-icon > chevron_left< / mat-icon >
{{ 'iot-hub.back-to-iot-hub' | translate }}
< / button >
<!-- Header -->
< div class = "tb-installed-header" >
< h1 class = "tb-installed-title" > {{ 'iot-hub.installed-items' | translate }}< / h1 >
< button mat-flat-button color = "primary" ( click ) = " checkForUpdates ( ) " [ disabled ] = " isCheckingUpdates " >
@if (isCheckingUpdates) {
< mat-spinner diameter = "18" > < / mat-spinner >
} @else {
< mat-icon > sync< / mat-icon >
}
{{ 'iot-hub.check-for-updates' | translate }}
< / button >
< / div >
< div class = "tb-iot-hub-installed-search-row" >
< mat-form-field appearance = "outline" class = "tb-iot-hub-installed-search-field" >
< mat-icon matPrefix > search< / mat-icon >
< input matInput
[placeholder]="'iot-hub.search-installed-items' | translate"
[value]="textSearch"
(input)="onSearchChange($any($event.target).value)">
@if (textSearch) {
< button matSuffix mat-icon-button ( click ) = " onSearchChange ( ' ' ) " >
< mat-icon > close< / mat-icon >
<!-- Filter + Search row -->
< div class = "tb-installed-toolbar" >
< div class = "tb-installed-filter-area" >
< button mat-stroked-button color = "primary" class = "tb-installed-filter-btn" ( click ) = " toggleFilter ( ) " >
< mat-icon > filter_list< / mat-icon >
{{ 'iot-hub.filter' | translate }}
< / button >
@if (hasActiveFilters()) {
< mat-chip-set class = "tb-installed-filter-chips" >
@for (type of activeTypeFilters; track type) {
< mat-chip ( removed ) = " removeTypeFilter ( type ) " >
{{ getItemTypeLabel(type) }}
< mat-icon matChipRemove > close< / mat-icon >
< / mat-chip >
}
< / mat-chip-set >
< button class = "tb-installed-clear-btn" ( click ) = " clearAllFilters ( ) " >
{{ 'iot-hub.clear-all' | translate }}
< / button >
}
< / mat-form-field >
< / div >
< div class = "tb-installed-search" >
< mat-icon class = "tb-installed-search-icon" > search< / mat-icon >
< input class = "tb-installed-search-input"
[placeholder]="'iot-hub.search' | translate"
[value]="textSearch"
(input)="onSearchChange($any($event.target).value)">
< / div >
< / div >
< div class = "tb-iot-hub-installed-table-container" >
@if (isLoading) {
< mat-progress-bar mode = "indeterminate" > < / mat-progress-bar >
}
<!-- Filter dropdown -->
@if (filterOpen) {
< div class = "tb-installed-filter-dropdown" >
@for (type of allItemTypes; track type) {
< mat-checkbox [ checked ] = " isTypeFilterActive ( type ) " ( change ) = " toggleTypeFilter ( type ) " >
{{ getItemTypeLabel(type) }}
< / mat-checkbox >
}
< / div >
}
< table mat-table [ dataSource ] = " dataSource " matSort >
<!-- Table -->
< div class = "tb-installed-table-container" >
< table mat-table [ dataSource ] = " dataSource " matSort matSortActive = "createdTime" matSortDirection = "desc" >
<!-- Name -->
< ng-container matColumnDef = "itemName" >
< th mat-header-cell * matHeaderCellDef mat-sort-header > {{ 'iot-hub.item-name' | translate }}< / th >
< td mat-cell * matCellDef = "let item" > {{ item.itemName }}< / td >
< / ng-container >
<!-- Type -->
< ng-container matColumnDef = "itemType" >
< th mat-header-cell * matHeaderCellDef mat-sort-header > {{ 'iot-hub.item-type' | translate }}< / th >
< th mat-header-cell * matHeaderCellDef > {{ 'iot-hub.item-type' | translate }}< / th >
< td mat-cell * matCellDef = "let item" >
< span class = "tb-iot-hub-type-chip" [ ngClass ] = " getItemTypeChipClass ( item . itemType ) " > {{ getItemTypeLabel(item.itemType) }}< / span >
< span class = "tb-installed-type" [ ngClass ] = " getItemTypeChipClass ( item . itemType ) " >
< mat-icon class = "tb-installed-type-icon" > {{ getItemTypeIcon(item.itemType) }}< / mat-icon >
{{ getItemTypeLabel(item.itemType) }}
< / span >
< / td >
< / ng-container >
<!-- Version -->
< ng-container matColumnDef = "version" >
< th mat-header-cell * matHeaderCellDef mat-sort-header > {{ 'iot-hub.item-version' | translate }}< / th >
< th mat-header-cell * matHeaderCellDef > {{ 'iot-hub.item-version' | translate }}< / th >
< td mat-cell * matCellDef = "let item" > {{ item.version }}< / td >
< / ng-container >
<!-- Installed date -->
< ng-container matColumnDef = "createdTime" >
< th mat-header-cell * matHeaderCellDef mat-sort-header > {{ 'iot-hub.installed-date' | translate }}< / th >
< td mat-cell * matCellDef = "let item" > {{ item.createdTime | date:'mediumDate' }}< / td >
< / ng-container >
<!-- Updates -->
< ng-container matColumnDef = "updates" >
< th mat-header-cell * matHeaderCellDef > {{ updatesChecked ? ( 'iot-hub.updates' | translate) : '' }}< / th >
< th mat-header-cell * matHeaderCellDef > {{ 'iot-hub.updates' | translate }}< / th >
< td mat-cell * matCellDef = "let item" >
@if (updatesChecked) {
@if (getPublishedVersionInfo(item); as publishedInfo) {
@if (publishedInfo.publishedVersionId !== item.itemVersionId) {
< button mat-stroked-button class = "tb-iot-hub-update-button"
[matTooltip]="'iot-hub.view-item-details' | translate"
matTooltipPosition="above"
(click)="viewUpdateDetails(publishedInfo, item)">
< mat-icon > info_outline< / mat-icon >
{{ publishedInfo.publishedVersion }}
< / button >
< button mat-stroked-button color = "primary" class = "tb-iot-hub-update-button"
(click)="updateItem(item, publishedInfo)">
@if (getPublishedVersionInfo(item); as pubInfo) {
@if (pubInfo.publishedVersionId !== item.itemVersionId) {
< span class = "tb-installed-update-available" >
< mat-icon > arrow_upward< / mat-icon >
v{{ pubInfo.publishedVersion }} {{ 'iot-hub.available' | translate }}
< / span >
< button mat-stroked-button color = "warn" class = "tb-installed-update-btn" ( click ) = " updateItem ( item , pubInfo ) " >
{{ 'iot-hub.update' | translate }}
< / button >
} @else {
< span class = "tb-iot-hub-up-to-date" > {{ 'iot-hub.up-to-date' | translate }}< / span >
< span class = "tb-installed-up-to-date" >
< mat-icon > check< / mat-icon >
{{ 'iot-hub.up-to-date' | translate }}
< / span >
}
} @else {
< span class = "tb-iot-hub-up-to-date" > {{ 'iot-hub.up-to-date' | translate }}< / span >
< span class = "tb-installed-up-to-date" >
< mat-icon > check< / mat-icon >
{{ 'iot-hub.up-to-date' | translate }}
< / span >
}
}
< / td >
< / ng-container >
<!-- Actions -->
< ng-container matColumnDef = "actions" >
< th mat-header-cell * matHeaderCellDef > < / th >
< td mat-cell * matCellDef = "let item" >
< button mat-icon-button
[matTooltip]="'iot-hub.view-item-details' | translate"
matTooltipPosition="above"
(click)="viewItemDetails(item); $event.stopPropagation()">
< mat-icon > info_outline< / mat-icon >
< / button >
@if (getEntityId(item)) {
< button mat-icon-button color = "primary"
[matTooltip]="'iot-hub.open-installed-entity' | translate"
matTooltipPosition="above"
(click)="openEntity(item); $event.stopPropagation()">
< div class = "tb-installed-actions" >
< button mat-icon-button ( click ) = " viewItemDetails ( item ) " matTooltip = "{{ 'iot-hub.view-item-details' | translate }}" >
< mat-icon > info_outline< / mat-icon >
< / button >
< button mat-icon-button ( click ) = " openEntity ( item ) " matTooltip = "{{ 'iot-hub.open-installed-entity' | translate }}" >
< mat-icon > open_in_new< / mat-icon >
< / button >
}
< button mat-icon-button color = "warn"
[matTooltip]="'action.delete' | translate"
matTooltipPosition="above"
(click)="deleteItem(item); $event.stopPropagation()">
< mat-icon > delete< / mat-icon >
< / button >
< button mat-icon-button ( click ) = " deleteItem ( item ) " matTooltip = "{{ 'iot-hub.remove' | translate }}" >
< tb-icon > mdi:trash-can-outline< / tb-icon >
< / button >
< / div >
< / td >
< / ng-container >
< tr mat-header-row * matHeaderRowDef = "displayedColumns" > < / tr >
< tr mat-row * matRowDef = "let row; columns: displayedColumns;" > < / tr >
< tr class = "mat-row" * matNoDataRow >
< td class = "mat-cell" [ attr . colspan ] = " displayedColumns . length " >
< div class = "tb-iot-hub-installed-empty" >
{{ 'iot-hub.no-installed-items' | translate }}
< / div >
< / td >
< / tr >
< / table >
< mat-paginator
[length]="totalElements"
[pageSize]="pageSize"
[pageIndex]="pageIndex"
[pageSizeOptions]="[10, 20, 50]"
(page)="onPageChange($event)">
< / mat-paginator >
@if (isLoading) {
< div class = "tb-installed-loading" >
< mat-spinner diameter = "40" > < / mat-spinner >
< / div >
}
@if (!isLoading & & dataSource.length === 0) {
< div class = "tb-installed-empty" >
{{ 'iot-hub.no-installed-items' | translate }}
< / div >
}
< / div >
<!-- Paginator -->
< mat-paginator
[length]="totalElements"
[pageSize]="pageSize"
[pageIndex]="pageIndex"
[pageSizeOptions]="[10, 25, 50]"
(page)="onPageChange($event)"
showFirstLastButtons>
< / mat-paginator >
< / div >