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();