From: Courtney Caldwell Date: Tue, 15 Dec 2020 16:41:18 +0000 (-0500) Subject: mgr/dashboard: replace cdCopy2ClipboardButton Directive with a component X-Git-Tag: v16.1.0~254^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=065fbf96036cdac05d88f49a479c3ddce8661b1a;p=ceph.git mgr/dashboard: replace cdCopy2ClipboardButton Directive with a component Replaces Directive-Based copy2ClipboardButton with a Component-based version. Further replaces all instances of Directive use with Component version. Similar toastr logic used. Fixes: https://tracker.ceph.com/issues/44960 Signed-off-by: Courtney Caldwell --- diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html index c7724e9ec9a9..d84ea787f139 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-discovery-modal/iscsi-target-discovery-modal.component.html @@ -48,10 +48,8 @@ class="btn btn-light" cdPasswordButton="password"> - + + - + + - + + @@ -311,10 +309,8 @@ class="btn btn-light" cdPasswordButton="target_mutual_password"> - + + @@ -418,10 +414,8 @@ class="btn btn-light" [cdPasswordButton]="'password' + ii"> - + + - + + - + +

@@ -50,10 +50,10 @@ [textItem]="logText" fileName="audit_log"> - + +

diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/services/service-form/service-form.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/services/service-form/service-form.component.html index 6f9d47ce4210..e2d4f01140cc 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/services/service-form/service-form.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/services/service-form/service-form.component.html @@ -319,10 +319,8 @@ class="btn btn-light" cdPasswordButton="api_password"> - + + - {{ actionLabels.NEXT }} + {{ actionLabels.NEXT }}

