Skip to content

Commit 33ab081

Browse files
authored
Merge pull request ceph#64911 from rhcs-dashboard/dashboard-loading-state
mgr/dashboard: loading state for inventory card Reviewed-by: Afreen Misbah <[email protected]>
2 parents 00f0c33 + 05f7cb6 commit 33ab081

File tree

16 files changed

+244
-141
lines changed

16 files changed

+244
-141
lines changed

src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/upgrade/upgrade.component.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,9 @@ <h5>{{ version }}</h5>
8383
<h5>
8484
<i class="text-success"
8585
[ngClass]="[icons.success]"
86-
*ngIf="(healthData.mgr_map | mgrSummary).total > 1; else warningIcon">
86+
*ngIf="(healthData.mgr_map | mgrSummary)?.total > 1; else warningIcon">
8787
</i>
88-
{{ (healthData.mgr_map | mgrSummary).total }}
88+
{{ (healthData.mgr_map | mgrSummary)?.total }}
8989
</h5>
9090
</div>
9191
</cd-card>
@@ -139,12 +139,12 @@ <h5>
139139
*ngIf="info$ | async as info; else checkingForUpgradeStatus">
140140
<ng-container *ngIf="info.versions.length > 0; else noUpgradesAvailable">
141141
<div i18n-ngbTooltip
142-
[ngbTooltip]="(healthData.mgr_map | mgrSummary).total <= 1 ? 'To upgrade, you need minimum 2 mgr daemons.' : ''">
142+
[ngbTooltip]="(healthData.mgr_map | mgrSummary)?.total <= 1 ? 'To upgrade, you need minimum 2 mgr daemons.' : ''">
143143
<button class="btn btn-accent mt-2"
144144
id="upgrade"
145145
aria-label="Upgrade now"
146146
(click)="upgradeNow(info.versions[info.versions.length - 1])"
147-
[disabled]="(healthData.mgr_map | mgrSummary).total <= 1"
147+
[disabled]="(healthData.mgr_map | mgrSummary)?.total <= 1"
148148
i18n>Upgrade to {{ info.versions[info.versions.length - 1] }}</button>
149149
</div>
150150
<a class="mt-2 link-primary mb-2"

src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-v3.module.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { DashboardPieComponent } from './dashboard-pie/dashboard-pie.component';
1414
import { DashboardTimeSelectorComponent } from './dashboard-time-selector/dashboard-time-selector.component';
1515
import { DashboardV3Component } from './dashboard/dashboard-v3.component';
1616
import { PgSummaryPipe } from './pg-summary.pipe';
17-
import { ToggletipModule } from 'carbon-components-angular';
17+
import { InlineLoadingModule, ToggletipModule } from 'carbon-components-angular';
1818

