[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
This commit is contained in:
suzanadirla
2017-11-22 15:40:47 +02:00
committed by Eugenio Romano
parent ed6aa1a0c1
commit 68239cd002
21 changed files with 148 additions and 34 deletions

View File

@@ -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

View File

@@ -20,6 +20,7 @@ import { MinimalNodeEntryEntity } from 'alfresco-js-api';
export interface ContentNodeSelectorComponentData {
title: string;
actionName?: string;
currentFolderId?: string;
dropdownHideMyFiles?: boolean;
dropdownSiteList?: any[];

View File

@@ -28,6 +28,7 @@
<adf-sites-dropdown
(change)="siteChanged($event)"
[placeholder]="'NODE_SELECTOR.SELECT_LOCATION'"
[hideMyFiles]="dropdownHideMyFiles"
[siteList]="dropdownSiteList"
data-automation-id="content-node-selector-sites-combo"></adf-sites-dropdown>
@@ -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 }}
</button>
</footer>

View File

@@ -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);
}
}
}
}

View File

@@ -107,6 +107,7 @@ describe('ContentNodeSelectorComponent', () => {
beforeEach(async(() => {
data = {
title: 'Move along citizen...',
actionName: 'move',
select: new EventEmitter<MinimalNodeEntryEntity>(),
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 = <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', () => {

View File

@@ -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<ContentNodeSelectorComponent>) {
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;

View File

@@ -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),

View File

@@ -60,6 +60,8 @@
"NODE_SELECTOR": {
"CANCEL": "Abbrechen",
"CHOOSE": "Auswählen",
"COPY": "Kopieren",
"MOVE": "Verschieben",
"NO_RESULTS": "Keine Ergebnisse gefunden"
},
"OPERATION": {

View File

@@ -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": {

View File

@@ -60,6 +60,8 @@
"NODE_SELECTOR": {
"CANCEL": "Cancelar",
"CHOOSE": "Elegir",
"COPY": "Copiar",
"MOVE": "Mover",
"NO_RESULTS": "Ningún resultado encontrado"
},
"OPERATION": {

View File

@@ -60,6 +60,8 @@
"NODE_SELECTOR": {
"CANCEL": "Annuler",
"CHOOSE": "Choisir",
"COPY": "Copier",
"MOVE": "Déplacer",
"NO_RESULTS": "Aucun résultat trouvé"
},
"OPERATION": {

View File

@@ -60,6 +60,8 @@
"NODE_SELECTOR": {
"CANCEL": "Annulla",
"CHOOSE": "Scegli",
"COPY": "Copia",
"MOVE": "Sposta",
"NO_RESULTS": "Nessun risultato trovato"
},
"OPERATION": {

View File

@@ -60,6 +60,8 @@
"NODE_SELECTOR": {
"CANCEL": "キャンセル",
"CHOOSE": "選択",
"COPY": "コピー",
"MOVE": "移動",
"NO_RESULTS": "一致するアイテムはありません"
},
"OPERATION": {

View File

@@ -60,6 +60,8 @@
"NODE_SELECTOR": {
"CANCEL": "Avbryt",
"CHOOSE": "Velg",
"COPY": "Kopier",
"MOVE": "Flytt",
"NO_RESULTS": "Ingen resultater funnet"
},
"OPERATION": {

View File

@@ -60,6 +60,8 @@
"NODE_SELECTOR": {
"CANCEL": "Annuleren",
"CHOOSE": "Kiezen",
"COPY": "Kopiëren",
"MOVE": "Verplaatsen",
"NO_RESULTS": "Geen resultaten gevonden"
},
"OPERATION": {

View File

@@ -60,6 +60,8 @@
"NODE_SELECTOR": {
"CANCEL": "Cancelar",
"CHOOSE": "Escolher",
"COPY": "Copiar",
"MOVE": "Mover",
"NO_RESULTS": "Nenhum resultado encontrado"
},
"OPERATION": {

View File

@@ -60,6 +60,8 @@
"NODE_SELECTOR": {
"CANCEL": "Отмена",
"CHOOSE": "Выбрать",
"COPY": "Копировать",
"MOVE": "Переместить",
"NO_RESULTS": "Результаты не найдены"
},
"OPERATION": {

View File

@@ -60,6 +60,8 @@
"NODE_SELECTOR": {
"CANCEL": "取消",
"CHOOSE": "选择",
"COPY": "复制",
"MOVE": "移动",
"NO_RESULTS": "未找到结果"
},
"OPERATION": {

View File

@@ -3,7 +3,7 @@
<mat-select
class="adf-site-dropdown-list-element"
id="site-dropdown"
placeholder="{{'DROPDOWN.PLACEHOLDER_LABEL' | translate}}"
placeholder="{{placeholder | translate}}"
floatPlaceholder="never"
data-automation-id="site-my-files-select"
[(ngModel)]="siteSelected"

View File

@@ -102,7 +102,7 @@ describe('DropdownSitesComponent', () => {
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();

View File

@@ -31,6 +31,9 @@ export class DropdownSitesComponent implements OnInit {
@Input()
siteList: any[] = null;
@Input()
placeholder: string = 'DROPDOWN.PLACEHOLDER_LABEL';
@Output()
change: EventEmitter<SiteModel> = new EventEmitter();