@@ -267,10 +267,8 @@ - + + diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-form/rgw-user-form.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-form/rgw-user-form.component.html index 25b7bce95306..360015125b5d 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-form/rgw-user-form.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-user-form/rgw-user-form.component.html @@ -155,10 +155,8 @@ class="btn btn-light" cdPasswordButton="access_key"> - + +
- + + - + + - + + - + + - + + 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 5defbf36a3a5..bccbc645bab1 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 @@ -22,6 +22,7 @@ import { AlertPanelComponent } from './alert-panel/alert-panel.component'; import { BackButtonComponent } from './back-button/back-button.component'; import { ConfigOptionComponent } from './config-option/config-option.component'; import { ConfirmationModalComponent } from './confirmation-modal/confirmation-modal.component'; +import { Copy2ClipboardButtonComponent } from './copy2clipboard-button/copy2clipboard-button.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'; @@ -88,6 +89,7 @@ import { UsageBarComponent } from './usage-bar/usage-bar.component'; OrchestratorDocPanelComponent, DateTimePickerComponent, DocComponent, + Copy2ClipboardButtonComponent, DownloadButtonComponent, FormButtonPanelComponent ], @@ -113,6 +115,7 @@ import { UsageBarComponent } from './usage-bar/usage-bar.component'; OrchestratorDocPanelComponent, DateTimePickerComponent, DocComponent, + Copy2ClipboardButtonComponent, DownloadButtonComponent, FormButtonPanelComponent ] diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/copy2clipboard-button/copy2clipboard-button.component.html b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/copy2clipboard-button/copy2clipboard-button.component.html new file mode 100644 index 000000000000..25a3f3cfe252 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/copy2clipboard-button/copy2clipboard-button.component.html @@ -0,0 +1,7 @@ + diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/copy2clipboard-button/copy2clipboard-button.component.scss b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/copy2clipboard-button/copy2clipboard-button.component.scss new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/copy2clipboard-button/copy2clipboard-button.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/copy2clipboard-button/copy2clipboard-button.component.spec.ts new file mode 100644 index 000000000000..2842793c67ba --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/copy2clipboard-button/copy2clipboard-button.component.spec.ts @@ -0,0 +1,65 @@ +import { TestBed } from '@angular/core/testing'; + +import * as BrowserDetect from 'detect-browser'; +import { ToastrService } from 'ngx-toastr'; + +import { configureTestBed } from '~/testing/unit-test-helper'; +import { Copy2ClipboardButtonComponent } from './copy2clipboard-button.component'; + +describe('Copy2ClipboardButtonComponent', () => { + let component: Copy2ClipboardButtonComponent; + + configureTestBed({ + providers: [ + { + provide: ToastrService, + useValue: { + error: () => true, + success: () => true + } + } + ] + }); + + it('should create an instance', () => { + component = new Copy2ClipboardButtonComponent(null); + expect(component).toBeTruthy(); + }); + + describe('test onClick behaviours', () => { + let toastrService: ToastrService; + let queryFn: jasmine.Spy; + let writeTextFn: jasmine.Spy; + + beforeEach(() => { + toastrService = TestBed.inject(ToastrService); + component = new Copy2ClipboardButtonComponent(toastrService); + spyOn(component, 'getText').and.returnValue('foo'); + Object.assign(navigator, { + permissions: { query: jest.fn() }, + clipboard: { + writeText: jest.fn() + } + }); + queryFn = spyOn(navigator.permissions, 'query'); + }); + + it('should not call permissions API', () => { + spyOn(BrowserDetect, 'detect').and.returnValue({ name: 'firefox' }); + writeTextFn = spyOn(navigator.clipboard, 'writeText').and.returnValue( + new Promise((resolve, _) => { + resolve(); + }) + ); + component.onClick(); + expect(queryFn).not.toHaveBeenCalled(); + expect(writeTextFn).toHaveBeenCalledWith('foo'); + }); + + it('should call permissions API', () => { + spyOn(BrowserDetect, 'detect').and.returnValue({ name: 'chrome' }); + component.onClick(); + expect(queryFn).toHaveBeenCalled(); + }); + }); +}); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/copy2clipboard-button/copy2clipboard-button.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/copy2clipboard-button/copy2clipboard-button.component.ts new file mode 100644 index 000000000000..2cc656bfccbe --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/copy2clipboard-button/copy2clipboard-button.component.ts @@ -0,0 +1,55 @@ +import { Component, HostListener, Input } from '@angular/core'; + +import { detect } from 'detect-browser'; +import { ToastrService } from 'ngx-toastr'; + +import { Icons } from '~/app/shared/enum/icons.enum'; + +@Component({ + selector: 'cd-copy-2-clipboard-button', + templateUrl: './copy2clipboard-button.component.html', + styleUrls: ['./copy2clipboard-button.component.scss'] +}) +export class Copy2ClipboardButtonComponent { + @Input() + private source: string; + + @Input() + byId = true; + + icons = Icons; + + constructor(private toastr: ToastrService) {} + + private getText(): string { + const element = document.getElementById(this.source) as HTMLInputElement; + return element.value; + } + + @HostListener('click') + onClick() { + try { + const browser = detect(); + const text = this.byId ? this.getText() : this.source; + const toastrFn = () => { + this.toastr.success('Copied text to the clipboard successfully.'); + }; + if (['firefox', 'ie', 'ios', 'safari'].includes(browser.name)) { + // Various browsers do not support the `Permissions API`. + // https://developer.mozilla.org/en-US/docs/Web/API/Permissions_API#Browser_compatibility + navigator.clipboard.writeText(text).then(() => toastrFn()); + } else { + // Checking if we have the clipboard-write permission + navigator.permissions + .query({ name: 'clipboard-write' as PermissionName }) + .then((result: any) => { + if (result.state === 'granted' || result.state === 'prompt') { + navigator.clipboard.writeText(text).then(() => toastrFn()); + } + }); + } + } catch (_) { + this.toastr.error('Failed to copy text to the clipboard.'); + } + } +} diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/directives/copy2clipboard-button.directive.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/directives/copy2clipboard-button.directive.spec.ts deleted file mode 100644 index b9681a95a2a2..000000000000 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/directives/copy2clipboard-button.directive.spec.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import * as BrowserDetect from 'detect-browser'; -import { ToastrService } from 'ngx-toastr'; - -import { configureTestBed } from '~/testing/unit-test-helper'; -import { Copy2ClipboardButtonDirective } from './copy2clipboard-button.directive'; - -describe('Copy2clipboardButtonDirective', () => { - let directive: Copy2ClipboardButtonDirective; - - configureTestBed({ - providers: [ - { - provide: ToastrService, - useValue: { - error: () => true, - success: () => true - } - } - ] - }); - - it('should create an instance', () => { - directive = new Copy2ClipboardButtonDirective(null, null, null); - expect(directive).toBeTruthy(); - }); - - describe('test onClick behaviours', () => { - let toastrService: ToastrService; - let queryFn: jasmine.Spy; - let writeTextFn: jasmine.Spy; - - beforeEach(() => { - toastrService = TestBed.inject(ToastrService); - directive = new Copy2ClipboardButtonDirective(null, null, toastrService); - spyOn(directive, 'getText').and.returnValue('foo'); - Object.assign(navigator, { - permissions: { query: jest.fn() }, - clipboard: { - writeText: jest.fn() - } - }); - queryFn = spyOn(navigator.permissions, 'query'); - }); - - it('should not call permissions API', () => { - spyOn(BrowserDetect, 'detect').and.returnValue({ name: 'firefox' }); - writeTextFn = spyOn(navigator.clipboard, 'writeText').and.returnValue( - new Promise((resolve, _) => { - resolve(); - }) - ); - directive.onClick(); - expect(queryFn).not.toHaveBeenCalled(); - expect(writeTextFn).toHaveBeenCalledWith('foo'); - }); - - it('should call permissions API', () => { - spyOn(BrowserDetect, 'detect').and.returnValue({ name: 'chrome' }); - directive.onClick(); - expect(queryFn).toHaveBeenCalled(); - }); - }); -}); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/directives/copy2clipboard-button.directive.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/directives/copy2clipboard-button.directive.ts deleted file mode 100644 index 218af07eedd9..000000000000 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/directives/copy2clipboard-button.directive.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { Directive, ElementRef, HostListener, Input, OnInit, Renderer2 } from '@angular/core'; - -import { detect } from 'detect-browser'; -import { ToastrService } from 'ngx-toastr'; - -@Directive({ - selector: '[cdCopy2ClipboardButton]' -}) -export class Copy2ClipboardButtonDirective implements OnInit { - @Input() - private cdCopy2ClipboardButton: string; - @Input() - byId = true; - - constructor( - private elementRef: ElementRef, - private renderer: Renderer2, - private toastr: ToastrService - ) {} - - ngOnInit() { - const iElement = this.renderer.createElement('i'); - this.renderer.addClass(iElement, 'fa'); - this.renderer.addClass(iElement, 'fa-clipboard'); - this.renderer.setAttribute(iElement, 'title', $localize`Copy to clipboard`); - this.renderer.appendChild(this.elementRef.nativeElement, iElement); - } - - private getText(): string { - const element = document.getElementById(this.cdCopy2ClipboardButton) as HTMLInputElement; - return element.value; - } - - @HostListener('click') - onClick() { - try { - const browser = detect(); - const text = this.byId ? this.getText() : this.cdCopy2ClipboardButton; - const toastrFn = () => { - this.toastr.success('Copied text to the clipboard successfully.'); - }; - if (['firefox', 'ie', 'ios', 'safari'].includes(browser.name)) { - // Various browsers do not support the `Permissions API`. - // https://developer.mozilla.org/en-US/docs/Web/API/Permissions_API#Browser_compatibility - navigator.clipboard.writeText(text).then(() => toastrFn()); - } else { - // Checking if we have the clipboard-write permission - navigator.permissions - .query({ name: 'clipboard-write' as PermissionName }) - .then((result: any) => { - if (result.state === 'granted' || result.state === 'prompt') { - navigator.clipboard.writeText(text).then(() => toastrFn()); - } - }); - } - } catch (_) { - this.toastr.error('Failed to copy text to the clipboard.'); - } - } -} diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/directives/directives.module.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/directives/directives.module.ts index fd43d6621285..00e5635d36b5 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/directives/directives.module.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/directives/directives.module.ts @@ -1,7 +1,6 @@ import { NgModule } from '@angular/core'; import { AutofocusDirective } from './autofocus.directive'; -import { Copy2ClipboardButtonDirective } from './copy2clipboard-button.directive'; import { DimlessBinaryPerSecondDirective } from './dimless-binary-per-second.directive'; import { DimlessBinaryDirective } from './dimless-binary.directive'; import { FormInputDisableDirective } from './form-input-disable.directive'; @@ -20,7 +19,6 @@ import { TrimDirective } from './trim.directive'; imports: [], declarations: [ AutofocusDirective, - Copy2ClipboardButtonDirective, DimlessBinaryDirective, DimlessBinaryPerSecondDirective, PasswordButtonDirective, @@ -37,7 +35,6 @@ import { TrimDirective } from './trim.directive'; ], exports: [ AutofocusDirective, - Copy2ClipboardButtonDirective, DimlessBinaryDirective, DimlessBinaryPerSecondDirective, PasswordButtonDirective,