diff --git a/ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-browse.component.html b/ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-browse.component.html index a1e69167ec..c0d3ac14c3 100644 --- a/ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-browse.component.html +++ b/ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-browse.component.html @@ -213,7 +213,8 @@ (cardClick)="openItemDetail($event)" (creatorClick)="navigateToCreator($event)" (installClick)="installItem($event)" - (updateClick)="updateItem($event)"> + (updateClick)="updateItem($event)" + (deleteClick)="deleteInstalledItem($event)"> } diff --git a/ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-browse.component.scss b/ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-browse.component.scss index 93b66b7c80..3f7c2373ee 100644 --- a/ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-browse.component.scss +++ b/ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-browse.component.scss @@ -26,11 +26,16 @@ height: 100%; } -// Tabs — Design: px-40, bottom border rgba(0,0,0,0.12) +// Tabs — Design: px-40, bottom border, labels auto-width (not stretched) .tb-iot-hub-tabs { padding: 0 40px; flex-shrink: 0; border-bottom: 1px solid rgba(0, 0, 0, 0.12); + + .mat-mdc-tab-link { + min-width: auto; + flex: 0 0 auto; + } } // Two-column layout below tabs @@ -45,6 +50,8 @@ flex-shrink: 0; border-right: 1px solid rgba(0, 0, 0, 0.12); position: relative; + padding-bottom: 48px; + margin-bottom: -48px; } .tb-iot-hub-filters-wrapper { diff --git a/ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-browse.component.ts b/ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-browse.component.ts index f753f0da27..697b540782 100644 --- a/ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-browse.component.ts +++ b/ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-browse.component.ts @@ -34,6 +34,7 @@ import { ActivatedRoute, Router } from '@angular/router'; import { TbIotHubItemDetailDialogComponent, IotHubItemDetailDialogData } from './iot-hub-item-detail-dialog.component'; import { TbIotHubInstallDialogComponent, IotHubInstallDialogData } from './iot-hub-install-dialog.component'; import { TbIotHubUpdateDialogComponent, IotHubUpdateDialogData } from './iot-hub-update-dialog.component'; +import { TbIotHubDeleteDialogComponent, IotHubDeleteDialogData } from './iot-hub-delete-dialog.component'; interface SortOption { value: string; @@ -92,6 +93,7 @@ export class TbIotHubBrowseComponent implements OnInit, OnDestroy { widgetTypes: Map = widgetTypeTranslations; ruleChainTypes: Map = ruleChainTypeTranslations; + installedWidgets: IotHubInstalledItem[] = null; installedSolutionTemplates: IotHubInstalledItem[] = null; private searchSubject = new Subject(); @@ -123,6 +125,11 @@ export class TbIotHubBrowseComponent implements OnInit, OnDestroy { } } this.updateCategories(); + if (this.activeType === ItemType.WIDGET) { + this.loadInstalledWidgets(); + } else if (this.activeType === ItemType.SOLUTION_TEMPLATE) { + this.loadInstalledSolutionTemplates(); + } this.loadItems(); } @@ -153,7 +160,9 @@ export class TbIotHubBrowseComponent implements OnInit, OnDestroy { this.activeRuleChainTypes.clear(); this.updateCategories(); this.pageIndex = 0; - if (type === ItemType.SOLUTION_TEMPLATE) { + if (type === ItemType.WIDGET) { + this.loadInstalledWidgets(); + } else if (type === ItemType.SOLUTION_TEMPLATE) { this.loadInstalledSolutionTemplates(); } this.loadItems(); @@ -356,14 +365,17 @@ export class TbIotHubBrowseComponent implements OnInit, OnDestroy { } getInstalledItem(item: MpItemVersionView): IotHubInstalledItem | undefined { - if (this.activeType !== ItemType.SOLUTION_TEMPLATE || !this.installedSolutionTemplates) { - return undefined; + if (this.activeType === ItemType.WIDGET && this.installedWidgets) { + return this.installedWidgets.find(i => i.itemId === item.itemId); } - return this.installedSolutionTemplates.find(i => i.itemId === item.itemId); + if (this.activeType === ItemType.SOLUTION_TEMPLATE && this.installedSolutionTemplates) { + return this.installedSolutionTemplates.find(i => i.itemId === item.itemId); + } + return undefined; } openItemDetail(item: MpItemVersionView): void { - this.dialog.open(TbIotHubItemDetailDialogComponent, { + const dialogRef = this.dialog.open(TbIotHubItemDetailDialogComponent, { panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], autoFocus: false, data: { @@ -372,19 +384,25 @@ export class TbIotHubBrowseComponent implements OnInit, OnDestroy { installedItem: this.getInstalledItem(item) } as IotHubItemDetailDialogData }); + dialogRef.afterClosed().subscribe(result => { + if (result === 'installed' || result === 'deleted') { + this.reloadInstalledItems(); + } + }); } installItem(item: MpItemVersionView): void { const dialogRef = this.dialog.open(TbIotHubInstallDialogComponent, { panelClass: ['tb-dialog'], + autoFocus: false, data: { item, iotHubApiService: this.iotHubApiService } as IotHubInstallDialogData }); dialogRef.afterClosed().subscribe(result => { - if (result === 'installed' && this.activeType === ItemType.SOLUTION_TEMPLATE) { - this.loadItems(); + if (result === 'installed') { + this.reloadInstalledItems(); } }); } @@ -396,6 +414,7 @@ export class TbIotHubBrowseComponent implements OnInit, OnDestroy { } const dialogRef = this.dialog.open(TbIotHubUpdateDialogComponent, { panelClass: ['tb-dialog'], + autoFocus: false, data: { installedItemId: installedItem.id.id, itemName: item.name, @@ -406,8 +425,27 @@ export class TbIotHubBrowseComponent implements OnInit, OnDestroy { } as IotHubUpdateDialogData }); dialogRef.afterClosed().subscribe(result => { - if (result === 'updated' && this.activeType === ItemType.SOLUTION_TEMPLATE) { - this.loadItems(); + if (result === 'updated') { + this.reloadInstalledItems(); + } + }); + } + + deleteInstalledItem(item: MpItemVersionView): void { + const installedItem = this.getInstalledItem(item); + if (!installedItem) { + return; + } + const dialogRef = this.dialog.open(TbIotHubDeleteDialogComponent, { + panelClass: ['tb-dialog'], + autoFocus: false, + data: { itemName: item.name } as IotHubDeleteDialogData + }); + dialogRef.afterClosed().subscribe(confirmed => { + if (confirmed) { + this.iotHubApiService.deleteInstalledItem(installedItem.id.id).subscribe(() => { + this.reloadInstalledItems(); + }); } }); } @@ -420,6 +458,18 @@ export class TbIotHubBrowseComponent implements OnInit, OnDestroy { this.router.navigate(['/iot-hub/installed']); } + private loadInstalledWidgets(): void { + if (this.installedWidgets !== null) { + return; + } + const pageLink = new PageLink(10000, 0); + this.iotHubApiService.getInstalledItems(pageLink, ItemType.WIDGET, {ignoreLoading: true}).subscribe({ + next: (data) => { + this.installedWidgets = data.data; + } + }); + } + private loadInstalledSolutionTemplates(): void { if (this.installedSolutionTemplates !== null) { return; @@ -432,6 +482,20 @@ export class TbIotHubBrowseComponent implements OnInit, OnDestroy { }); } + private reloadInstalledItems(): void { + const config = {ignoreLoading: true}; + const pageLink = new PageLink(10000, 0); + if (this.activeType === ItemType.WIDGET) { + this.iotHubApiService.getInstalledItems(pageLink, ItemType.WIDGET, config).subscribe(data => { + this.installedWidgets = data.data; + }); + } else if (this.activeType === ItemType.SOLUTION_TEMPLATE) { + this.iotHubApiService.getInstalledItems(pageLink, ItemType.SOLUTION_TEMPLATE, config).subscribe(data => { + this.installedSolutionTemplates = data.data; + }); + } + } + private updateCategories(): void { this.categories = getCategoriesForType(this.activeType); } diff --git a/ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-creator-profile.component.html b/ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-creator-profile.component.html index 62bac84619..d664a3bbfd 100644 --- a/ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-creator-profile.component.html +++ b/ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-creator-profile.component.html @@ -47,9 +47,9 @@
+ @if (showSubtype && getSubtypeLabel(); as subtypeLabel) { + {{ subtypeLabel }} + }

