Browse Source

Add popular devices section, installed devices tracking, fix wizard stepper

Home page:
- Add "Popular Devices" section with big card grid
- Fetch and track installed devices (installedDevices property)
- getInstalledDevice, findInstalledItem, reloadInstalledItems handle DEVICE type
- deleteInstalledItem handles DEVICE type

Item detail dialog:
- Hide "Install one more" button for WIDGET and SOLUTION_TEMPLATE types

Device install wizard:
- Fix double-click to advance stepper: add cdr.detectChanges() before stepper.next()
pull/15508/head
Igor Kulikov 3 months ago
parent
commit
c2341bc0cb
  1. 1
      ui-ngx/src/app/modules/home/components/iot-hub/device-install-dialog/device-install-dialog.component.ts
  2. 20
      ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-detail-dialog.component.html
  3. 25
      ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-home.component.html
  4. 18
      ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-home.component.ts
  5. 1
      ui-ngx/src/assets/locale/locale.constant-en_US.json

1
ui-ngx/src/app/modules/home/components/iot-hub/device-install-dialog/device-install-dialog.component.ts

@ -238,6 +238,7 @@ export class TbDeviceInstallDialogComponent extends DialogComponent<TbDeviceInst
return;
}
step.completed = true;
this.cdr.detectChanges();
this.stepper.next();
this.onStepActivated();
}

20
ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-detail-dialog.component.html

