From 68239cd00200eadbd96c5da2393f478135d1ecc1 Mon Sep 17 00:00:00 2001 From: suzanadirla Date: Wed, 22 Nov 2017 15:40:47 +0200 Subject: [PATCH] [ADF-1599] [Destination Picker] Updates to match the designed component (#2642) * [ADF-1599] fix design issues Search Term Highlight text to be orange (primary color) Main action button text label to be orange (primary color) Main action button text to be in Uppercase Main action button to relate to the action i.e. MOVE or COPY Dialog title: Name of item to move/copy should be in 'quotes' * [ADF-1599] fix Dropdown Placeholder text from 'Site List' to 'Select Location' * [ADF-1599] fix Dropdown Placeholder text from 'Site List' to 'Select Location' * fix 'Select Location' width and bottom margin * [ADF-1599] update document picker to match design * [ADF-1599] fix failing tests * [ADF-1599] update the unit tests * [ADF-1599] use only colors from $theme on component scss file * [ADF-1599] change needed after resolving conflict on merge --- docs/sites-dropdown.component.md | 1 + ...-node-selector.component-data.interface.ts | 1 + .../content-node-selector.component.html | 3 +- .../content-node-selector.component.scss | 35 +++++++--- .../content-node-selector.component.spec.ts | 37 ++++++----- .../content-node-selector.component.ts | 6 ++ .../services/node-actions.service.ts | 3 +- lib/content-services/i18n/de.json | 2 + lib/content-services/i18n/en.json | 5 +- lib/content-services/i18n/es.json | 2 + lib/content-services/i18n/fr.json | 2 + lib/content-services/i18n/it.json | 2 + lib/content-services/i18n/ja.json | 2 + lib/content-services/i18n/nb.json | 2 + lib/content-services/i18n/nl.json | 2 + lib/content-services/i18n/pt-BR.json | 2 + lib/content-services/i18n/ru.json | 2 + lib/content-services/i18n/zh-CN.json | 2 + .../sites-dropdown.component.html | 2 +- .../sites-dropdown.component.spec.ts | 66 +++++++++++++++++-- .../site-dropdown/sites-dropdown.component.ts | 3 + 21 files changed, 148 insertions(+), 34 deletions(-) diff --git a/docs/sites-dropdown.component.md b/docs/sites-dropdown.component.md index 93e7c7130e..93424828da 100644 --- a/docs/sites-dropdown.component.md +++ b/docs/sites-dropdown.component.md @@ -30,6 +30,7 @@ Displays a dropdown menu to show and interact with the sites of the current user | --- | --- | --- | --- | | hideMyFiles | boolean | false | Hide the "My Files" option added to the list by default | | siteList | any[] | null | A custom list of sites to be displayed by the dropdown. If no value is given, the sites of the current user are displayed by default. A list of objects only with properties 'title' and 'guid' is enough to be able to display the dropdown. | +| placeholder | string | 'DROPDOWN.PLACEHOLDER_LABEL' | The placeholder text/the key from translation files for the placeholder text to be shown by default| ### Events diff --git a/lib/content-services/content-node-selector/content-node-selector.component-data.interface.ts b/lib/content-services/content-node-selector/content-node-selector.component-data.interface.ts index fd5b888735..66aaff996a 100644 --- a/lib/content-services/content-node-selector/content-node-selector.component-data.interface.ts +++ b/lib/content-services/content-node-selector/content-node-selector.component-data.interface.ts @@ -20,6 +20,7 @@ import { MinimalNodeEntryEntity } from 'alfresco-js-api'; export interface ContentNodeSelectorComponentData { title: string; + actionName?: string; currentFolderId?: string; dropdownHideMyFiles?: boolean; dropdownSiteList?: any[]; diff --git a/lib/content-services/content-node-selector/content-node-selector.component.html b/lib/content-services/content-node-selector/content-node-selector.component.html index 81145d2431..6b73ff9468 100644 --- a/lib/content-services/content-node-selector/content-node-selector.component.html +++ b/lib/content-services/content-node-selector/content-node-selector.component.html @@ -28,6 +28,7 @@ @@ -96,7 +97,7 @@ [disabled]="!chosenNode" class="adf-content-node-selector-actions-choose" (click)="choose()" - data-automation-id="content-node-selector-actions-choose">{{ 'NODE_SELECTOR.CHOOSE' | translate }} + data-automation-id="content-node-selector-actions-choose">{{ buttonActionName | translate }} diff --git a/lib/content-services/content-node-selector/content-node-selector.component.scss b/lib/content-services/content-node-selector/content-node-selector.component.scss index 66cf07d50c..38e7116b02 100644 --- a/lib/content-services/content-node-selector/content-node-selector.component.scss +++ b/lib/content-services/content-node-selector/content-node-selector.component.scss @@ -1,6 +1,7 @@ @mixin adf-content-node-selector-theme($theme) { $primary: map-get($theme, primary); - $accent: map-get($theme, accent); + $foreground: map-get($theme, foreground); + $background: map-get($theme, background); .adf-content-node-selector-dialog { @@ -27,11 +28,11 @@ width: 100%; &-icon { - color: rgba(0, 0, 0, 0.38); + color: mat-color($foreground, disabled-button); cursor: pointer; &:hover { - color: rgba(0, 0, 0, 1); + color: mat-color($foreground, base); } } } @@ -41,9 +42,16 @@ transition: none; } + .adf-site-dropdown-container { + .mat-form-field { + display: block; + margin-bottom: 15px; + } + } + .adf-site-dropdown-list-element { width: 100%; - margin-bottom: 20px; + margin-bottom: 0; .mat-select-trigger { font-size: 14px; @@ -52,16 +60,17 @@ } .adf-toolbar .mat-toolbar { - border: none; + border-bottom-width: 0; + font-size: 14px; } &-list { height: 200px; overflow: auto; - border: 1px solid rgba(0, 0, 0, 0.07); + border: 1px solid mat-color($foreground, base, 0.07); .adf-highlight { - color: mat-color($accent);; + color: mat-color($primary); } .adf-data-table { @@ -97,10 +106,14 @@ &-actions { padding: 8px; - background-color: rgb(250, 250, 250); + background-color: mat-color($background, background); display: flex; justify-content: flex-end; - color: rgb(121, 121, 121); + color: mat-color($foreground, secondary-text); + + button { + text-transform: uppercase; + } &:last-child { margin-bottom: 0px; @@ -116,6 +129,10 @@ &[disabled] { opacity: 0.6; } + + &:enabled { + color: mat-color($primary); + } } } } diff --git a/lib/content-services/content-node-selector/content-node-selector.component.spec.ts b/lib/content-services/content-node-selector/content-node-selector.component.spec.ts index 5972bfe68a..c190625e01 100644 --- a/lib/content-services/content-node-selector/content-node-selector.component.spec.ts +++ b/lib/content-services/content-node-selector/content-node-selector.component.spec.ts @@ -107,6 +107,7 @@ describe('ContentNodeSelectorComponent', () => { beforeEach(async(() => { data = { title: 'Move along citizen...', + actionName: 'move', select: new EventEmitter(), rowFilter: () => {}, imageResolver: () => 'piccolo', @@ -131,6 +132,12 @@ describe('ContentNodeSelectorComponent', () => { expect(titleElement.nativeElement.innerText).toBe('Move along citizen...'); }); + it('should have the INJECTED actionName on the name of the choose button', () => { + const actionButton = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-choose"]')); + expect(actionButton).not.toBeNull(); + expect(actionButton.nativeElement.innerText).toBe('NODE_SELECTOR.MOVE'); + }); + it('should pass through the injected currentFolderId to the documentlist', () => { let documentList = fixture.debugElement.query(By.directive(DocumentListComponent)); expect(documentList).not.toBeNull('Document list should be shown'); @@ -595,7 +602,7 @@ describe('ContentNodeSelectorComponent', () => { }); }); - describe('Choose button', () => { + describe('Action button for the chosen node', () => { const entry: MinimalNodeEntryEntity = {}; let hasPermission; @@ -608,8 +615,8 @@ describe('ContentNodeSelectorComponent', () => { it('should be disabled by default', () => { fixture.detectChanges(); - let chooseButton = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-choose"]')); - expect(chooseButton.nativeElement.disabled).toBe(true); + let actionButton = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-choose"]')); + expect(actionButton.nativeElement.disabled).toBe(true); }); it('should become enabled after loading node with the necessary permissions', () => { @@ -618,8 +625,8 @@ describe('ContentNodeSelectorComponent', () => { component.documentList.ready.emit(); fixture.detectChanges(); - let chooseButton = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-choose"]')); - expect(chooseButton.nativeElement.disabled).toBe(false); + let actionButton = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-choose"]')); + expect(actionButton.nativeElement.disabled).toBe(false); }); it('should remain disabled after loading node without the necessary permissions', () => { @@ -628,8 +635,8 @@ describe('ContentNodeSelectorComponent', () => { component.documentList.ready.emit(); fixture.detectChanges(); - let chooseButton = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-choose"]')); - expect(chooseButton.nativeElement.disabled).toBe(true); + let actionButton = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-choose"]')); + expect(actionButton.nativeElement.disabled).toBe(true); }); it('should be enabled when clicking on a node (with the right permissions) in the list (onNodeSelect)', () => { @@ -638,8 +645,8 @@ describe('ContentNodeSelectorComponent', () => { component.onNodeSelect({ detail: { node: { entry } } }); fixture.detectChanges(); - let chooseButton = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-choose"]')); - expect(chooseButton.nativeElement.disabled).toBe(false); + let actionButton = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-choose"]')); + expect(actionButton.nativeElement.disabled).toBe(false); }); it('should remain disabled when clicking on a node (with the WRONG permissions) in the list (onNodeSelect)', () => { @@ -648,8 +655,8 @@ describe('ContentNodeSelectorComponent', () => { component.onNodeSelect({ detail: { node: { entry } } }); fixture.detectChanges(); - let chooseButton = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-choose"]')); - expect(chooseButton.nativeElement.disabled).toBe(true); + let actionButton = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-choose"]')); + expect(actionButton.nativeElement.disabled).toBe(true); }); it('should become disabled when clicking on a node (with the WRONG permissions) after previously selecting a right node', () => { @@ -661,8 +668,8 @@ describe('ContentNodeSelectorComponent', () => { component.onNodeSelect({ detail: { node: { entry } } }); fixture.detectChanges(); - let chooseButton = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-choose"]')); - expect(chooseButton.nativeElement.disabled).toBe(true); + let actionButton = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-choose"]')); + expect(actionButton.nativeElement.disabled).toBe(true); }); it('should be disabled when resetting the chosen node', () => { @@ -673,8 +680,8 @@ describe('ContentNodeSelectorComponent', () => { component.resetChosenNode(); fixture.detectChanges(); - let chooseButton = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-choose"]')); - expect(chooseButton.nativeElement.disabled).toBe(true); + let actionButton = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-choose"]')); + expect(actionButton.nativeElement.disabled).toBe(true); }); it('should make the call to get the corresponding node entry to emit when a site node is selected as destination', () => { diff --git a/lib/content-services/content-node-selector/content-node-selector.component.ts b/lib/content-services/content-node-selector/content-node-selector.component.ts index 3b355e46f6..794026ecd3 100644 --- a/lib/content-services/content-node-selector/content-node-selector.component.ts +++ b/lib/content-services/content-node-selector/content-node-selector.component.ts @@ -46,10 +46,14 @@ export class ContentNodeSelectorComponent implements OnInit { pagination: Pagination; skipCount: number = 0; infiniteScroll: boolean = false; + buttonActionName: string; @Input() title: string; + @Input() + actionName: string; + @Input() currentFolderId: string | null = null; @@ -85,6 +89,7 @@ export class ContentNodeSelectorComponent implements OnInit { @Optional() private containingDialog?: MatDialogRef) { if (data) { this.title = data.title; + this.actionName = data.actionName; this.select = data.select; this.currentFolderId = data.currentFolderId; this.dropdownHideMyFiles = data.dropdownHideMyFiles; @@ -92,6 +97,7 @@ export class ContentNodeSelectorComponent implements OnInit { this.rowFilter = data.rowFilter; this.imageResolver = data.imageResolver; } + this.buttonActionName = this.actionName ? `NODE_SELECTOR.${this.actionName.toUpperCase()}` : 'NODE_SELECTOR.CHOOSE'; if (this.containingDialog) { this.inDialog = true; diff --git a/lib/content-services/document-list/services/node-actions.service.ts b/lib/content-services/document-list/services/node-actions.service.ts index 377d5e39ba..42ccb6e951 100644 --- a/lib/content-services/document-list/services/node-actions.service.ts +++ b/lib/content-services/document-list/services/node-actions.service.ts @@ -86,7 +86,8 @@ export class NodeActionsService { if (this.contentService.hasPermission(contentEntry, permission)) { const data: ContentNodeSelectorComponentData = { - title: `${action} ${contentEntry.name} to ...`, + title: `${action} '${contentEntry.name}' to ...`, + actionName: action, currentFolderId: contentEntry.parentId, rowFilter: this.rowFilter.bind(this, contentEntry.id), imageResolver: this.imageResolver.bind(this), diff --git a/lib/content-services/i18n/de.json b/lib/content-services/i18n/de.json index 295f3645d9..40e2339672 100644 --- a/lib/content-services/i18n/de.json +++ b/lib/content-services/i18n/de.json @@ -60,6 +60,8 @@ "NODE_SELECTOR": { "CANCEL": "Abbrechen", "CHOOSE": "Auswählen", + "COPY": "Kopieren", + "MOVE": "Verschieben", "NO_RESULTS": "Keine Ergebnisse gefunden" }, "OPERATION": { diff --git a/lib/content-services/i18n/en.json b/lib/content-services/i18n/en.json index a29c74d08c..0c242715b1 100644 --- a/lib/content-services/i18n/en.json +++ b/lib/content-services/i18n/en.json @@ -60,7 +60,10 @@ "NODE_SELECTOR": { "CANCEL": "Cancel", "CHOOSE": "Choose", - "NO_RESULTS": "No results found" + "COPY": "Copy", + "MOVE": "Move", + "NO_RESULTS": "No results found", + "SELECT_LOCATION": "Select Location" }, "OPERATION": { "SUCCES": { diff --git a/lib/content-services/i18n/es.json b/lib/content-services/i18n/es.json index e5148546ca..fc1c4cbc42 100644 --- a/lib/content-services/i18n/es.json +++ b/lib/content-services/i18n/es.json @@ -60,6 +60,8 @@ "NODE_SELECTOR": { "CANCEL": "Cancelar", "CHOOSE": "Elegir", + "COPY": "Copiar", + "MOVE": "Mover", "NO_RESULTS": "Ningún resultado encontrado" }, "OPERATION": { diff --git a/lib/content-services/i18n/fr.json b/lib/content-services/i18n/fr.json index a2438515b3..ee5b4847c0 100644 --- a/lib/content-services/i18n/fr.json +++ b/lib/content-services/i18n/fr.json @@ -60,6 +60,8 @@ "NODE_SELECTOR": { "CANCEL": "Annuler", "CHOOSE": "Choisir", + "COPY": "Copier", + "MOVE": "Déplacer", "NO_RESULTS": "Aucun résultat trouvé" }, "OPERATION": { diff --git a/lib/content-services/i18n/it.json b/lib/content-services/i18n/it.json index 83d776f7dd..ee66c94228 100644 --- a/lib/content-services/i18n/it.json +++ b/lib/content-services/i18n/it.json @@ -60,6 +60,8 @@ "NODE_SELECTOR": { "CANCEL": "Annulla", "CHOOSE": "Scegli", + "COPY": "Copia", + "MOVE": "Sposta", "NO_RESULTS": "Nessun risultato trovato" }, "OPERATION": { diff --git a/lib/content-services/i18n/ja.json b/lib/content-services/i18n/ja.json index 2239a0fb43..e5d050f084 100644 --- a/lib/content-services/i18n/ja.json +++ b/lib/content-services/i18n/ja.json @@ -60,6 +60,8 @@ "NODE_SELECTOR": { "CANCEL": "キャンセル", "CHOOSE": "選択", + "COPY": "コピー", + "MOVE": "移動", "NO_RESULTS": "一致するアイテムはありません" }, "OPERATION": { diff --git a/lib/content-services/i18n/nb.json b/lib/content-services/i18n/nb.json index 1848373066..040fad2225 100644 --- a/lib/content-services/i18n/nb.json +++ b/lib/content-services/i18n/nb.json @@ -60,6 +60,8 @@ "NODE_SELECTOR": { "CANCEL": "Avbryt", "CHOOSE": "Velg", + "COPY": "Kopier", + "MOVE": "Flytt", "NO_RESULTS": "Ingen resultater funnet" }, "OPERATION": { diff --git a/lib/content-services/i18n/nl.json b/lib/content-services/i18n/nl.json index 1e2861dd93..ab84be4e38 100644 --- a/lib/content-services/i18n/nl.json +++ b/lib/content-services/i18n/nl.json @@ -60,6 +60,8 @@ "NODE_SELECTOR": { "CANCEL": "Annuleren", "CHOOSE": "Kiezen", + "COPY": "Kopiëren", + "MOVE": "Verplaatsen", "NO_RESULTS": "Geen resultaten gevonden" }, "OPERATION": { diff --git a/lib/content-services/i18n/pt-BR.json b/lib/content-services/i18n/pt-BR.json index ccb2f88867..7f0a53083c 100644 --- a/lib/content-services/i18n/pt-BR.json +++ b/lib/content-services/i18n/pt-BR.json @@ -60,6 +60,8 @@ "NODE_SELECTOR": { "CANCEL": "Cancelar", "CHOOSE": "Escolher", + "COPY": "Copiar", + "MOVE": "Mover", "NO_RESULTS": "Nenhum resultado encontrado" }, "OPERATION": { diff --git a/lib/content-services/i18n/ru.json b/lib/content-services/i18n/ru.json index 46282d6dea..a78ca9cba3 100644 --- a/lib/content-services/i18n/ru.json +++ b/lib/content-services/i18n/ru.json @@ -60,6 +60,8 @@ "NODE_SELECTOR": { "CANCEL": "Отмена", "CHOOSE": "Выбрать", + "COPY": "Копировать", + "MOVE": "Переместить", "NO_RESULTS": "Результаты не найдены" }, "OPERATION": { diff --git a/lib/content-services/i18n/zh-CN.json b/lib/content-services/i18n/zh-CN.json index 3b30782fa9..af51418d22 100644 --- a/lib/content-services/i18n/zh-CN.json +++ b/lib/content-services/i18n/zh-CN.json @@ -60,6 +60,8 @@ "NODE_SELECTOR": { "CANCEL": "取消", "CHOOSE": "选择", + "COPY": "复制", + "MOVE": "移动", "NO_RESULTS": "未找到结果" }, "OPERATION": { diff --git a/lib/content-services/site-dropdown/sites-dropdown.component.html b/lib/content-services/site-dropdown/sites-dropdown.component.html index 64978c7eae..941335de2c 100644 --- a/lib/content-services/site-dropdown/sites-dropdown.component.html +++ b/lib/content-services/site-dropdown/sites-dropdown.component.html @@ -3,7 +3,7 @@ { TestBed.resetTestingModule(); }); - it('Dropdown sites should be renedered', async(() => { + it('Dropdown sites should be rendered', async(() => { fixture.detectChanges(); fixture.whenStable().then(() => { fixture.detectChanges(); @@ -145,24 +145,78 @@ describe('DropdownSitesComponent', () => { }); })); - // todo: something wrong with the test itself - xit('should load sites on init', async(() => { + it('should show the default placeholder label by default', async(() => { + fixture.detectChanges(); + jasmine.Ajax.requests.mostRecent().respondWith({ status: 200, contentType: 'json', responseText: sitesList }); + + openSelectbox(); + + fixture.whenStable().then(() => { + fixture.detectChanges(); + expect(fixture.nativeElement.innerText.trim()).toBe('DROPDOWN.PLACEHOLDER_LABEL'); + }); + })); + + it('should show custom placeholder label when the \'placeholder\' input property is given a value', async(() => { + component.placeholder = 'NODE_SELECTOR.SELECT_LOCATION'; + fixture.detectChanges(); + jasmine.Ajax.requests.mostRecent().respondWith({ status: 200, contentType: 'json', responseText: sitesList }); + + openSelectbox(); + + fixture.whenStable().then(() => { + fixture.detectChanges(); + expect(fixture.nativeElement.innerText.trim()).toBe('NODE_SELECTOR.SELECT_LOCATION'); + }); + })); + + it('should load custom sites when the \'siteList\' input property is given a value', async(() => { + component.siteList = [{title: 'PERSONAL_FILES', guid: '-my-'}, {title: 'FILE_LIBRARIES', guid: '-mysites-'}]; + fixture.detectChanges(); + + openSelectbox(); + + let options: any = []; + fixture.whenStable().then(() => { + fixture.detectChanges(); + options = debug.queryAll(By.css('mat-option')); + options[0].triggerEventHandler('click', null); + fixture.detectChanges(); + }); + + component.change.subscribe(() => { + expect(options[0].attributes['ng-reflect-value']).toBe('default'); + expect(options[1].attributes['ng-reflect-value']).toBe('-my-'); + expect(options[2].attributes['ng-reflect-value']).toBe('-mysites-'); + }); + })); + + it('should load sites by default', (done) => { fixture.detectChanges(); jasmine.Ajax.requests.mostRecent().respondWith({ status: 200, contentType: 'json', responseText: sitesList }); + + openSelectbox(); + + let options: any = []; fixture.whenStable().then(() => { fixture.detectChanges(); - debug.query(By.css('.mat-select-trigger')).triggerEventHandler('click', null); + options = debug.queryAll(By.css('mat-option')); + options[0].triggerEventHandler('click', null); fixture.detectChanges(); - let options: any = debug.queryAll(By.css('mat-option')); + }); + + component.change.subscribe(() => { expect(options[0].attributes['ng-reflect-value']).toBe('default'); expect(options[1].attributes['ng-reflect-value']).toBe('fake-1'); expect(options[2].attributes['ng-reflect-value']).toBe('fake-2'); + + done(); }); - })); + }); it('should raise an event when a site is selected', (done) => { fixture.detectChanges(); diff --git a/lib/content-services/site-dropdown/sites-dropdown.component.ts b/lib/content-services/site-dropdown/sites-dropdown.component.ts index f9dc01e91a..10cc2e054b 100644 --- a/lib/content-services/site-dropdown/sites-dropdown.component.ts +++ b/lib/content-services/site-dropdown/sites-dropdown.component.ts @@ -31,6 +31,9 @@ export class DropdownSitesComponent implements OnInit { @Input() siteList: any[] = null; + @Input() + placeholder: string = 'DROPDOWN.PLACEHOLDER_LABEL'; + @Output() change: EventEmitter = new EventEmitter();