]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: Add Orchestrator doc components
authorKiefer Chang <kiefer.chang@suse.com>
Mon, 23 Dec 2019 08:03:10 +0000 (16:03 +0800)
committerKiefer Chang <kiefer.chang@suse.com>
Wed, 11 Mar 2020 06:19:43 +0000 (14:19 +0800)
Create two components for redirecting to Orchestrator Documents:
- cd-orchestrator-doc-panel: For displaying an information panel
- cd-orchestrator-doc-modal: For displaying an modal contains the
information panel

Signed-off-by: Kiefer Chang <kiefer.chang@suse.com>
13 files changed:
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/cluster.module.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/api/orchestrator.service.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/components/components.module.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/components/orchestrator-doc-modal/orchestrator-doc-modal.component.html [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/shared/components/orchestrator-doc-modal/orchestrator-doc-modal.component.scss [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/shared/components/orchestrator-doc-modal/orchestrator-doc-modal.component.spec.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/shared/components/orchestrator-doc-modal/orchestrator-doc-modal.component.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/shared/components/orchestrator-doc-panel/orchestrator-doc-panel.component.html [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/shared/components/orchestrator-doc-panel/orchestrator-doc-panel.component.scss [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/shared/components/orchestrator-doc-panel/orchestrator-doc-panel.component.spec.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/shared/components/orchestrator-doc-panel/orchestrator-doc-panel.component.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/shared/services/dep-checker.service.spec.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/shared/services/dep-checker.service.ts [new file with mode: 0644]

index 53aae8e28d376de50605214aeef8cbcaa9d4e246..a08d669044b7e529354ba62cf6bb3019115921e9 100644 (file)
@@ -14,6 +14,7 @@ import { TimepickerModule } from 'ngx-bootstrap/timepicker';
 import { TooltipModule } from 'ngx-bootstrap/tooltip';
 import { TypeaheadModule } from 'ngx-bootstrap/typeahead';
 
+import { OrchestratorDocModalComponent } from '../../shared/components/orchestrator-doc-modal/orchestrator-doc-modal.component';
 import { SharedModule } from '../../shared/shared.module';
 import { PerformanceCounterModule } from '../performance-counter/performance-counter.module';
 import { CephSharedModule } from '../shared/ceph-shared.module';
@@ -62,7 +63,8 @@ import { ServicesComponent } from './services/services.component';
     OsdReweightModalComponent,
     SilenceMatcherModalComponent,
     OsdDevicesSelectionModalComponent,
-    OsdCreationPreviewModalComponent
+    OsdCreationPreviewModalComponent,
+    OrchestratorDocModalComponent
   ],
   imports: [
     CommonModule,
index 6fbd44d2fa5d5e675b4f45e081f837ecaa151d01..cea8d4bccd93bfc7d408ff33b888cbfb6e308511 100644 (file)
@@ -17,8 +17,8 @@ export class OrchestratorService {
 
   constructor(private http: HttpClient) {}
 
-  status() {
-    return this.http.get(`${this.url}/status`);
+  status(): Observable<{ available: boolean; description: string }> {
+    return this.http.get<{ available: boolean; description: string }>(`${this.url}/status`);
   }
 
   identifyDevice(hostname: string, device: string, duration: number) {
index 6c729a85858df81782857c21098092b216a9402c..db8b6364e29df9d9e772c59ac538ddd53f87eba7 100644 (file)
@@ -28,6 +28,8 @@ import { LanguageSelectorComponent } from './language-selector/language-selector
 import { LoadingPanelComponent } from './loading-panel/loading-panel.component';
 import { ModalComponent } from './modal/modal.component';
 import { NotificationsSidebarComponent } from './notifications-sidebar/notifications-sidebar.component';
+import { OrchestratorDocModalComponent } from './orchestrator-doc-modal/orchestrator-doc-modal.component';
+import { OrchestratorDocPanelComponent } from './orchestrator-doc-panel/orchestrator-doc-panel.component';
 import { PwdExpirationNotificationComponent } from './pwd-expiration-notification/pwd-expiration-notification.component';
 import { RefreshSelectorComponent } from './refresh-selector/refresh-selector.component';
 import { SelectBadgesComponent } from './select-badges/select-badges.component';
@@ -77,7 +79,9 @@ import { ViewCacheComponent } from './view-cache/view-cache.component';
     ConfigOptionComponent,
     AlertPanelComponent,
     FormModalComponent,
-    PwdExpirationNotificationComponent
+    PwdExpirationNotificationComponent,
+    OrchestratorDocPanelComponent,
+    OrchestratorDocModalComponent
   ],
   providers: [],
   exports: [
@@ -97,7 +101,8 @@ import { ViewCacheComponent } from './view-cache/view-cache.component';
     RefreshSelectorComponent,
     ConfigOptionComponent,
     AlertPanelComponent,
-    PwdExpirationNotificationComponent
+    PwdExpirationNotificationComponent,
+    OrchestratorDocPanelComponent
   ],
   entryComponents: [
     ModalComponent,
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/orchestrator-doc-modal/orchestrator-doc-modal.component.html b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/orchestrator-doc-modal/orchestrator-doc-modal.component.html
new file mode 100644 (file)
index 0000000..a205f71
--- /dev/null
@@ -0,0 +1,16 @@
+<cd-modal [modalRef]="bsModalRef">
+  <ng-container class="modal-title"
+                i18n>{{ actionDescription }} {{ itemDescription }}</ng-container>
+
+  <ng-container class="modal-content">
+    <div class="modal-body">
+      <cd-orchestrator-doc-panel></cd-orchestrator-doc-panel>
+    </div>
+    <div class="modal-footer">
+      <cd-back-button [back]="bsModalRef.hide"
+                      name="Close"
+                      i18n-name>
+      </cd-back-button>
+    </div>
+  </ng-container>
+</cd-modal>
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/orchestrator-doc-modal/orchestrator-doc-modal.component.scss b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/orchestrator-doc-modal/orchestrator-doc-modal.component.scss
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/orchestrator-doc-modal/orchestrator-doc-modal.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/orchestrator-doc-modal/orchestrator-doc-modal.component.spec.ts
new file mode 100644 (file)
index 0000000..49fe438
--- /dev/null
@@ -0,0 +1,29 @@
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { RouterTestingModule } from '@angular/router/testing';
+
+import { BsModalRef } from 'ngx-bootstrap/modal';
+
+import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper';
+import { ComponentsModule } from '../components.module';
+import { OrchestratorDocModalComponent } from './orchestrator-doc-modal.component';
+
+describe('OrchestratorDocModalComponent', () => {
+  let component: OrchestratorDocModalComponent;
+  let fixture: ComponentFixture<OrchestratorDocModalComponent>;
+
+  configureTestBed({
+    imports: [ComponentsModule, HttpClientTestingModule, RouterTestingModule],
+    providers: [BsModalRef, i18nProviders]
+  });
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(OrchestratorDocModalComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/orchestrator-doc-modal/orchestrator-doc-modal.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/orchestrator-doc-modal/orchestrator-doc-modal.component.ts
new file mode 100644 (file)
index 0000000..91463bf
--- /dev/null
@@ -0,0 +1,21 @@
+import { Component, OnInit } from '@angular/core';
+
+import { BsModalRef } from 'ngx-bootstrap/modal';
+
+@Component({
+  selector: 'cd-orchestrator-doc-modal',
+  templateUrl: './orchestrator-doc-modal.component.html',
+  styleUrls: ['./orchestrator-doc-modal.component.scss']
+})
+export class OrchestratorDocModalComponent implements OnInit {
+  actionDescription: string;
+  itemDescription: string;
+
+  constructor(public bsModalRef: BsModalRef) {}
+
+  ngOnInit() {}
+
+  onSubmit() {
+    this.bsModalRef.hide();
+  }
+}
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
new file mode 100644 (file)
index 0000000..5159177
--- /dev/null
@@ -0,0 +1,5 @@
+<cd-alert-panel type="info"
+                i18n>Orchestrator is not available. Please consult the
+  <a href="{{ docsUrl }}"
+     target="_blank">documentation</a> on how to
+  configure and enable the functionality.</cd-alert-panel>
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/orchestrator-doc-panel/orchestrator-doc-panel.component.scss b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/orchestrator-doc-panel/orchestrator-doc-panel.component.scss
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/orchestrator-doc-panel/orchestrator-doc-panel.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/orchestrator-doc-panel/orchestrator-doc-panel.component.spec.ts
new file mode 100644 (file)
index 0000000..e2c7935
--- /dev/null
@@ -0,0 +1,29 @@
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { RouterTestingModule } from '@angular/router/testing';
+
+import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper';
+import { CephReleaseNamePipe } from '../../pipes/ceph-release-name.pipe';
+import { SummaryService } from '../../services/summary.service';
+import { ComponentsModule } from '../components.module';
+import { OrchestratorDocPanelComponent } from './orchestrator-doc-panel.component';
+
+describe('OrchestratorDocPanelComponent', () => {
+  let component: OrchestratorDocPanelComponent;
+  let fixture: ComponentFixture<OrchestratorDocPanelComponent>;
+
+  configureTestBed({
+    imports: [ComponentsModule, HttpClientTestingModule, RouterTestingModule],
+    providers: [CephReleaseNamePipe, SummaryService, i18nProviders]
+  });
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(OrchestratorDocPanelComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
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
new file mode 100644 (file)
index 0000000..f2f8b1e
--- /dev/null
@@ -0,0 +1,33 @@
+import { Component, OnInit } from '@angular/core';
+
+import { CephReleaseNamePipe } from '../../pipes/ceph-release-name.pipe';
+import { SummaryService } from '../../services/summary.service';
+
+@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() {
+    const subs = this.summaryService.subscribe((summary: any) => {
+      if (!summary) {
+        return;
+      }
+
+      const releaseName = this.cephReleaseNamePipe.transform(summary.version);
+      this.docsUrl = `http://docs.ceph.com/docs/${releaseName}/mgr/orchestrator_cli/`;
+
+      setTimeout(() => {
+        subs.unsubscribe();
+      }, 0);
+    });
+  }
+}
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/services/dep-checker.service.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/dep-checker.service.spec.ts
new file mode 100644 (file)
index 0000000..7114f28
--- /dev/null
@@ -0,0 +1,20 @@
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { TestBed } from '@angular/core/testing';
+
+import { BsModalService, ModalModule } from 'ngx-bootstrap/modal';
+
+import { configureTestBed } from '../../../testing/unit-test-helper';
+import { OrchestratorService } from '../api/orchestrator.service';
+import { DepCheckerService } from './dep-checker.service';
+
+describe('DepCheckerService', () => {
+  configureTestBed({
+    providers: [BsModalService, DepCheckerService, OrchestratorService],
+    imports: [HttpClientTestingModule, ModalModule.forRoot()]
+  });
+
+  it('should be created', () => {
+    const service: DepCheckerService = TestBed.get(DepCheckerService);
+    expect(service).toBeTruthy();
+  });
+});
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/services/dep-checker.service.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/dep-checker.service.ts
new file mode 100644 (file)
index 0000000..84a0dfa
--- /dev/null
@@ -0,0 +1,36 @@
+import { Injectable } from '@angular/core';
+
+import { BsModalService } from 'ngx-bootstrap/modal';
+
+import { OrchestratorService } from '../api/orchestrator.service';
+import { OrchestratorDocModalComponent } from '../components/orchestrator-doc-modal/orchestrator-doc-modal.component';
+
+@Injectable({
+  providedIn: 'root'
+})
+export class DepCheckerService {
+  constructor(private orchService: OrchestratorService, private modalService: BsModalService) {}
+
+  /**
+   * Check if orchestrator is available. Display an information modal if not.
+   * If orchestrator is available, then the provided function will be called.
+   * This helper function can be used with table actions.
+   * @param {string} actionDescription name of the action.
+   * @param {string} itemDescription the item's name that the action operates on.
+   * @param {Function} func the function to be called if orchestrator is available.
+   */
+  checkOrchestratorOrModal(actionDescription: string, itemDescription: string, func: Function) {
+    this.orchService.status().subscribe((status) => {
+      if (status.available) {
+        func();
+      } else {
+        this.modalService.show(OrchestratorDocModalComponent, {
+          initialState: {
+            actionDescription: actionDescription,
+            itemDescription: itemDescription
+          }
+        });
+      }
+    });
+  }
+}