@ -98,10 +98,12 @@
</button>
}
@if (isInstalled()) {
<button mat-stroked-button (click)="install()">
<mat-icon>add</mat-icon>
{{ 'iot-hub.install-one-more' | translate }}
</button>
@if (item.type !== ItemType.WIDGET && item.type !== ItemType.SOLUTION_TEMPLATE) {
<button mat-stroked-button (click)="install()">
<mat-icon>add</mat-icon>
{{ 'iot-hub.install-one-more' | translate }}
</button>
}
<button mat-stroked-button color="warn" (click)="deleteItem()">
<mat-icon>delete</mat-icon>
{{ 'iot-hub.remove' | translate }}
@ -230,10 +232,12 @@
</button>
}
@if (isInstalled()) {
<button mat-stroked-button (click)="install()">
<mat-icon>add</mat-icon>
{{ 'iot-hub.install-one-more' | translate }}
</button>
@if (item.type !== ItemType.WIDGET && item.type !== ItemType.SOLUTION_TEMPLATE) {
<button mat-stroked-button (click)="install()">
<mat-icon>add</mat-icon>
{{ 'iot-hub.install-one-more' | translate }}
</button>
}
<button mat-stroked-button color="warn" (click)="deleteItem()">
<tb-icon matButtonIcon class="tb-mat-24">mdi:trash-can-outline</tb-icon>
{{ 'iot-hub.remove' | translate }}

25
ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-home.component.html

@ -263,6 +263,31 @@
</div>
</div>
}
<!-- Popular Devices -->
@if (popularDevices.length) {
<div class="tb-iot-hub-section">
<button mat-button class="tb-iot-hub-section-header" (click)="navigateToBrowse(ItemType.DEVICE)">
{{ 'iot-hub.popular-devices' | translate }}
<mat-icon iconPositionEnd>chevron_right</mat-icon>
</button>
<div class="tb-iot-hub-big-cards-row">
@for (item of popularDevices; track item.id) {
<tb-iot-hub-item-card
[item]="item"
[installedItem]="getInstalledDevice(item)"
[showTypeChip]="false"
[showCreator]="true"
(cardClick)="openItemDetail($event)"
(creatorClick)="navigateToCreator($event)"
(installClick)="installItem($event)"
(updateClick)="updateItem($event)"
(deleteClick)="deleteInstalledItem($event)">
</tb-iot-hub-item-card>
}
</div>
</div>
}
}
@if (isLoading) {

18
ui-ngx/src/app/modules/home/pages/iot-hub/iot-hub-home.component.ts

@ -124,9 +124,11 @@ export class TbIotHubHomeComponent implements OnInit, OnDestroy {
popularSolutionTemplates: MpItemVersionView[] = [];
popularCalcFields: MpItemVersionView[] = [];
popularRuleChains: MpItemVersionView[] = [];
popularDevices: MpItemVersionView[] = [];
installedWidgets: IotHubInstalledItem[] = [];
installedSolutionTemplates: IotHubInstalledItem[] = [];
installedDevices: IotHubInstalledItem[] = [];
installedItemsCount = 0;
isLoading = true;
@ -329,6 +331,10 @@ export class TbIotHubHomeComponent implements OnInit, OnDestroy {
this.iotHubApiService.getInstalledItems(pageLink, ItemType.SOLUTION_TEMPLATE, config).subscribe(data => {
this.installedSolutionTemplates = data.data;
});
} else if (type === ItemType.DEVICE) {
this.iotHubApiService.getInstalledItems(pageLink, ItemType.DEVICE, config).subscribe(data => {
this.installedDevices = data.data;
});
}
}
@ -338,6 +344,8 @@ export class TbIotHubHomeComponent implements OnInit, OnDestroy {
return this.installedWidgets.find(i => i.itemId === item.itemId);
case ItemType.SOLUTION_TEMPLATE:
return this.installedSolutionTemplates.find(i => i.itemId === item.itemId);
case ItemType.DEVICE:
return this.installedDevices.find(i => i.itemId === item.itemId);
default:
return undefined;
}
@ -373,6 +381,10 @@ export class TbIotHubHomeComponent implements OnInit, OnDestroy {
return this.installedSolutionTemplates.find(i => i.itemId === item.itemId);
}
getInstalledDevice(item: MpItemVersionView): IotHubInstalledItem | undefined {
return this.installedDevices.find(i => i.itemId === item.itemId);
}
deleteInstalledItem(item: MpItemVersionView): void {
const installedItem = this.findInstalledItem(item);
if (!installedItem) { return; }
@ -382,6 +394,8 @@ export class TbIotHubHomeComponent implements OnInit, OnDestroy {
this.installedWidgets = this.installedWidgets.filter(i => i.id.id !== installedItem.id.id);
} else if (item.type === ItemType.SOLUTION_TEMPLATE) {
this.installedSolutionTemplates = this.installedSolutionTemplates.filter(i => i.id.id !== installedItem.id.id);
} else if (item.type === ItemType.DEVICE) {
this.installedDevices = this.installedDevices.filter(i => i.id.id !== installedItem.id.id);
}
});
}
@ -438,8 +452,10 @@ export class TbIotHubHomeComponent implements OnInit, OnDestroy {
solutionTemplates: this.iotHubApiService.getPublishedVersions(buildQuery(ItemType.SOLUTION_TEMPLATE, this.bigCardCount), config),
calcFields: this.iotHubApiService.getPublishedVersions(buildQuery(ItemType.CALCULATED_FIELD, this.compactCardCount), config),
ruleChains: this.iotHubApiService.getPublishedVersions(buildQuery(ItemType.RULE_CHAIN, this.compactCardCount), config),
devices: this.iotHubApiService.getPublishedVersions(buildQuery(ItemType.DEVICE, this.bigCardCount), config),
installedWidgets: this.iotHubApiService.getInstalledItems(installedPageLink, ItemType.WIDGET, config),
installedSolutionTemplates: this.iotHubApiService.getInstalledItems(installedPageLink, ItemType.SOLUTION_TEMPLATE, config),
installedDevices: this.iotHubApiService.getInstalledItems(installedPageLink, ItemType.DEVICE, config),
installedCount: this.iotHubApiService.getInstalledItemsCount(null, config)
}).subscribe({
next: (results) => {
@ -448,8 +464,10 @@ export class TbIotHubHomeComponent implements OnInit, OnDestroy {
this.popularSolutionTemplates = results.solutionTemplates.data;
this.popularCalcFields = results.calcFields.data;
this.popularRuleChains = results.ruleChains.data;
this.popularDevices = results.devices.data;
this.installedWidgets = results.installedWidgets.data;
this.installedSolutionTemplates = results.installedSolutionTemplates.data;
this.installedDevices = results.installedDevices.data;
this.installedItemsCount = results.installedCount;
this.isLoading = false;
},

1
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -3730,6 +3730,7 @@
"popular-solution-templates": "Popular Solution Templates",
"popular-calculated-fields": "Popular Calculated Fields",
"popular-rule-chains": "Popular Rule Chains",
"popular-devices": "Popular Devices",
"become-creator-text": "Submit your templates to the ThingsBoard IoT Hub to get featured and showcase your solutions to our global community.",
"contribute": "Contribute",
"browse": "Browse IoT Hub",

Loading…
Cancel
Save