Skip to content
Snippets Groups Projects
Commit 4411c312 authored by Yana De Pauw's avatar Yana De Pauw
Browse files

55990: Add move item component

parent d26bba8e
No related branches found
No related tags found
No related merge requests found
Showing
with 256 additions and 17 deletions
......@@ -6,7 +6,7 @@
<div class="row">
<div class="col-12">
<ds-input-suggestions #f id="search-form"
[suggestions]="(filterSearchResults | async)"
[suggestions]="(CollectionSearchResults | async)"
[placeholder]="'item.move.search.placeholder'| translate"
[action]="getCurrentUrl()"
[name]="'item-move'"
......
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {Item} from '../../../core/shared/item.model';
import {RouterStub} from '../../../shared/testing/router-stub';
import {CommonModule} from '@angular/common';
import {RouterTestingModule} from '@angular/router/testing';
import {TranslateModule} from '@ngx-translate/core';
import {NgbModule} from '@ng-bootstrap/ng-bootstrap';
import {ActivatedRoute, Router} from '@angular/router';
import {ItemMoveComponent} from './item-move.component';
import {NotificationsServiceStub} from '../../../shared/testing/notifications-service-stub';
import {NotificationsService} from '../../../shared/notifications/notifications.service';
import {SearchService} from '../../../+search-page/search-service/search.service';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {ItemDataService} from '../../../core/data/item-data.service';
import {RestResponse} from '../../../core/cache/response-cache.models';
import {RemoteData} from '../../../core/data/remote-data';
import {PaginatedList} from '../../../core/data/paginated-list';
let comp: ItemMoveComponent;
let fixture: ComponentFixture<ItemMoveComponent>;
const mockItem = Object.assign(new Item(), {
id: 'fake-id',
handle: 'fake/handle',
lastModified: '2018'
});
const itemPageUrl = `fake-url/${mockItem.id}`;
const routerStub = Object.assign(new RouterStub(), {
url: `${itemPageUrl}/edit`
});
const mockItemDataService = jasmine.createSpyObj({
moveToCollection: Observable.of(new RestResponse(true, '200'))
});
const mockItemDataServiceFail = jasmine.createSpyObj({
moveToCollection: Observable.of(new RestResponse(false, '500'))
});
const routeStub = {
data: Observable.of({
item: new RemoteData(false, false, true, null, {
id: 'item1'
})
})
};
const mockSearchService = {
search: () => {
return Observable.of(new RemoteData(false, false, true, null,
new PaginatedList(null, [
{
dspaceObject: {
name: 'Test collection 1',
uuid: 'collection1'
}, hitHighlights: {}
}, {
dspaceObject: {
name: 'Test collection 2',
uuid: 'collection2'
}, hitHighlights: {}
}
])));
}
};
const notificationsServiceStub = new NotificationsServiceStub();
describe('ItemMoveComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [CommonModule, FormsModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
declarations: [ItemMoveComponent],
providers: [
{provide: ActivatedRoute, useValue: routeStub},
{provide: Router, useValue: routerStub},
{provide: ItemDataService, useValue: mockItemDataService},
{provide: NotificationsService, useValue: notificationsServiceStub},
{provide: SearchService, useValue: mockSearchService},
], schemas: [
CUSTOM_ELEMENTS_SCHEMA
]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ItemMoveComponent);
comp = fixture.componentInstance;
fixture.detectChanges();
});
it('should load suggestions', () => {
const expected = [
{
displayValue: 'Test collection 1',
value: {
name: 'Test collection 1',
id: 'collection1',
}
},
{
displayValue: 'Test collection 2',
value: {
name: 'Test collection 2',
id: 'collection2',
}
}
];
comp.CollectionSearchResults.subscribe((value) => {
expect(value).toEqual(expected);
}
);
});
it('should get current url ', () => {
expect(comp.getCurrentUrl()).toEqual('fake-url/fake-id/edit');
});
it('should on click select the correct collection name and id', () => {
const data = {
name: 'Test collection 1',
id: 'collection1',
};
comp.onClick(data);
expect(comp.selectedCollection).toEqual('Test collection 1');
expect(comp.selectedCollectionId).toEqual('collection1');
});
describe('moveCollection', () => {
it('should call itemDataService.moveToCollection', () => {
comp.itemId = 'item-id';
comp.selectedCollectionId = 'selected-collection-id';
comp.moveCollection();
expect(mockItemDataService.moveToCollection).toHaveBeenCalledWith('item-id', 'selected-collection-id');
});
it('should call notificationsService success message on success', () => {
spyOn(notificationsServiceStub, 'success');
comp.moveCollection();
expect(notificationsServiceStub.success).toHaveBeenCalled();
});
});
});
describe('ItemMoveComponent fail', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [CommonModule, FormsModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
declarations: [ItemMoveComponent],
providers: [
{provide: ActivatedRoute, useValue: routeStub},
{provide: Router, useValue: routerStub},
{provide: ItemDataService, useValue: mockItemDataServiceFail},
{provide: NotificationsService, useValue: notificationsServiceStub},
{provide: SearchService, useValue: mockSearchService},
], schemas: [
CUSTOM_ELEMENTS_SCHEMA
]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ItemMoveComponent);
comp = fixture.componentInstance;
fixture.detectChanges();
});
it('should call notificationsService error message on fail', () => {
spyOn(notificationsServiceStub, 'error');
comp.moveCollection();
expect(notificationsServiceStub.error).toHaveBeenCalled();
});
});
......@@ -8,12 +8,9 @@ import {RemoteData} from '../../../core/data/remote-data';
import {DSpaceObject} from '../../../core/shared/dspace-object.model';
import {PaginatedList} from '../../../core/data/paginated-list';
import {SearchResult} from '../../../+search-page/search-result.model';
import {PaginatedSearchOptions} from '../../../+search-page/paginated-search-options.model';
import {Item} from '../../../core/shared/item.model';
import {ActivatedRoute, Router} from '@angular/router';
import {NotificationsService} from '../../../shared/notifications/notifications.service';
import {CollectionDataService} from '../../../core/data/collection-data.service';
import {SearchConfigurationService} from '../../../+search-page/search-service/search-configuration.service';
import {TranslateService} from '@ngx-translate/core';
import {getSucceededRemoteData} from '../../../core/shared/operators';
import {ItemDataService} from '../../../core/data/item-data.service';
......@@ -24,15 +21,14 @@ import {getItemEditPath} from '../../item-page-routing.module';
selector: 'ds-item-move',
templateUrl: './item-move.component.html'
})
/**
* Component that handles the moving of an item to a different collection
*/
export class ItemMoveComponent implements OnInit {
inheritPolicies = false;
itemRD$: Observable<RemoteData<Item>>;
/**
* Search options
*/
searchOptions$: Observable<PaginatedSearchOptions>;
filterSearchResults: Observable<any[]> = Observable.of([]);
CollectionSearchResults: Observable<any[]> = Observable.of([]);
selectedCollection: string;
selectedCollectionId: string;
......@@ -41,9 +37,7 @@ export class ItemMoveComponent implements OnInit {
constructor(private route: ActivatedRoute,
private router: Router,
private notificationsService: NotificationsService,
private collectionDataService: CollectionDataService,
private itemDataService: ItemDataService,
private searchConfigService: SearchConfigurationService,
private searchService: SearchService,
private translateService: TranslateService) {
}
......@@ -54,10 +48,13 @@ export class ItemMoveComponent implements OnInit {
this.itemId = rd.payload.id;
}
);
this.searchOptions$ = this.searchConfigService.paginatedSearchOptions;
this.loadSuggestions('');
}
/**
* Find suggestions based on entered query
* @param query - Search query
*/
findSuggestions(query): void {
this.loadSuggestions(query);
}
......@@ -67,7 +64,7 @@ export class ItemMoveComponent implements OnInit {
* TODO: When the API support it, only fetch collections where user has ADD rights to.
*/
loadSuggestions(query): void {
this.filterSearchResults = this.searchService.search(new SearchOptions({
this.CollectionSearchResults = this.searchService.search(new SearchOptions({
dsoType: DSpaceObjectType.COLLECTION,
query: query
})).first().pipe(
......@@ -83,6 +80,10 @@ export class ItemMoveComponent implements OnInit {
}
/**
* Set the collection name and id based on the selected value
* @param data - obtained from the ds-input-suggestions component
*/
onClick(data: any): void {
this.selectedCollection = data.name;
this.selectedCollectionId = data.id;
......@@ -95,6 +96,9 @@ export class ItemMoveComponent implements OnInit {
return this.router.url;
}
/**
* Moves the item to a new collection based on the selected collection
*/
moveCollection() {
this.itemDataService.moveToCollection(this.itemId, this.selectedCollectionId).first().subscribe(
(response: RestResponse) => {
......
import {ItemOperation} from './itemOperation.model';
import {async, TestBed} from '@angular/core/testing';
import {ItemOperationComponent} from './item-operation.component';
import {TranslateModule} from '@ngx-translate/core';
import {By} from '@angular/platform-browser';
describe('ItemOperationComponent', () => {
const itemOperation: ItemOperation = new ItemOperation('key1', 'url1');
let fixture;
let comp;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [TranslateModule.forRoot()],
declarations: [ItemOperationComponent]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ItemOperationComponent);
comp = fixture.componentInstance;
comp.operation = itemOperation;
fixture.detectChanges();
});
it('should render operation row', () => {
const span = fixture.debugElement.query(By.css('span')).nativeElement;
expect(span.textContent).toContain('item.edit.tabs.status.buttons.key1.label');
const link = fixture.debugElement.query(By.css('a')).nativeElement;
expect(link.href).toContain('url1');
expect(link.textContent).toContain('item.edit.tabs.status.buttons.key1.button');
});
it('should render disabled operation row', () => {
itemOperation.setDisabled(true);
fixture.detectChanges();
const span = fixture.debugElement.query(By.css('span')).nativeElement;
expect(span.textContent).toContain('item.edit.tabs.status.buttons.key1.label');
const span2 = fixture.debugElement.query(By.css('span.btn-danger')).nativeElement;
expect(span2.textContent).toContain('item.edit.tabs.status.buttons.key1.button');
});
});
......@@ -5,7 +5,9 @@ import {ItemOperation} from './itemOperation.model';
selector: 'ds-item-operation',
templateUrl: './item-operation.component.html'
})
/**
* Operation that can be performed on an item
*/
export class ItemOperationComponent {
@Input() operation: ItemOperation;
......
......@@ -7,6 +7,15 @@ export class ItemOperation {
constructor(operationKey: string, operationUrl: string) {
this.operationKey = operationKey;
this.operationUrl = operationUrl;
this.setDisabled(false);
}
/**
* Set whether this operation should be disabled
* @param disabled
*/
setDisabled(disabled: boolean): void {
this.disabled = disabled;
}
}
......@@ -10,6 +10,7 @@ import { Router } from '@angular/router';
import { RouterStub } from '../../../shared/testing/router-stub';
import { Item } from '../../../core/shared/item.model';
import { By } from '@angular/platform-browser';
import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
describe('ItemStatusComponent', () => {
let comp: ItemStatusComponent;
......@@ -33,7 +34,7 @@ describe('ItemStatusComponent', () => {
providers: [
{ provide: Router, useValue: routerStub },
{ provide: HostWindowService, useValue: new HostWindowServiceStub(0) }
]
], schemas: [CUSTOM_ELEMENTS_SCHEMA]
}).compileComponents();
}));
......
......@@ -30,7 +30,7 @@
| translate}}</a>
</div>
</div>
<ds-input-suggestions [suggestions]="(filterSearchResults | async)"
<ds-input-suggestions [suggestions]="(CollectionSearchResults | async)"
[placeholder]="'search.filters.filter.' + filterConfig.name + '.placeholder'| translate"
[action]="getCurrentUrl()"
[name]="filterConfig.paramName"
......
......@@ -32,7 +32,7 @@
| translate}}</a>
</div>
</div>
<ds-input-suggestions [suggestions]="(filterSearchResults | async)"
<ds-input-suggestions [suggestions]="(CollectionSearchResults | async)"
[placeholder]="'search.filters.filter.' + filterConfig.name + '.placeholder'| translate"
[action]="getCurrentUrl()"
[name]="filterConfig.paramName"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment