diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.ts index 8671057520..3034cee011 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.ts @@ -26,7 +26,7 @@ import { widgetType, WidgetTypeInfo } from '@shared/models/widget.models'; -import { debounceTime, distinctUntilChanged, map, skip, switchMap } from 'rxjs/operators'; +import { debounceTime, distinctUntilChanged, map, skip } from 'rxjs/operators'; import { BehaviorSubject, combineLatest, forkJoin, of } from 'rxjs'; import { PageLink } from '@shared/models/page/page-link'; import { Direction, SortOrder } from '@shared/models/page/sort-order'; @@ -780,21 +780,17 @@ export class DashboardWidgetSelectComponent { } private fetchInstalledWidgetVersions() { - const itemIds = (this.installedWidgets || []).map(i => i.itemId); - if (itemIds.length === 0) { + const versionIds = (this.installedWidgets || []) + .map(i => i.itemVersionId) + .filter(id => !!id); + if (versionIds.length === 0) { this.installedWidgetVersions = []; return of([]); } - return this.iotHubApiService.getItemsPublishedVersions(itemIds, { ignoreLoading: true }).pipe( - switchMap(infos => { - if (infos.length === 0) { - return of([]); - } - const versionRequests = infos.map(info => - this.iotHubApiService.getVersionInfo(info.publishedVersionId, { ignoreLoading: true }) - ); - return forkJoin(versionRequests); - }), + const versionRequests = versionIds.map(id => + this.iotHubApiService.getVersionInfo(id, { ignoreLoading: true }) + ); + return forkJoin(versionRequests).pipe( map(versions => { this.installedWidgetVersions = versions.sort((a, b) => b.totalInstallCount - a.totalInstallCount); return this.installedWidgetVersions; diff --git a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.html b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.html index cb59c9f5e9..0448de834c 100644 --- a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.html +++ b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.html @@ -405,87 +405,92 @@ - - @if (isLoading) { -
- -
- } +
- - @if (hasError && !isLoading) { -
-
-

{{ 'iot-hub.unable-to-load' | translate }}

-

{{ 'iot-hub.unable-to-load-text' | translate }}

- -
- } - - - @if (!isLoading && !hasError && items.length === 0) { -
-
-

{{ 'iot-hub.no-items-found' | translate }}

-

{{ 'iot-hub.no-items-found-text' | translate }}

- @if (hasActiveFilters()) { - + + @if (hasError) { +
+
+

{{ 'iot-hub.network-server-unavailable' | translate }}

+

{{ 'iot-hub.network-server-unavailable-text' | translate }}

+ +
} -
- } - - @if (!isLoading && !hasError && items.length > 0) { -
- @for (item of items; track item.id) { - - + + @if (!hasError && items.length === 0) { +
+
+

{{ 'iot-hub.no-items-found' | translate }}

+

{{ 'iot-hub.no-items-found-text' | translate }}

+ @if (hasActiveFilters()) { + + } +
} -
- -
-
- - @for (p of getPageNumbers(); track p) { - - } - -
-
- {{ 'iot-hub.items-per-page' | translate }}: - - @for (size of pageSizeOptions; track size) { - {{ size }} + + @if (!hasError && items.length > 0) { +
+ @for (item of items; track item.id) { + + } - -
+
+ + +
+
+ + @for (p of getPageNumbers(); track p) { + + } + +
+
+ {{ 'iot-hub.items-per-page' | translate }}: + + @for (size of pageSizeOptions; track size) { + {{ size }} + } + +
+
+ } + + + @if (isLoading) { +
+
+ +
+
+ }
- }
diff --git a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.scss b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.scss index b377219bb7..fc685f5b90 100644 --- a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.scss +++ b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.scss @@ -112,7 +112,8 @@ } .tb-iot-hub-filters-wrapper { - position: absolute; + position: sticky; + max-height: calc(100vh - var(--mat-toolbar-standard-height, 64px)); inset: 0; overflow-y: auto; } @@ -146,10 +147,12 @@ width: 60%; max-width: 550px; min-width: 300px; - margin-bottom: -48px; - - .embedded & { - margin-bottom: 0; + &:not(.embedded &) { + position: fixed; + top: var(--mat-toolbar-standard-height, 64px); + @media #{$mat-xs} { + top: var(--mat-toolbar-mobile-height, 56px); + } } } @@ -421,7 +424,7 @@ // Empty state text + no-data image .tb-iot-hub-empty-state { - .tb-no-data-bg { + .tb-no-data-bg, .tb-no-service-bg { flex: auto; height: 100px; } diff --git a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.ts b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.ts index 149ef64912..2efea716bf 100644 --- a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.ts +++ b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-browse.component.ts @@ -113,6 +113,7 @@ export class TbIotHubBrowseComponent implements OnInit, AfterViewInit, OnDestroy isLoading = false; hasError = false; filterDrawerOpened = false; + private retryTimer: any = null; textSearch = ''; _activeType: ItemType = ItemType.WIDGET; @@ -676,9 +677,23 @@ export class TbIotHubBrowseComponent implements OnInit, AfterViewInit, OnDestroy }); } + retryLoadItems(): void { + if (this.retryTimer != null) { + clearTimeout(this.retryTimer); + } + this.isLoading = true; + this.retryTimer = setTimeout(() => { + this.retryTimer = null; + this.loadItems(); + }, 350); + } + loadItems(): void { + if (this.retryTimer != null) { + clearTimeout(this.retryTimer); + this.retryTimer = null; + } this.isLoading = true; - this.hasError = false; const sort = this.sortOptions[this.selectedSortIndex]; const sortOrder: SortOrder = { property: sort.value, direction: sort.direction }; const pageLink = new PageLink(this.pageSize, this.pageIndex, this.textSearch || null, sortOrder); @@ -702,6 +717,7 @@ export class TbIotHubBrowseComponent implements OnInit, AfterViewInit, OnDestroy this.items = data.data; this.totalElements = data.totalElements; this.isLoading = false; + this.hasError = false; }, error: () => { this.isLoading = false; diff --git a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-card.component.html b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-card.component.html index 70dc7d986e..dc2030b00a 100644 --- a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-card.component.html +++ b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-card.component.html @@ -80,7 +80,7 @@ } @else {
-
+
@if (getPreviewUrl(); as previewUrl) { } @else { diff --git a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-card.component.scss b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-card.component.scss index 77d363f4ad..d46124d91e 100644 --- a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-card.component.scss +++ b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-card.component.scss @@ -52,11 +52,6 @@ position: relative; overflow: hidden; padding: 12px; - - &.tb-iot-hub-card-preview-device { - background: white; - border-bottom: 1px solid rgba(0, 0, 0, 0.12); - } } .tb-iot-hub-preview-image { diff --git a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-detail-dialog.component.html b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-detail-dialog.component.html index c72e209037..6c0318abbc 100644 --- a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-detail-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-detail-dialog.component.html @@ -94,8 +94,7 @@
+ [class.dlg-preview-carousel]="item.type === ItemType.SOLUTION_TEMPLATE && carouselImages.length > 1"> @if (item.type === ItemType.SOLUTION_TEMPLATE && carouselImages.length > 1) {