From e95853eee3fa52e8b90584a1145ce6e753cc5e2b Mon Sep 17 00:00:00 2001 From: guodan1 Date: Fri, 18 Jan 2019 14:33:43 +0800 Subject: [PATCH] mgr/dashboar: Add refresh nterval to the dashboard landing page Fixes: http://tracker.ceph.com/issues/26872 Signed-off-by: guodan1 (cherry picked from commit 58e9d48259ad7ac562ffb85bc22b3d6fba6120e1) --- .../dashboard/dashboard.component.html | 1 + .../dashboard/health/health.component.spec.ts | 4 +- .../ceph/dashboard/health/health.component.ts | 13 +++--- .../shared/components/components.module.ts | 7 ++- .../refresh-selector.component.html | 18 ++++++++ .../refresh-selector.component.scss | 26 +++++++++++ .../refresh-selector.component.spec.ts | 28 ++++++++++++ .../refresh-selector.component.ts | 32 +++++++++++++ .../services/refresh-interval.service.spec.ts | 45 +++++++++++++++++++ .../services/refresh-interval.service.ts | 43 ++++++++++++++++++ .../frontend/src/locale/messages.xlf | 10 ++++- 11 files changed, 217 insertions(+), 10 deletions(-) create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/shared/components/refresh-selector/refresh-selector.component.html create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/shared/components/refresh-selector/refresh-selector.component.scss create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/shared/components/refresh-selector/refresh-selector.component.spec.ts create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/shared/components/refresh-selector/refresh-selector.component.ts create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/shared/services/refresh-interval.service.spec.ts create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/shared/services/refresh-interval.service.ts diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/dashboard/dashboard.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/dashboard/dashboard.component.html index 89a37fd6c0e..c59717c524f 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/dashboard/dashboard.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/dashboard/dashboard.component.html @@ -1,4 +1,5 @@
+ diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.spec.ts index cc5a3b61dbe..99bc05fc8db 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.spec.ts @@ -12,6 +12,7 @@ import { HealthService } from '../../../shared/api/health.service'; import { Permissions } from '../../../shared/models/permissions'; import { AuthStorageService } from '../../../shared/services/auth-storage.service'; import { FeatureTogglesService } from '../../../shared/services/feature-toggles.service'; +import { RefreshIntervalService } from '../../../shared/services/refresh-interval.service'; import { SharedModule } from '../../../shared/shared.module'; import { PgCategoryService } from '../../shared/pg-category.service'; import { HealthPieColor } from '../health-pie/health-pie-color.enum'; @@ -62,7 +63,8 @@ describe('HealthComponent', () => { providers: [ i18nProviders, { provide: AuthStorageService, useValue: fakeAuthStorageService }, - PgCategoryService + PgCategoryService, + RefreshIntervalService ] }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.ts index a722afebd7e..c5748642d35 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard/health/health.component.ts @@ -2,6 +2,7 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; import { I18n } from '@ngx-translate/i18n-polyfill'; import * as _ from 'lodash'; +import { Subscription } from 'rxjs/Subscription'; import { HealthService } from '../../../shared/api/health.service'; import { Permissions } from '../../../shared/models/permissions'; @@ -10,6 +11,7 @@ import { FeatureTogglesMap$, FeatureTogglesService } from '../../../shared/services/feature-toggles.service'; +import { RefreshIntervalService } from '../../../shared/services/refresh-interval.service'; import { PgCategoryService } from '../../shared/pg-category.service'; import { HealthPieColor } from '../health-pie/health-pie-color.enum'; @@ -20,7 +22,7 @@ import { HealthPieColor } from '../health-pie/health-pie-color.enum'; }) export class HealthComponent implements OnInit, OnDestroy { healthData: any; - interval: number; + interval = new Subscription(); permissions: Permissions; enabledFeature$: FeatureTogglesMap$; @@ -29,7 +31,8 @@ export class HealthComponent implements OnInit, OnDestroy { private i18n: I18n, private authStorageService: AuthStorageService, private pgCategoryService: PgCategoryService, - private featureToggles: FeatureTogglesService + private featureToggles: FeatureTogglesService, + private refreshIntervalService: RefreshIntervalService ) { this.permissions = this.authStorageService.getPermissions(); this.enabledFeature$ = this.featureToggles.get(); @@ -37,13 +40,13 @@ export class HealthComponent implements OnInit, OnDestroy { ngOnInit() { this.getHealth(); - this.interval = window.setInterval(() => { + this.interval = this.refreshIntervalService.intervalData$.subscribe(() => { this.getHealth(); - }, 5000); + }); } ngOnDestroy() { - clearInterval(this.interval); + this.interval.unsubscribe(); } getHealth() { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/components.module.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/components.module.ts index 02c54aa160c..517c5282331 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/components.module.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/components.module.ts @@ -20,6 +20,7 @@ import { InfoPanelComponent } from './info-panel/info-panel.component'; import { LanguageSelectorComponent } from './language-selector/language-selector.component'; import { LoadingPanelComponent } from './loading-panel/loading-panel.component'; import { ModalComponent } from './modal/modal.component'; +import { RefreshSelectorComponent } from './refresh-selector/refresh-selector.component'; import { SelectBadgesComponent } from './select-badges/select-badges.component'; import { SelectComponent } from './select/select.component'; import { SparklineComponent } from './sparkline/sparkline.component'; @@ -59,7 +60,8 @@ import { WarningPanelComponent } from './warning-panel/warning-panel.component'; WarningPanelComponent, LanguageSelectorComponent, GrafanaComponent, - SelectComponent + SelectComponent, + RefreshSelectorComponent ], providers: [], exports: [ @@ -76,7 +78,8 @@ import { WarningPanelComponent } from './warning-panel/warning-panel.component'; WarningPanelComponent, LanguageSelectorComponent, GrafanaComponent, - SelectComponent + SelectComponent, + RefreshSelectorComponent ], entryComponents: [ModalComponent, CriticalConfirmationModalComponent, ConfirmationModalComponent] }) diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/refresh-selector/refresh-selector.component.html b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/refresh-selector/refresh-selector.component.html new file mode 100644 index 00000000000..ce90465370a --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/refresh-selector/refresh-selector.component.html @@ -0,0 +1,18 @@ +
+
+ +
+ +
+
+
\ No newline at end of file diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/refresh-selector/refresh-selector.component.scss b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/refresh-selector/refresh-selector.component.scss new file mode 100644 index 00000000000..3440b874549 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/refresh-selector/refresh-selector.component.scss @@ -0,0 +1,26 @@ +.refresh-selector { + padding: 0; + float: right; + margin-right: 60px; + + * { + padding: 0; + box-sizing: border-box; + } + + label { + padding: 10px 10px 0 0; + text-align: right; + margin: 0; + } + + @media (min-width: 500px) and (max-width: 767px) { + width: 24vw; + } + @media (min-width: 1200px) { + width: 12vw; + } + @media (min-width: 1400px) { + width: 10vw; + } +} diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/refresh-selector/refresh-selector.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/refresh-selector/refresh-selector.component.spec.ts new file mode 100644 index 00000000000..87389fcc090 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/refresh-selector/refresh-selector.component.spec.ts @@ -0,0 +1,28 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormsModule } from '@angular/forms'; + +import { configureTestBed } from '../../../../testing/unit-test-helper'; + +import { RefreshIntervalService } from '../../services/refresh-interval.service'; +import { RefreshSelectorComponent } from './refresh-selector.component'; + +describe('RefreshSelectorComponent', () => { + let component: RefreshSelectorComponent; + let fixture: ComponentFixture; + + configureTestBed({ + imports: [FormsModule], + declarations: [RefreshSelectorComponent], + providers: [RefreshIntervalService] + }); + + beforeEach(() => { + fixture = TestBed.createComponent(RefreshSelectorComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/refresh-selector/refresh-selector.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/refresh-selector/refresh-selector.component.ts new file mode 100644 index 00000000000..632ddf6fd89 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/refresh-selector/refresh-selector.component.ts @@ -0,0 +1,32 @@ +import { Component, OnInit } from '@angular/core'; + +import { RefreshIntervalService } from '../../services/refresh-interval.service'; + +@Component({ + selector: 'cd-refresh-selector', + templateUrl: './refresh-selector.component.html', + styleUrls: ['./refresh-selector.component.scss'] +}) +export class RefreshSelectorComponent implements OnInit { + selectedInterval: number; + intervalList: { [key: string]: number } = { + '5 s': 5000, + '10 s': 10000, + '15 s': 15000, + '30 s': 30000, + '1 min': 60000, + '3 min': 180000, + '5 min': 300000 + }; + intervalKeys = Object.keys(this.intervalList); + + constructor(private refreshIntervalService: RefreshIntervalService) {} + + ngOnInit() { + this.selectedInterval = this.refreshIntervalService.getRefreshInterval() || 5000; + } + + changeRefreshInterval(interval: number) { + this.refreshIntervalService.setRefreshInterval(interval); + } +} diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/services/refresh-interval.service.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/refresh-interval.service.spec.ts new file mode 100644 index 00000000000..da55b44fd60 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/refresh-interval.service.spec.ts @@ -0,0 +1,45 @@ +import { fakeAsync, tick } from '@angular/core/testing'; + +import { RefreshIntervalService } from './refresh-interval.service'; + +describe('RefreshIntervalService', () => { + let service: RefreshIntervalService; + + beforeEach(() => { + service = new RefreshIntervalService(); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); + + it('should initial private interval time right', () => { + sessionStorage.setItem('dashboard_interval', '10000'); + service = new RefreshIntervalService(); + expect(service.getRefreshInterval()).toBe(10000); + }); + + describe('setRefreshInterval', () => { + let notifyCount: number; + + it('should send notification to component at correct interval time when interval changed', fakeAsync(() => { + service.intervalData$.subscribe(() => { + notifyCount++; + }); + + notifyCount = 0; + service.setRefreshInterval(10000); + tick(10000); + expect(service.getRefreshInterval()).toBe(10000); + expect(notifyCount).toBe(1); + + notifyCount = 0; + service.setRefreshInterval(30000); + tick(30000); + expect(service.getRefreshInterval()).toBe(30000); + expect(notifyCount).toBe(1); + + service.ngOnDestroy(); + })); + }); +}); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/services/refresh-interval.service.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/refresh-interval.service.ts new file mode 100644 index 00000000000..4cc846acdb9 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/refresh-interval.service.ts @@ -0,0 +1,43 @@ +import { Injectable, OnDestroy } from '@angular/core'; + +import { BehaviorSubject, interval, Subscription } from 'rxjs'; + +import { ServicesModule } from './services.module'; +@Injectable({ + providedIn: ServicesModule +}) +export class RefreshIntervalService implements OnDestroy { + private intervalTime: number; + // Observable sources + private intervalDataSource = new BehaviorSubject(null); + private intervalSubscription: Subscription; + // Observable streams + intervalData$ = this.intervalDataSource.asObservable(); + + constructor() { + const initialInterval = parseInt(sessionStorage.getItem('dashboard_interval'), 10) || 5000; + this.setRefreshInterval(initialInterval); + } + + setRefreshInterval(newInterval: number) { + this.intervalTime = newInterval; + sessionStorage.setItem('dashboard_interval', newInterval.toString()); + + if (this.intervalSubscription) { + this.intervalSubscription.unsubscribe(); + } + this.intervalSubscription = interval(this.intervalTime).subscribe(() => + this.intervalDataSource.next(this.intervalTime) + ); + } + + getRefreshInterval() { + return this.intervalTime; + } + + ngOnDestroy() { + if (this.intervalSubscription) { + this.intervalSubscription.unsubscribe(); + } + } +} diff --git a/src/pybind/mgr/dashboard/frontend/src/locale/messages.xlf b/src/pybind/mgr/dashboard/frontend/src/locale/messages.xlf index 8f404a7f4fc..127290d7714 100644 --- a/src/pybind/mgr/dashboard/frontend/src/locale/messages.xlf +++ b/src/pybind/mgr/dashboard/frontend/src/locale/messages.xlf @@ -322,6 +322,12 @@ app/shared/components/grafana/grafana.component.html 35 + + Refresh + + app/shared/components/refresh-selector/refresh-selector.component.html + 5 + Failed to load data. @@ -1751,13 +1757,13 @@ Health app/ceph/dashboard/dashboard/dashboard.component.html - 4 + 5 Statistics app/ceph/dashboard/dashboard/dashboard.component.html - 8 + 9 Please consult the documentation -- 2.47.3