From e12702a6c71d2050fe3f3991173a60332c5d583a Mon Sep 17 00:00:00 2001 From: Tiago Melo Date: Thu, 30 Jul 2020 20:31:13 +0000 Subject: [PATCH] mgr/dashboard: Extract documentation link to a component Fixes: https://tracker.ceph.com/issues/36565 Fixes: https://tracker.ceph.com/issues/43375 Signed-off-by: Tiago Melo --- .../iscsi-target-list.component.html | 5 +- .../iscsi-target-list.component.ts | 11 +-- .../cluster/inventory/inventory.component.ts | 1 - .../osd/osd-form/osd-form.component.ts | 1 - .../active-alert-list.component.html | 8 +-- .../active-alert-list.component.ts | 8 +-- .../prometheus/prometheus-list-helper.ts | 13 +--- .../rules-list/rules-list.component.html | 4 +- .../rules-list/rules-list.component.ts | 8 +-- .../silence-list/silence-list.component.html | 8 +-- .../silence-list/silence-list.component.ts | 8 +-- .../cluster/services/services.component.ts | 1 - .../ceph/nfs/nfs-501/nfs-501.component.html | 5 +- .../app/ceph/nfs/nfs-501/nfs-501.component.ts | 17 +---- .../ceph/nfs/nfs-form/nfs-form.component.html | 5 +- .../ceph/nfs/nfs-form/nfs-form.component.ts | 10 --- .../pool/pool-form/pool-form.component.html | 6 +- .../ceph/rgw/rgw-501/rgw-501.component.html | 5 +- .../app/ceph/rgw/rgw-501/rgw-501.component.ts | 17 +---- .../dashboard-help.component.html | 3 +- .../dashboard-help.component.ts | 13 ++-- .../shared/components/components.module.ts | 7 +- .../shared/components/doc/doc.component.html | 2 + .../shared/components/doc/doc.component.scss | 0 .../components/doc/doc.component.spec.ts | 27 ++++++++ .../shared/components/doc/doc.component.ts | 23 +++++++ .../components/grafana/grafana.component.html | 10 +-- .../grafana/grafana.component.spec.ts | 3 +- .../components/grafana/grafana.component.ts | 18 +---- .../orchestrator-doc-panel.component.html | 7 +- .../orchestrator-doc-panel.component.ts | 21 +----- .../app/shared/services/doc.service.spec.ts | 69 +++++++++++++++++++ .../src/app/shared/services/doc.service.ts | 57 +++++++++++++++ 33 files changed, 229 insertions(+), 172 deletions(-) create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/shared/components/doc/doc.component.html create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/shared/components/doc/doc.component.scss create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/shared/components/doc/doc.component.spec.ts create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/shared/components/doc/doc.component.ts create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/shared/services/doc.service.spec.ts create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/shared/services/doc.service.ts diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-list/iscsi-target-list.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-list/iscsi-target-list.component.html index 276629cd413..0103c11249a 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-list/iscsi-target-list.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-list/iscsi-target-list.component.html @@ -4,9 +4,8 @@ *ngIf="available === false" title="iSCSI Targets not available" i18n-title> - Please consult the documentation - on how to configure and enable the iSCSI Targets management functionality. + Please consult the on + how to configure and enable the iSCSI Targets management functionality.
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-list/iscsi-target-list.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-list/iscsi-target-list.component.ts index dd96295ca0e..686b1ba4589 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-list/iscsi-target-list.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-list/iscsi-target-list.component.ts @@ -17,11 +17,9 @@ import { CdTableSelection } from '../../../shared/models/cd-table-selection'; import { FinishedTask } from '../../../shared/models/finished-task'; import { Permission } from '../../../shared/models/permissions'; import { Task } from '../../../shared/models/task'; -import { CephReleaseNamePipe } from '../../../shared/pipes/ceph-release-name.pipe'; import { NotAvailablePipe } from '../../../shared/pipes/not-available.pipe'; import { AuthStorageService } from '../../../shared/services/auth-storage.service'; import { ModalService } from '../../../shared/services/modal.service'; -import { SummaryService } from '../../../shared/services/summary.service'; import { TaskListService } from '../../../shared/services/task-list.service'; import { TaskWrapperService } from '../../../shared/services/task-wrapper.service'; import { IscsiTargetDiscoveryModalComponent } from '../iscsi-target-discovery-modal/iscsi-target-discovery-modal.component'; @@ -38,7 +36,6 @@ export class IscsiTargetListComponent extends ListWithDetails implements OnInit, available: boolean = undefined; columns: CdTableColumn[]; - docsUrl: string; modalRef: NgbModalRef; permission: Permission; selection = new CdTableSelection(); @@ -62,9 +59,7 @@ export class IscsiTargetListComponent extends ListWithDetails implements OnInit, private authStorageService: AuthStorageService, private iscsiService: IscsiService, private taskListService: TaskListService, - private cephReleaseNamePipe: CephReleaseNamePipe, private notAvailablePipe: NotAvailablePipe, - private summaryservice: SummaryService, private modalService: ModalService, private taskWrapper: TaskWrapperService, public actionLabels: ActionLabelsI18n @@ -145,11 +140,7 @@ export class IscsiTargetListComponent extends ListWithDetails implements OnInit, this.settings = settings; }); } else { - this.summaryservice.subscribeOnce((summary) => { - const releaseName = this.cephReleaseNamePipe.transform(summary.version); - this.docsUrl = `http://docs.ceph.com/docs/${releaseName}/mgr/dashboard/#enabling-iscsi-management`; - this.status = result.message; - }); + this.status = result.message; } }); } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/inventory/inventory.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/inventory/inventory.component.ts index a529924d93e..da0f1a541a1 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/inventory/inventory.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/inventory/inventory.component.ts @@ -16,7 +16,6 @@ export class InventoryComponent implements OnChanges, OnInit { icons = Icons; hasOrchestrator = false; - docsUrl: string; devices: Array = []; diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-form/osd-form.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-form/osd-form.component.ts index 7a3538e6e20..651ae814ffa 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-form/osd-form.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-form/osd-form.component.ts @@ -60,7 +60,6 @@ export class OsdFormComponent extends CdForm implements OnInit { featureList: OsdFeature[] = []; hasOrchestrator = true; - docsUrl: string; constructor( public actionLabels: ActionLabelsI18n, diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/active-alert-list/active-alert-list.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/active-alert-list/active-alert-list.component.html index 8f9605b5bb2..278bc4ddc46 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/active-alert-list/active-alert-list.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/active-alert-list/active-alert-list.component.html @@ -2,11 +2,9 @@ To see all active Prometheus alerts, please - provide the URL to the API of Prometheus' Alertmanager as described - in the documentation. - + i18n>To see all active Prometheus alerts, please provide + the URL to the API of Prometheus' Alertmanager as described + in the . { this.isPrometheusConfigured = true; }); - this.summaryService.subscribeOnce((summary) => { - const releaseName = this.cephReleaseNamePipe.transform(summary.version); - this.docsUrl = `https://docs.ceph.com/docs/${releaseName}/mgr/dashboard/#enabling-prometheus-alerting`; - }); } } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/rules-list/rules-list.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/rules-list/rules-list.component.html index 8600c3df2ec..0066784a864 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/rules-list/rules-list.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/rules-list/rules-list.component.html @@ -4,9 +4,7 @@ type="info" i18n>To see all configured Prometheus alerts, please provide the URL to the API of Prometheus as described in - the documentation. - + the . To enable Silences, please provide the URL to the - API of the Prometheus' Alertmanager as described in - the documentation. - + i18n>To enable Silences, please provide the URL to + the API of the Prometheus' Alertmanager as described in the + . selection.first() && selection.first().status && selection.first().status.state === 'expired'; diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/services/services.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/services/services.component.ts index 48f5acc293d..2f825874f94 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/services/services.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/services/services.component.ts @@ -30,7 +30,6 @@ export class ServicesComponent extends ListWithDetails implements OnChanges, OnI checkingOrchestrator = true; hasOrchestrator = false; - docsUrl: string; columns: Array = []; services: Array = []; diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/nfs/nfs-501/nfs-501.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/nfs/nfs-501/nfs-501.component.html index dae183db0d6..bcbb8812542 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/nfs/nfs-501/nfs-501.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/nfs/nfs-501/nfs-501.component.html @@ -1,6 +1,5 @@ {{ message }}
- Please consult the documentation - on how to configure and enable the NFS Ganesha management functionality. + Please consult the on how + to configure and enable the NFS Ganesha management functionality.
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/nfs/nfs-501/nfs-501.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/nfs/nfs-501/nfs-501.component.ts index 4654a5ca5c6..7f917229465 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/nfs/nfs-501/nfs-501.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/nfs/nfs-501/nfs-501.component.ts @@ -1,33 +1,18 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { CephReleaseNamePipe } from '../../../shared/pipes/ceph-release-name.pipe'; -import { SummaryService } from '../../../shared/services/summary.service'; - @Component({ selector: 'cd-nfs-501', templateUrl: './nfs-501.component.html', styleUrls: ['./nfs-501.component.scss'] }) export class Nfs501Component implements OnInit, OnDestroy { - docsUrl: string; message = $localize`The NFS Ganesha service is not configured.`; routeParamsSubscribe: any; - constructor( - private route: ActivatedRoute, - private summaryService: SummaryService, - private cephReleaseNamePipe: CephReleaseNamePipe - ) {} + constructor(private route: ActivatedRoute) {} ngOnInit() { - this.summaryService.subscribeOnce((summary) => { - const releaseName = this.cephReleaseNamePipe.transform(summary.version); - this.docsUrl = - `http://docs.ceph.com/docs/${releaseName}/mgr/dashboard/` + - `#configuring-nfs-ganesha-in-the-dashboard`; - }); - this.routeParamsSubscribe = this.route.params.subscribe((params: { message: string }) => { this.message = params.message; }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/nfs/nfs-form/nfs-form.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/nfs/nfs-form/nfs-form.component.html index f7d02b03bac..a8b978c4f7a 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/nfs/nfs-form/nfs-form.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/nfs/nfs-form/nfs-form.component.html @@ -405,9 +405,8 @@ *ngIf="nfsForm.getValue('access_type') === 'RW' && nfsForm.getValue('name') === 'RGW'" i18n>The Object Gateway NFS backend has a number of limitations which will seriously affect applications writing to - the share. Please consult the - documentation for details before enabling write access. + the share. Please consult the + for details before enabling write access. This field is required. diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/nfs/nfs-form/nfs-form.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/nfs/nfs-form/nfs-form.component.ts index 4a62907fbec..7e4abf6c171 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/nfs/nfs-form/nfs-form.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/nfs/nfs-form/nfs-form.component.ts @@ -18,9 +18,7 @@ import { CdFormGroup } from '../../../shared/forms/cd-form-group'; import { CdValidators } from '../../../shared/forms/cd-validators'; import { FinishedTask } from '../../../shared/models/finished-task'; import { Permission } from '../../../shared/models/permissions'; -import { CephReleaseNamePipe } from '../../../shared/pipes/ceph-release-name.pipe'; import { AuthStorageService } from '../../../shared/services/auth-storage.service'; -import { SummaryService } from '../../../shared/services/summary.service'; import { TaskWrapperService } from '../../../shared/services/task-wrapper.service'; import { NfsFormClientComponent } from '../nfs-form-client/nfs-form-client.component'; @@ -61,7 +59,6 @@ export class NfsFormComponent extends CdForm implements OnInit { action: string; resource: string; - docsUrl: string; daemonsSelections: SelectOption[] = []; daemonsMessages = new SelectMessages({ noOptions: $localize`There are no daemons available.` }); @@ -90,8 +87,6 @@ export class NfsFormComponent extends CdForm implements OnInit { private router: Router, private rgwUserService: RgwUserService, private formBuilder: CdFormBuilder, - private summaryservice: SummaryService, - private cephReleaseNamePipe: CephReleaseNamePipe, private taskWrapper: TaskWrapperService, private cdRef: ChangeDetectorRef, public actionLabels: ActionLabelsI18n @@ -127,11 +122,6 @@ export class NfsFormComponent extends CdForm implements OnInit { this.action = this.actionLabels.CREATE; this.getData(promises); } - - this.summaryservice.subscribeOnce((summary) => { - const releaseName = this.cephReleaseNamePipe.transform(summary.version); - this.docsUrl = `http://docs.ceph.com/docs/${releaseName}/radosgw/nfs/`; - }); } getData(promises: Observable[]) { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-form/pool-form.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-form/pool-form.component.html index b21e94f8e1a..397c1829c9d 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-form/pool-form.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-form/pool-form.component.html @@ -107,9 +107,9 @@ *ngIf="form.showError('pgNum', formDir, '34')" i18n>Your cluster can't handle this many PGs. Please recalculate the PG amount needed. - Calculation help + {{ message }}
- Please consult the documentation - on how to configure and enable the Object Gateway management functionality. + Please consult the on how + to configure and enable the Object Gateway management functionality. diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-501/rgw-501.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-501/rgw-501.component.ts index 02fbc18cdc6..77bea30a6be 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-501/rgw-501.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-501/rgw-501.component.ts @@ -1,33 +1,18 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { CephReleaseNamePipe } from '../../../shared/pipes/ceph-release-name.pipe'; -import { SummaryService } from '../../../shared/services/summary.service'; - @Component({ selector: 'cd-rgw-501', templateUrl: './rgw-501.component.html', styleUrls: ['./rgw-501.component.scss'] }) export class Rgw501Component implements OnInit, OnDestroy { - docsUrl: string; message = 'The Object Gateway service is not configured.'; routeParamsSubscribe: any; - constructor( - private route: ActivatedRoute, - private summaryService: SummaryService, - private cephReleaseNamePipe: CephReleaseNamePipe - ) {} + constructor(private route: ActivatedRoute) {} ngOnInit() { - this.summaryService.subscribeOnce((summary) => { - const releaseName = this.cephReleaseNamePipe.transform(summary.version); - this.docsUrl = - `http://docs.ceph.com/docs/${releaseName}/mgr/dashboard/` + - `#enabling-the-object-gateway-management-frontend`; - }); - this.routeParamsSubscribe = this.route.params.subscribe((params: { message: string }) => { this.message = params.message; }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/dashboard-help/dashboard-help.component.html b/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/dashboard-help/dashboard-help.component.html index 7d092ccdd7d..161e1f0c3b0 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/dashboard-help/dashboard-help.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/dashboard-help/dashboard-help.component.html @@ -18,9 +18,10 @@
Documentation + i18n>documentation diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/dashboard-help/dashboard-help.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/dashboard-help/dashboard-help.component.ts index 8ec10466629..c5036e5b8dd 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/dashboard-help/dashboard-help.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/dashboard-help/dashboard-help.component.ts @@ -3,10 +3,9 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; import { Icons } from '../../../shared/enum/icons.enum'; -import { CephReleaseNamePipe } from '../../../shared/pipes/ceph-release-name.pipe'; import { AuthStorageService } from '../../../shared/services/auth-storage.service'; +import { DocService } from '../../../shared/services/doc.service'; import { ModalService } from '../../../shared/services/modal.service'; -import { SummaryService } from '../../../shared/services/summary.service'; import { AboutComponent } from '../about/about.component'; @Component({ @@ -22,16 +21,14 @@ export class DashboardHelpComponent implements OnInit { icons = Icons; constructor( - private summaryService: SummaryService, - private cephReleaseNamePipe: CephReleaseNamePipe, private modalService: ModalService, - private authStorageService: AuthStorageService + private authStorageService: AuthStorageService, + private docService: DocService ) {} ngOnInit() { - this.summaryService.subscribeOnce((summary) => { - const releaseName = this.cephReleaseNamePipe.transform(summary.version); - this.docsUrl = `http://docs.ceph.com/docs/${releaseName}/mgr/dashboard/`; + this.docService.subscribeOnce('dashboard', (url: string) => { + this.docsUrl = url; }); } 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 91731064080..52938b6ad10 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 @@ -25,6 +25,7 @@ import { ConfigOptionComponent } from './config-option/config-option.component'; import { ConfirmationModalComponent } from './confirmation-modal/confirmation-modal.component'; import { CriticalConfirmationModalComponent } from './critical-confirmation-modal/critical-confirmation-modal.component'; import { DateTimePickerComponent } from './date-time-picker/date-time-picker.component'; +import { DocComponent } from './doc/doc.component'; import { FormModalComponent } from './form-modal/form-modal.component'; import { GrafanaComponent } from './grafana/grafana.component'; import { HelperComponent } from './helper/helper.component'; @@ -87,7 +88,8 @@ import { UsageBarComponent } from './usage-bar/usage-bar.component'; TelemetryNotificationComponent, OrchestratorDocPanelComponent, OrchestratorDocModalComponent, - DateTimePickerComponent + DateTimePickerComponent, + DocComponent ], providers: [], exports: [ @@ -109,7 +111,8 @@ import { UsageBarComponent } from './usage-bar/usage-bar.component'; PwdExpirationNotificationComponent, TelemetryNotificationComponent, OrchestratorDocPanelComponent, - DateTimePickerComponent + DateTimePickerComponent, + DocComponent ] }) export class ComponentsModule {} diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/doc/doc.component.html b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/doc/doc.component.html new file mode 100644 index 00000000000..b90fedc0cf1 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/doc/doc.component.html @@ -0,0 +1,2 @@ +{{ docText }} diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/doc/doc.component.scss b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/doc/doc.component.scss new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/doc/doc.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/doc/doc.component.spec.ts new file mode 100644 index 00000000000..b66e63f3fe7 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/doc/doc.component.spec.ts @@ -0,0 +1,27 @@ +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { configureTestBed } from '../../../../testing/unit-test-helper'; +import { CephReleaseNamePipe } from '../../../shared/pipes/ceph-release-name.pipe'; +import { DocComponent } from './doc.component'; + +describe('DocComponent', () => { + let component: DocComponent; + let fixture: ComponentFixture; + + configureTestBed({ + declarations: [DocComponent], + imports: [HttpClientTestingModule], + providers: [CephReleaseNamePipe] + }); + + beforeEach(() => { + fixture = TestBed.createComponent(DocComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/doc/doc.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/doc/doc.component.ts new file mode 100644 index 00000000000..7bc2d3c8dd6 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/doc/doc.component.ts @@ -0,0 +1,23 @@ +import { Component, Input, OnInit } from '@angular/core'; + +import { DocService } from '../../../shared/services/doc.service'; + +@Component({ + selector: 'cd-doc', + templateUrl: './doc.component.html', + styleUrls: ['./doc.component.scss'] +}) +export class DocComponent implements OnInit { + @Input() section: string; + @Input() docText = $localize`documentation`; + + docUrl: string; + + constructor(private docService: DocService) {} + + ngOnInit() { + this.docService.subscribeOnce(this.section, (url: string) => { + this.docUrl = url; + }); + } +} diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.html b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.html index d6ac94af42a..a5a29bfbee8 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.html @@ -4,17 +4,13 @@ Please consult the - documentation on how to - configure and enable the monitoring functionality. + i18n>Please consult the on + how to configure and enable the monitoring functionality. Grafana Dashboard doesn't exist. Please refer to - documentation on how to - add dashboards to Grafana. + on how to add dashboards to Grafana.
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.spec.ts index fb7747cabf5..f597f6074f4 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.spec.ts @@ -11,6 +11,7 @@ import { SummaryService } from '../../../shared/services/summary.service'; import { SettingsService } from '../../api/settings.service'; import { CephReleaseNamePipe } from '../../pipes/ceph-release-name.pipe'; import { AlertPanelComponent } from '../alert-panel/alert-panel.component'; +import { DocComponent } from '../doc/doc.component'; import { LoadingPanelComponent } from '../loading-panel/loading-panel.component'; import { GrafanaComponent } from './grafana.component'; @@ -19,7 +20,7 @@ describe('GrafanaComponent', () => { let fixture: ComponentFixture; configureTestBed({ - declarations: [GrafanaComponent, AlertPanelComponent, LoadingPanelComponent], + declarations: [GrafanaComponent, AlertPanelComponent, LoadingPanelComponent, DocComponent], imports: [NgbAlertModule, HttpClientTestingModule, RouterTestingModule, FormsModule], providers: [CephReleaseNamePipe, SettingsService, SummaryService] }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.ts index 827210ccb6b..18649d48870 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/grafana/grafana.component.ts @@ -2,8 +2,6 @@ import { Component, Input, OnChanges, OnInit } from '@angular/core'; import { DomSanitizer, SafeUrl } from '@angular/platform-browser'; import { Icons } from '../../../shared/enum/icons.enum'; -import { CephReleaseNamePipe } from '../../../shared/pipes/ceph-release-name.pipe'; -import { SummaryService } from '../../../shared/services/summary.service'; import { SettingsService } from '../../api/settings.service'; @Component({ @@ -36,14 +34,7 @@ export class GrafanaComponent implements OnInit, OnChanges { @Input() uid: string; - docsUrl: string; - - constructor( - private summaryService: SummaryService, - private sanitizer: DomSanitizer, - private settingsService: SettingsService, - private cephReleaseNamePipe: CephReleaseNamePipe - ) { + constructor(private sanitizer: DomSanitizer, private settingsService: SettingsService) { this.grafanaTimes = [ { name: $localize`Last 5 minutes`, @@ -176,13 +167,6 @@ export class GrafanaComponent implements OnInit, OnChanges { three: 'grafana_three' }; - this.summaryService.subscribeOnce((summary) => { - const releaseName = this.cephReleaseNamePipe.transform(summary.version); - this.docsUrl = - `http://docs.ceph.com/docs/${releaseName}/mgr/dashboard/` + - `#enabling-the-embedding-of-grafana-dashboards`; - }); - this.settingsService.ifSettingConfigured('api/grafana/url', (url) => { this.grafanaExist = true; this.loading = false; diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/orchestrator-doc-panel/orchestrator-doc-panel.component.html b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/orchestrator-doc-panel/orchestrator-doc-panel.component.html index 5159177ab50..4c7175910b0 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/orchestrator-doc-panel/orchestrator-doc-panel.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/orchestrator-doc-panel/orchestrator-doc-panel.component.html @@ -1,5 +1,4 @@ Orchestrator is not available. Please consult the - documentation on how to - configure and enable the functionality. + i18n>Orchestrator is not available. + Please consult the on how to configure and + enable the functionality. diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/orchestrator-doc-panel/orchestrator-doc-panel.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/orchestrator-doc-panel/orchestrator-doc-panel.component.ts index d4728bce702..71c94ec7fac 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/orchestrator-doc-panel/orchestrator-doc-panel.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/orchestrator-doc-panel/orchestrator-doc-panel.component.ts @@ -1,25 +1,8 @@ -import { Component, OnInit } from '@angular/core'; - -import { CephReleaseNamePipe } from '../../pipes/ceph-release-name.pipe'; -import { SummaryService } from '../../services/summary.service'; +import { Component } from '@angular/core'; @Component({ selector: 'cd-orchestrator-doc-panel', templateUrl: './orchestrator-doc-panel.component.html', styleUrls: ['./orchestrator-doc-panel.component.scss'] }) -export class OrchestratorDocPanelComponent implements OnInit { - docsUrl: string; - - constructor( - private cephReleaseNamePipe: CephReleaseNamePipe, - private summaryService: SummaryService - ) {} - - ngOnInit() { - this.summaryService.subscribeOnce((summary) => { - const releaseName = this.cephReleaseNamePipe.transform(summary.version); - this.docsUrl = `http://docs.ceph.com/docs/${releaseName}/mgr/orchestrator/`; - }); - } -} +export class OrchestratorDocPanelComponent {} diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/services/doc.service.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/doc.service.spec.ts new file mode 100644 index 00000000000..db0825e6d1b --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/doc.service.spec.ts @@ -0,0 +1,69 @@ +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { TestBed } from '@angular/core/testing'; + +import { Subscriber } from 'rxjs'; + +import { configureTestBed } from '../../../testing/unit-test-helper'; +import { SharedModule } from '../shared.module'; +import { DocService } from './doc.service'; + +describe('DocService', () => { + let service: DocService; + + configureTestBed({ imports: [HttpClientTestingModule, SharedModule] }); + + beforeEach(() => { + service = TestBed.inject(DocService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); + + it('should return full URL', () => { + expect(service.urlGenerator('foo', 'iscsi')).toBe( + 'http://docs.ceph.com/docs/foo/mgr/dashboard/#enabling-iscsi-management' + ); + }); + + describe('Name of the group', () => { + let result: string; + let i: number; + + const nextSummary = (newData: any) => service['releaseDataSource'].next(newData); + + const callback = (response: string) => { + i++; + result = response; + }; + + beforeEach(() => { + i = 0; + result = undefined; + nextSummary(undefined); + }); + + it('should call subscribeOnce without releaseName', () => { + const subscriber = service.subscribeOnce('prometheus', callback); + + expect(subscriber).toEqual(jasmine.any(Subscriber)); + expect(i).toBe(0); + expect(result).toEqual(undefined); + }); + + it('should call subscribeOnce with releaseName', () => { + const subscriber = service.subscribeOnce('prometheus', callback); + + expect(subscriber).toEqual(jasmine.any(Subscriber)); + expect(i).toBe(0); + expect(result).toEqual(undefined); + + nextSummary('foo'); + expect(result).toEqual( + 'http://docs.ceph.com/docs/foo/mgr/dashboard/#enabling-prometheus-alerting' + ); + expect(i).toBe(1); + expect(subscriber.closed).toBe(true); + }); + }); +}); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/services/doc.service.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/doc.service.ts new file mode 100644 index 00000000000..4d3ab0f6fd1 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/doc.service.ts @@ -0,0 +1,57 @@ +import { Injectable } from '@angular/core'; + +import { BehaviorSubject, Subscription } from 'rxjs'; +import { filter, first, map } from 'rxjs/operators'; + +import { CephReleaseNamePipe } from '../pipes/ceph-release-name.pipe'; +import { SummaryService } from './summary.service'; + +@Injectable({ + providedIn: 'root' +}) +export class DocService { + private releaseDataSource = new BehaviorSubject(null); + releaseData$ = this.releaseDataSource.asObservable(); + + constructor( + private summaryservice: SummaryService, + private cephReleaseNamePipe: CephReleaseNamePipe + ) { + this.summaryservice.subscribeOnce((summary) => { + const releaseName = this.cephReleaseNamePipe.transform(summary.version); + this.releaseDataSource.next(releaseName); + }); + } + + urlGenerator(release: string, section: string): string { + const domain = `http://docs.ceph.com/docs/${release}/`; + + const sections = { + iscsi: `${domain}mgr/dashboard/#enabling-iscsi-management`, + prometheus: `${domain}mgr/dashboard/#enabling-prometheus-alerting`, + 'nfs-ganesha': `${domain}mgr/dashboard/#configuring-nfs-ganesha-in-the-dashboard`, + 'rgw-nfs': `${domain}radosgw/nfs`, + rgw: `${domain}mgr/dashboard/#enabling-the-object-gateway-management-frontend`, + dashboard: `${domain}mgr/dashboard`, + grafana: `${domain}mgr/dashboard/#enabling-the-embedding-of-grafana-dashboards`, + orch: `${domain}mgr/orchestrator`, + pgs: `http://ceph.com/pgcalc` + }; + + return sections[section]; + } + + subscribeOnce( + section: string, + next: (release: string) => void, + error?: (error: any) => void + ): Subscription { + return this.releaseData$ + .pipe( + filter((value) => !!value), + map((release) => this.urlGenerator(release, section)), + first() + ) + .subscribe(next, error); + } +} -- 2.39.5