1919
@NgModule({
2020
imports: [
@@ -28,7 +28,8 @@ import { ToggletipModule } from 'carbon-components-angular';
2828
ReactiveFormsModule,
2929
SimplebarAngularModule,
3030
BaseChartDirective,
31-
ToggletipModule
31+
ToggletipModule,
32+
InlineLoadingModule
3233
],
3334
declarations: [
3435
DashboardV3Component,

src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.html

Lines changed: 62 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
<div class="container-fluid p-4"
2-
*ngIf="healthData && enabledFeature$ | async as enabledFeature">
3-
1+
<div class="container-fluid p-4">
42
<div class="row d-flex flex-row ps-3">
53

64
<!-- First Grid to hold Details and Inventory Card-->
@@ -66,64 +64,60 @@
6664
i18n-title
6765
class="pt-4"
6866
aria-label="Inventory card">
69-
<!-- Hosts -->
70-
<cd-card-row [data]="healthData.hosts"
71-
link="/hosts"
72-
title="Host"
73-
summaryType="simplified"
74-
*ngIf="healthData.hosts != null"
75-
[dropdownData]="(isHardwareEnabled$ | async) && (hardwareSummary$ | async)">
76-
</cd-card-row>
77-
<!-- Monitors -->
78-
<cd-card-row [data]="healthData.mon_status.monmap.mons.length"
79-
link="/monitor"
80-
title="Monitor"
81-
summaryType="simplified"
82-
*ngIf="healthData.mon_status"></cd-card-row>
83-
<!-- Managers -->
84-
<cd-card-row [data]="healthData.mgr_map | mgrSummary"
85-
title="Manager"
86-
*ngIf="healthData.mgr_map"></cd-card-row>
67+
<ng-container *ngIf="enabledFeature$ | async as enabledFeature">
68+
<!-- Hosts -->
69+
<cd-card-row [data]="hostsCount"
70+
link="/hosts"
71+
title="Host"
72+
summaryType="simplified"
73+
[dropdownData]="(isHardwareEnabled$ | async) && (hardwareSummary$ | async)">
74+
</cd-card-row>
75+
<!-- Monitors -->
76+
<cd-card-row [data]="monMap?.monmap.mons.length"
77+
link="/monitor"
78+
title="Monitor"
79+
summaryType="simplified"></cd-card-row>
80+
<!-- Managers -->
81+
<cd-card-row [data]="mgrMap | mgrSummary"
82+
title="Manager"></cd-card-row>
8783

88-
<!-- OSDs -->
89-
<cd-card-row [data]="healthData.osd_map | osdSummary"
90-
link="/osd"
91-
title="OSD"
92-
summaryType="osd"
93-
*ngIf="healthData.osd_map"></cd-card-row>
84+
<!-- OSDs -->
85+
<cd-card-row [data]="osdMap | osdSummary"
86+
link="/osd"
87+
title="OSD"
88+
summaryType="osd"></cd-card-row>
9489

95-
<!-- Pools -->
96-
<cd-card-row [data]="healthData.pools.length"
97-
link="/pool"
98-
title="Pool"
99-
summaryType="simplified"
100-
*ngIf="healthData.pools"></cd-card-row>
90+
<!-- Pools -->
91+
<cd-card-row [data]="poolStatus?.length"
92+
link="/pool"
93+
title="Pool"
94+
summaryType="simplified"></cd-card-row>
10195

102-
<!-- PG Info -->
103-
<cd-card-row [data]="healthData.pg_info | pgSummary"
104-
title="PG"
105-
*ngIf="healthData.pg_info"></cd-card-row>
96+
<!-- PG Info -->
97+
<cd-card-row [data]="pgStatus | pgSummary"
98+
title="PG"></cd-card-row>
10699

107-
<!-- Object gateways -->
108-
<cd-card-row [data]="healthData.rgw"
109-
link="/rgw/daemon"
110-
title="Object Gateway"
111-
summaryType="simplified"
112-
id="rgw-item"
113-
*ngIf="enabledFeature.rgw && healthData.rgw || healthData.rgw === 0 "></cd-card-row>
100+
<!-- Object gateways -->
101+
<cd-card-row [data]="rgwCount"
102+
link="/rgw/daemon"
103+
title="Object Gateway"
104+
summaryType="simplified"
105+
id="rgw-item"
106+
*ngIf="enabledFeature.rgw"></cd-card-row>
114107

115-
<!-- Metadata Servers -->
116-
<cd-card-row [data]="healthData.fs_map | mdsSummary"
117-
title="Metadata Server"
118-
id="mds-item"
119-
*ngIf="enabledFeature.cephfs && healthData.fs_map"></cd-card-row>
120-
<!-- iSCSI Gateways -->
121-
<cd-card-row [data]="healthData.iscsi_daemons"
122-
link="/iscsi/daemon"
123-
title="iSCSI Gateway"
124-
summaryType="iscsi"
125-
id="iscsi-item"
126-
*ngIf="enabledFeature.iscsi && healthData.iscsi_daemons"></cd-card-row>
108+
<!-- Metadata Servers -->
109+
<cd-card-row [data]="mdsMap | mdsSummary"
110+
title="Metadata Server"
111+
id="mds-item"
112+
*ngIf="enabledFeature.cephfs"></cd-card-row>
113+
<!-- iSCSI Gateways -->
114+
<cd-card-row [data]="iscsiMap"
115+
link="/iscsi/daemon"
116+
title="iSCSI Gateway"
117+
summaryType="iscsi"
118+
id="iscsi-item"
119+
*ngIf="enabledFeature.iscsi"></cd-card-row>
120+
</ng-container>
127121
</cd-card>
128122
</div>
129123

@@ -148,28 +142,28 @@
148142
</div>
149143
<div class="d-flex flex-column ms-4 me-4 mt-4 mb-4">
150144
<div class="d-flex flex-row col-md-3 ms-4">
151-
<i *ngIf="healthData.health?.status"
152-
[ngClass]="[healthData.health.status | healthIcon, icons.large2x]"
153-
[ngStyle]="healthData.health.status | healthColor"
154-
[title]="healthData.health.status">
145+
<i *ngIf="healthData?.status else loadingTpl"
146+
[ngClass]="[healthData.status | healthIcon, icons.large2x]"
147+
[ngStyle]="healthData.status | healthColor"
148+
[title]="healthData.status">
155149
</i>
156150
<span class="ms-2 mt-n1 lead"
157-
*ngIf="!healthData.health?.checks?.length"
151+
*ngIf="!healthData?.checks?.length"
158152
i18n>Cluster</span>
159153
<cds-toggletip [dropShadow]="true"
160154
[autoAlign]="true">
161155
<div cdsToggletipButton>
162156
<a class="ms-2 mt-n1 lead text-primary"
163157
popoverClass="info-card-popover-cluster-status"
164-
*ngIf="healthData.health?.checks?.length"
158+
*ngIf="healthData?.checks?.length"
165159
i18n>Cluster
166160
</a>
167161
</div>
168162
<div cdsToggletipContent
169163
#healthCheck>
170164
<div class="cds--popover-scroll-container">
171-
<cd-health-checks *ngIf="healthData?.health?.checks"
172-
[healthData]="healthData.health.checks">
165+
<cd-health-checks *ngIf="healthData?.checks"
166+
[healthData]="healthData.checks">
173167
</cd-health-checks>
174168
</div>
175169
</div>
@@ -330,3 +324,7 @@ <h6 class="card-title bold">{{ alert.labels.alertname }}</h6>
330324
i18n><i [ngClass]="[icons.infoCircle]"></i> See <a routerLink="/logs">Logs</a> for more details.</p>
331325
</ng-container>
332326
</ng-template>
327+
328+
<ng-template #loadingTpl>
329+
<cds-inline-loading></cds-inline-loading>
330+
</ng-template>

src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.ts

Lines changed: 58 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { Component, OnDestroy, OnInit } from '@angular/core';
22

33
import _ from 'lodash';
4-
import { BehaviorSubject, Observable, Subscription, of } from 'rxjs';
5-
import { switchMap, take } from 'rxjs/operators';
4+
import { BehaviorSubject, EMPTY, Observable, Subject, Subscription, of } from 'rxjs';
5+
import { catchError, exhaustMap, switchMap, take, takeUntil } from 'rxjs/operators';
66

77
import { HealthService } from '~/app/shared/api/health.service';
88
import { OsdService } from '~/app/shared/api/osd.service';
@@ -27,6 +27,14 @@ import { AlertClass } from '~/app/shared/enum/health-icon.enum';
2727
import { HardwareService } from '~/app/shared/api/hardware.service';
2828
import { SettingsService } from '~/app/shared/api/settings.service';
2929
import { OsdSettings } from '~/app/shared/models/osd-settings';
30+
import {
31+
IscsiMap,
32+
MdsMap,
33+
MgrMap,
34+
MonMap,
35+
OsdMap,
36+
PgStatus
37+
} from '~/app/shared/models/health.interface';
3038

3139
@Component({
3240
selector: 'cd-dashboard-v3',
@@ -37,7 +45,6 @@ export class DashboardV3Component extends PrometheusListHelper implements OnInit
3745
detailsCardData: DashboardDetails = {};
3846
osdSettingsService: any;
3947
osdSettings = new OsdSettings();
40-
interval = new Subscription();
4148
permissions: Permissions;
4249
enabledFeature$: FeatureTogglesMap$;
4350
color: string;
@@ -80,6 +87,17 @@ export class DashboardV3Component extends PrometheusListHelper implements OnInit
8087
hardwareSubject = new BehaviorSubject<any>([]);
8188
managedByConfig$: Observable<any>;
8289
private subs = new Subscription();
90+
private destroy$ = new Subject<void>();
91+
92+
hostsCount: number = null;
93+
monMap: MonMap = null;
94+
mgrMap: MgrMap = null;
95+
osdMap: OsdMap = null;
96+
poolStatus: Record<string, any>[] = null;
97+
pgStatus: PgStatus = null;
98+
rgwCount: number = null;
99+
mdsMap: MdsMap = null;
100+
iscsiMap: IscsiMap = null;
83101

84102
constructor(
85103
private summaryService: SummaryService,
@@ -103,6 +121,7 @@ export class DashboardV3Component extends PrometheusListHelper implements OnInit
103121
ngOnInit() {
104122
super.ngOnInit();
105123
if (this.permissions.configOpt.read) {
124+
this.getOsdSettings();
106125
this.isHardwareEnabled$ = this.getHardwareConfig();
107126
this.hardwareSummary$ = this.hardwareSubject.pipe(
108127
switchMap(() =>
@@ -116,12 +135,16 @@ export class DashboardV3Component extends PrometheusListHelper implements OnInit
116135
);
117136
this.managedByConfig$ = this.settingsService.getValues('MANAGED_BY_CLUSTERS');
118137
}
119-
this.interval = this.refreshIntervalService.intervalData$.subscribe(() => {
120-
this.getHealth();
121-
this.getCapacity();
122-
if (this.permissions.configOpt.read) this.getOsdSettings();
123-
if (this.hardwareEnabled) this.hardwareSubject.next([]);
138+
139+
this.loadInventories();
140+
141+
// fetch capacity to load the capacity chart
142+
this.refreshIntervalObs(() => this.healthService.getClusterCapacity()).subscribe({
143+
next: (capacity: any) => {
144+
this.capacity = capacity;
145+
}
124146
});
147+
125148
this.getPrometheusData(this.prometheusService.lastHourDateObject);
126149
this.getDetailsCardData();
127150
this.getTelemetryReport();
@@ -136,15 +159,10 @@ export class DashboardV3Component extends PrometheusListHelper implements OnInit
136159
Telemetry configration.';
137160
}
138161
ngOnDestroy() {
139-
this.interval.unsubscribe();
140162
this.prometheusService.unsubscribe();
141163
this.subs?.unsubscribe();
142-
}
143-
144-
getHealth() {
145-
this.healthService.getMinimalHealth().subscribe((data: any) => {
146-
this.healthData = data;
147-
});
164+
this.destroy$.next();
165+
this.destroy$.complete();
148166
}
149167

150168
toggleAlertsWindow(type: AlertClass) {
@@ -167,12 +185,6 @@ export class DashboardV3Component extends PrometheusListHelper implements OnInit
167185
);
168186
}
169187

170-
private getCapacity() {
171-
this.capacityService = this.healthService.getClusterCapacity().subscribe((data: any) => {
172-
this.capacity = data;
173-
});
174-
}
175-
176188
private getOsdSettings() {
177189
this.osdSettingsService = this.osdService
178190
.getOsdSettings()
@@ -208,4 +220,29 @@ export class DashboardV3Component extends PrometheusListHelper implements OnInit
208220
})
209221
);
210222
}
223+
224+
refreshIntervalObs(fn: Function) {
225+
return this.refreshIntervalService.intervalData$.pipe(
226+
exhaustMap(() => fn().pipe(catchError(() => EMPTY))),
227+
takeUntil(this.destroy$)
228+
);
229+
}
230+
231+
loadInventories() {
232+
this.refreshIntervalObs(() => this.healthService.getMinimalHealth()).subscribe({
233+
next: (result: any) => {
234+
this.hostsCount = result.hosts;
235+
this.monMap = result.mon_status;
236+
this.mgrMap = result.mgr_map;
237+
this.osdMap = result.osd_map;
238+
this.poolStatus = result.pools;
239+
this.pgStatus = result.pg_info;
240+
this.rgwCount = result.rgw;
241+
this.mdsMap = result.fs_map;
242+
this.iscsiMap = result.iscsi_daemons;
243+
this.healthData = result.health;
244+
this.enabledFeature$ = this.featureToggles.get();
245+
}
246+
});
247+
}
211248
}

src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/pg-summary.pipe.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export class PgSummaryPipe implements PipeTransform {
99
constructor(private pgCategoryService: PgCategoryService) {}
1010

1111
transform(value: any): any {
12+
if (!value) return null;
1213
const categoryPgAmount: Record<string, number> = {};
1314
let total = 0;
1415
_.forEach(value.statuses, (pgAmount, pgStatesText) => {

src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-overview-dashboard/rgw-overview-dashboard.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ export class RgwOverviewDashboardComponent implements OnInit, OnDestroy {
9999
this.getSyncStatus();
100100
});
101101
this.realmSub = this.rgwRealmService.list().subscribe((data: any) => {
102-
this.rgwRealmCount = data['realms'].length;
102+
this.rgwRealmCount = data['realms'].length || 0;
103103
});
104104
this.ZonegroupSub = this.rgwZonegroupService.list().subscribe((data: any) => {
105105
this.rgwZonegroupCount = data['zonegroups'].length;

0 commit comments

Comments
 (0)