{{ item.name }}

person diff --git a/ui-ngx/src/assets/iot-hub/hero-calculated-field-icon-1.svg b/ui-ngx/src/assets/iot-hub/hero-calculated-field-icon-1.svg new file mode 100644 index 0000000000..7734b75c7a --- /dev/null +++ b/ui-ngx/src/assets/iot-hub/hero-calculated-field-icon-1.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/iot-hub/hero-calculated-field-icon-2.svg b/ui-ngx/src/assets/iot-hub/hero-calculated-field-icon-2.svg new file mode 100644 index 0000000000..ac28694c40 --- /dev/null +++ b/ui-ngx/src/assets/iot-hub/hero-calculated-field-icon-2.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/iot-hub/hero-calculated-field-icon-3.svg b/ui-ngx/src/assets/iot-hub/hero-calculated-field-icon-3.svg new file mode 100644 index 0000000000..860997b4a5 --- /dev/null +++ b/ui-ngx/src/assets/iot-hub/hero-calculated-field-icon-3.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/iot-hub/hero-calculated-field-icon-4.svg b/ui-ngx/src/assets/iot-hub/hero-calculated-field-icon-4.svg new file mode 100644 index 0000000000..356d5dece0 --- /dev/null +++ b/ui-ngx/src/assets/iot-hub/hero-calculated-field-icon-4.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/iot-hub/hero-device-icon-1.svg b/ui-ngx/src/assets/iot-hub/hero-device-icon-1.svg new file mode 100644 index 0000000000..8ef1b628a4 --- /dev/null +++ b/ui-ngx/src/assets/iot-hub/hero-device-icon-1.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/iot-hub/hero-device-icon-2.svg b/ui-ngx/src/assets/iot-hub/hero-device-icon-2.svg new file mode 100644 index 0000000000..57e615a72d --- /dev/null +++ b/ui-ngx/src/assets/iot-hub/hero-device-icon-2.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/iot-hub/hero-device-icon-3.svg b/ui-ngx/src/assets/iot-hub/hero-device-icon-3.svg new file mode 100644 index 0000000000..1e7f844ba7 --- /dev/null +++ b/ui-ngx/src/assets/iot-hub/hero-device-icon-3.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/iot-hub/hero-device-icon-4.svg b/ui-ngx/src/assets/iot-hub/hero-device-icon-4.svg new file mode 100644 index 0000000000..164db57b9a --- /dev/null +++ b/ui-ngx/src/assets/iot-hub/hero-device-icon-4.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/iot-hub/hero-rule-chain-icon-1.svg b/ui-ngx/src/assets/iot-hub/hero-rule-chain-icon-1.svg new file mode 100644 index 0000000000..53a6019a4d --- /dev/null +++ b/ui-ngx/src/assets/iot-hub/hero-rule-chain-icon-1.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/iot-hub/hero-rule-chain-icon-2.svg b/ui-ngx/src/assets/iot-hub/hero-rule-chain-icon-2.svg new file mode 100644 index 0000000000..917f875faa --- /dev/null +++ b/ui-ngx/src/assets/iot-hub/hero-rule-chain-icon-2.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/iot-hub/hero-rule-chain-icon-3.svg b/ui-ngx/src/assets/iot-hub/hero-rule-chain-icon-3.svg new file mode 100644 index 0000000000..c5ecbe9b74 --- /dev/null +++ b/ui-ngx/src/assets/iot-hub/hero-rule-chain-icon-3.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/iot-hub/hero-rule-chain-icon-4.svg b/ui-ngx/src/assets/iot-hub/hero-rule-chain-icon-4.svg new file mode 100644 index 0000000000..eda7544128 --- /dev/null +++ b/ui-ngx/src/assets/iot-hub/hero-rule-chain-icon-4.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/iot-hub/hero-solution-template-icon-1.svg b/ui-ngx/src/assets/iot-hub/hero-solution-template-icon-1.svg new file mode 100644 index 0000000000..f1d0ee4799 --- /dev/null +++ b/ui-ngx/src/assets/iot-hub/hero-solution-template-icon-1.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/iot-hub/hero-solution-template-icon-2.svg b/ui-ngx/src/assets/iot-hub/hero-solution-template-icon-2.svg new file mode 100644 index 0000000000..9708abc935 --- /dev/null +++ b/ui-ngx/src/assets/iot-hub/hero-solution-template-icon-2.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/iot-hub/hero-solution-template-icon-3.svg b/ui-ngx/src/assets/iot-hub/hero-solution-template-icon-3.svg new file mode 100644 index 0000000000..7151c40b16 --- /dev/null +++ b/ui-ngx/src/assets/iot-hub/hero-solution-template-icon-3.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/iot-hub/hero-solution-template-icon-4.svg b/ui-ngx/src/assets/iot-hub/hero-solution-template-icon-4.svg new file mode 100644 index 0000000000..11a06c0a4f --- /dev/null +++ b/ui-ngx/src/assets/iot-hub/hero-solution-template-icon-4.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + +