diff --git a/src/app/+admin/admin-routing.module.ts b/src/app/+admin/admin-routing.module.ts index b4a68d692a..c3732c1ba7 100644 --- a/src/app/+admin/admin-routing.module.ts +++ b/src/app/+admin/admin-routing.module.ts @@ -4,6 +4,8 @@ import { URLCombiner } from '../core/url-combiner/url-combiner'; import { getAdminModulePath } from '../app-routing.module'; import { AdminSearchPageComponent } from './admin-search-page/admin-search-page.component'; import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.resolver'; +import { AdminWorkflowPageComponent } from './admin-workflow-page/admin-workflow-page.component'; +import { I18nBreadcrumbsService } from '../core/breadcrumbs/i18n-breadcrumbs.service'; const REGISTRIES_MODULE_PATH = 'registries'; const ACCESS_CONTROL_MODULE_PATH = 'access-control'; @@ -26,10 +28,18 @@ export function getRegistriesModulePath() { { path: 'search', resolve: { breadcrumb: I18nBreadcrumbResolver }, - component: AdminSearchPageComponent, - data: { title: 'admin.search.title', breadcrumbKey: 'admin.search' } + component: AdminWorkflowPageComponent, + data: { title: 'admin.workflow.title', breadcrumbKey: 'admin.workflow' } }, + { + path: 'workflow', + component: AdminSearchPageComponent, + } ]) + ], + providers: [ + I18nBreadcrumbResolver, + I18nBreadcrumbsService ] }) export class AdminRoutingModule { diff --git a/src/app/+admin/admin-sidebar/admin-sidebar.component.ts b/src/app/+admin/admin-sidebar/admin-sidebar.component.ts index e3f55b8e18..e86287f85d 100644 --- a/src/app/+admin/admin-sidebar/admin-sidebar.component.ts +++ b/src/app/+admin/admin-sidebar/admin-sidebar.component.ts @@ -439,6 +439,19 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit { icon: 'cogs', index: 9 }, + /* Workflow */ + { + id: 'workflow', + active: false, + visible: true, + model: { + type: MenuItemType.LINK, + text: 'menu.section.workflow', + link: '/admin/worklow' + } as LinkMenuItemModel, + icon: 'user-check', + index: 10 + }, ]; menuList.forEach((menuSection) => this.menuService.addSection(this.menuID, menuSection)); diff --git a/src/app/+admin/admin-workflow-page/admin-workflow-page.component.html b/src/app/+admin/admin-workflow-page/admin-workflow-page.component.html new file mode 100644 index 0000000000..47906405d9 --- /dev/null +++ b/src/app/+admin/admin-workflow-page/admin-workflow-page.component.html @@ -0,0 +1,3 @@ +BLABLABALAB + + diff --git a/src/app/+admin/admin-workflow-page/admin-workflow-page.component.scss b/src/app/+admin/admin-workflow-page/admin-workflow-page.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/+admin/admin-workflow-page/admin-workflow-page.component.spec.ts b/src/app/+admin/admin-workflow-page/admin-workflow-page.component.spec.ts new file mode 100644 index 0000000000..d329497473 --- /dev/null +++ b/src/app/+admin/admin-workflow-page/admin-workflow-page.component.spec.ts @@ -0,0 +1,27 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AdminWorkflowPageComponent } from './admin-workflow-page.component'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; + +describe('AdminSearchPageComponent', () => { + let component: AdminWorkflowPageComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ AdminWorkflowPageComponent ], + schemas: [NO_ERRORS_SCHEMA] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AdminWorkflowPageComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/+admin/admin-workflow-page/admin-workflow-page.component.ts b/src/app/+admin/admin-workflow-page/admin-workflow-page.component.ts new file mode 100644 index 0000000000..37ddc70692 --- /dev/null +++ b/src/app/+admin/admin-workflow-page/admin-workflow-page.component.ts @@ -0,0 +1,18 @@ +import { Component, OnInit } from '@angular/core'; +import { Context } from '../../core/shared/context.model'; + +@Component({ + selector: 'ds-admin-workflow-page', + templateUrl: './admin-workflow-page.component.html', + styleUrls: ['./admin-workflow-page.component.scss'] +}) + +/** + * Component that represents a search page for administrators + */ +export class AdminWorkflowPageComponent { + /** + * The context of this page + */ + context: Context = Context.AdminWorkflowSearch; +} diff --git a/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-grid-element/item-search-result/item-admin-workflow-search-result-grid-element.component.html b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-grid-element/item-search-result/item-admin-workflow-search-result-grid-element.component.html new file mode 100644 index 0000000000..1b8daaaff0 --- /dev/null +++ b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-grid-element/item-search-result/item-admin-workflow-search-result-grid-element.component.html @@ -0,0 +1,15 @@ + + + + + {{ "admin.search.item.private" | translate }} + + + {{ "admin.search.item.withdrawn" | translate }} + + + + + + + diff --git a/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-grid-element/item-search-result/item-admin-workflow-search-result-grid-element.component.scss b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-grid-element/item-search-result/item-admin-workflow-search-result-grid-element.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-grid-element/item-search-result/item-admin-workflow-search-result-grid-element.component.spec.ts b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-grid-element/item-search-result/item-admin-workflow-search-result-grid-element.component.spec.ts new file mode 100644 index 0000000000..7036e5c5ac --- /dev/null +++ b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-grid-element/item-search-result/item-admin-workflow-search-result-grid-element.component.spec.ts @@ -0,0 +1,121 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { TranslateModule } from '@ngx-translate/core'; +import { Observable } from 'rxjs/internal/Observable'; +import { BitstreamDataService } from '../../../../../core/data/bitstream-data.service'; +import { RemoteData } from '../../../../../core/data/remote-data'; +import { Bitstream } from '../../../../../core/shared/bitstream.model'; +import { Item } from '../../../../../core/shared/item.model'; +import { mockTruncatableService } from '../../../../../shared/mocks/mock-trucatable.service'; +import { SharedModule } from '../../../../../shared/shared.module'; +import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/testing/utils'; +import { TruncatableService } from '../../../../../shared/truncatable/truncatable.service'; +import { CollectionElementLinkType } from '../../../../../shared/object-collection/collection-element-link.type'; +import { ViewMode } from '../../../../../core/shared/view-mode.model'; +import { By } from '@angular/platform-browser'; +import { RouterTestingModule } from '@angular/router/testing'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { ItemAdminWorkflowSearchResultGridElementComponent } from './item-admin-workflow-search-result-grid-element.component'; + +describe('ItemAdminSearchResultGridElementComponent', () => { + let component: ItemAdminWorkflowSearchResultGridElementComponent; + let fixture: ComponentFixture; + let id; + let searchResult; + + const mockBitstreamDataService = { + getThumbnailFor(item: Item): Observable> { + return createSuccessfulRemoteDataObject$(new Bitstream()); + } + }; + + function init() { + id = '780b2588-bda5-4112-a1cd-0b15000a5339'; + searchResult = new ItemSearchResult(); + searchResult.indexableObject = new Item(); + searchResult.indexableObject.uuid = id; + } + + beforeEach(async(() => { + init(); + TestBed.configureTestingModule( + { + declarations: [ItemAdminWorkflowSearchResultGridElementComponent], + imports: [ + NoopAnimationsModule, + TranslateModule.forRoot(), + RouterTestingModule.withRoutes([]), + SharedModule + ], + providers: [ + { provide: TruncatableService, useValue: mockTruncatableService }, + { provide: BitstreamDataService, useValue: mockBitstreamDataService }, + ], + schemas: [NO_ERRORS_SCHEMA] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ItemAdminWorkflowSearchResultGridElementComponent); + component = fixture.componentInstance; + component.object = searchResult; + component.linkTypes = CollectionElementLinkType; + component.index = 0; + component.viewModes = ViewMode; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('when the item is not withdrawn', () => { + beforeEach(() => { + component.dso.isWithdrawn = false; + fixture.detectChanges(); + }); + + it('should not show the withdrawn badge', () => { + const badge = fixture.debugElement.query(By.css('div.withdrawn-badge')); + expect(badge).toBeNull(); + }); + }); + + describe('when the item is withdrawn', () => { + beforeEach(() => { + component.dso.isWithdrawn = true; + fixture.detectChanges(); + }); + + it('should show the withdrawn badge', () => { + const badge = fixture.debugElement.query(By.css('div.withdrawn-badge')); + expect(badge).not.toBeNull(); + }); + }); + + describe('when the item is not private', () => { + beforeEach(() => { + component.dso.isDiscoverable = true; + fixture.detectChanges(); + }); + it('should not show the private badge', () => { + const badge = fixture.debugElement.query(By.css('div.private-badge')); + expect(badge).toBeNull(); + }); + }); + + describe('when the item is private', () => { + beforeEach(() => { + component.dso.isDiscoverable = false; + fixture.detectChanges(); + }); + + it('should show the private badge', () => { + const badge = fixture.debugElement.query(By.css('div.private-badge')); + expect(badge).not.toBeNull(); + }); + }) +}); diff --git a/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-grid-element/item-search-result/item-admin-workflow-search-result-grid-element.component.ts b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-grid-element/item-search-result/item-admin-workflow-search-result-grid-element.component.ts new file mode 100644 index 0000000000..9b3ed12a24 --- /dev/null +++ b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-grid-element/item-search-result/item-admin-workflow-search-result-grid-element.component.ts @@ -0,0 +1,75 @@ +import { Component, ComponentFactoryResolver, ElementRef, OnInit, ViewChild, ViewContainerRef } from '@angular/core'; +import { Item } from '../../../../../core/shared/item.model'; +import { ViewMode } from '../../../../../core/shared/view-mode.model'; +import { getListableObjectComponent, listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { Context } from '../../../../../core/shared/context.model'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { getItemEditPath } from '../../../../../+item-page/item-page-routing.module'; +import { URLCombiner } from '../../../../../core/url-combiner/url-combiner'; +import { + ITEM_EDIT_DELETE_PATH, + ITEM_EDIT_MOVE_PATH, + ITEM_EDIT_PRIVATE_PATH, + ITEM_EDIT_PUBLIC_PATH, + ITEM_EDIT_REINSTATE_PATH, + ITEM_EDIT_WITHDRAW_PATH +} from '../../../../../+item-page/edit-item-page/edit-item-page.routing.module'; +import { SearchResultGridElementComponent } from '../../../../../shared/object-grid/search-result-grid-element/search-result-grid-element.component'; +import { TruncatableService } from '../../../../../shared/truncatable/truncatable.service'; +import { BitstreamDataService } from '../../../../../core/data/bitstream-data.service'; +import { GenericConstructor } from '../../../../../core/shared/generic-constructor'; +import { ListableObjectDirective } from '../../../../../shared/object-collection/shared/listable-object/listable-object.directive'; + +@listableObjectComponent(ItemSearchResult, ViewMode.GridElement, Context.AdminWorkflowSearch) +@Component({ + selector: 'ds-item-admin-workflow-search-result-grid-element', + styleUrls: ['./item-admin-workflow-search-result-grid-element.component.scss'], + templateUrl: './item-admin-workflow-search-result-grid-element.component.html' +}) +/** + * The component for displaying a list element for an item search result on the admin search page + */ +export class ItemAdminWorkflowSearchResultGridElementComponent extends SearchResultGridElementComponent implements OnInit { + @ViewChild(ListableObjectDirective, { static: true }) listableObjectDirective: ListableObjectDirective; + @ViewChild('badges', { static: true }) badges: ElementRef; + @ViewChild('buttons', { static: true }) buttons: ElementRef; + + constructor(protected truncatableService: TruncatableService, + protected bitstreamDataService: BitstreamDataService, + private componentFactoryResolver: ComponentFactoryResolver + ) { + super(truncatableService, bitstreamDataService); + } + + /** + * Setup the dynamic child component + */ + ngOnInit(): void { + super.ngOnInit(); + const componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.getComponent()); + + const viewContainerRef = this.listableObjectDirective.viewContainerRef; + viewContainerRef.clear(); + + const componentRef = viewContainerRef.createComponent( + componentFactory, + 0, + undefined, + [ + [this.badges.nativeElement], + [this.buttons.nativeElement] + ]); + (componentRef.instance as any).object = this.object; + (componentRef.instance as any).index = this.index; + (componentRef.instance as any).linkType = this.linkType; + (componentRef.instance as any).listID = this.listID; + } + + /** + * Fetch the component depending on the item's relationship type, view mode and context + * @returns {GenericConstructor} + */ + private getComponent(): GenericConstructor { + return getListableObjectComponent(this.object.getRenderTypes(), ViewMode.GridElement, undefined) + } +} diff --git a/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/item-search-result/item-admin-workflow-search-result-list-element.component.html b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/item-search-result/item-admin-workflow-search-result-list-element.component.html new file mode 100644 index 0000000000..14e6c1bcd1 --- /dev/null +++ b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/item-search-result/item-admin-workflow-search-result-list-element.component.html @@ -0,0 +1,12 @@ + + {{ "admin.search.item.private" | translate }} + + + {{ "admin.search.item.withdrawn" | translate }} + + + diff --git a/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/item-search-result/item-admin-workflow-search-result-list-element.component.scss b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/item-search-result/item-admin-workflow-search-result-list-element.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/item-search-result/item-admin-workflow-search-result-list-element.component.spec.ts b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/item-search-result/item-admin-workflow-search-result-list-element.component.spec.ts new file mode 100644 index 0000000000..595a36a5b3 --- /dev/null +++ b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/item-search-result/item-admin-workflow-search-result-list-element.component.spec.ts @@ -0,0 +1,101 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { TranslateModule } from '@ngx-translate/core'; +import { TruncatableService } from '../../../../../shared/truncatable/truncatable.service'; +import { CollectionElementLinkType } from '../../../../../shared/object-collection/collection-element-link.type'; +import { ViewMode } from '../../../../../core/shared/view-mode.model'; +import { By } from '@angular/platform-browser'; +import { RouterTestingModule } from '@angular/router/testing'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { ItemAdminWorkflowSearchResultListElementComponent } from './item-admin-workflow-search-result-list-element.component'; +import { Item } from '../../../../../core/shared/item.model'; + +describe('ItemAdminSearchResultListElementComponent', () => { + let component: ItemAdminWorkflowSearchResultListElementComponent; + let fixture: ComponentFixture; + let id; + let searchResult; + + function init() { + id = '780b2588-bda5-4112-a1cd-0b15000a5339'; + searchResult = new ItemSearchResult(); + searchResult.indexableObject = new Item(); + searchResult.indexableObject.uuid = id; + } + + beforeEach(async(() => { + init(); + TestBed.configureTestingModule({ + imports: [ + TranslateModule.forRoot(), + RouterTestingModule.withRoutes([]) + ], + declarations: [ItemAdminWorkflowSearchResultListElementComponent], + providers: [{ provide: TruncatableService, useValue: {} }], + schemas: [NO_ERRORS_SCHEMA] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ItemAdminWorkflowSearchResultListElementComponent); + component = fixture.componentInstance; + component.object = searchResult; + component.linkTypes = CollectionElementLinkType; + component.index = 0; + component.viewModes = ViewMode; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('when the item is not withdrawn', () => { + beforeEach(() => { + component.dso.isWithdrawn = false; + fixture.detectChanges(); + }); + + it('should not show the withdrawn badge', () => { + const badge = fixture.debugElement.query(By.css('div.withdrawn-badge')); + expect(badge).toBeNull(); + }); + }); + + describe('when the item is withdrawn', () => { + beforeEach(() => { + component.dso.isWithdrawn = true; + fixture.detectChanges(); + }); + + it('should show the withdrawn badge', () => { + const badge = fixture.debugElement.query(By.css('div.withdrawn-badge')); + expect(badge).not.toBeNull(); + }); + }); + + describe('when the item is not private', () => { + beforeEach(() => { + component.dso.isDiscoverable = true; + fixture.detectChanges(); + }); + it('should not show the private badge', () => { + const badge = fixture.debugElement.query(By.css('div.private-badge')); + expect(badge).toBeNull(); + }); + }); + + describe('when the item is private', () => { + beforeEach(() => { + component.dso.isDiscoverable = false; + fixture.detectChanges(); + }); + + it('should show the private badge', () => { + const badge = fixture.debugElement.query(By.css('div.private-badge')); + expect(badge).not.toBeNull(); + }); + }) +}); diff --git a/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/item-search-result/item-admin-workflow-search-result-list-element.component.ts b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/item-search-result/item-admin-workflow-search-result-list-element.component.ts new file mode 100644 index 0000000000..9550028919 --- /dev/null +++ b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/item-search-result/item-admin-workflow-search-result-list-element.component.ts @@ -0,0 +1,20 @@ +import { Component } from '@angular/core'; +import { Item } from '../../../../../core/shared/item.model'; +import { ViewMode } from '../../../../../core/shared/view-mode.model'; +import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { Context } from '../../../../../core/shared/context.model'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { SearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/search-result-list-element.component'; + +@listableObjectComponent(ItemSearchResult, ViewMode.ListElement, Context.AdminWorkflowSearch) +@Component({ + selector: 'ds-item-admin-workflow-search-result-list-element', + styleUrls: ['./item-admin-workflow-search-result-list-element.component.scss'], + templateUrl: './item-admin-workflow-search-result-list-element.component.html' +}) +/** + * The component for displaying a list element for an item search result on the admin search page + */ +export class ItemAdminWorkflowSearchResultListElementComponent extends SearchResultListElementComponent { + +} diff --git a/src/app/+admin/admin-workflow-page/admin-workflow-search-results/item-admin-workflow-search-result-actions.component.html b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/item-admin-workflow-search-result-actions.component.html new file mode 100644 index 0000000000..3f80b127a8 --- /dev/null +++ b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/item-admin-workflow-search-result-actions.component.html @@ -0,0 +1,7 @@ + + {{"admin.search.item.delete" | translate}} + + + + {{"admin.search.item.send-back" | translate}} + diff --git a/src/app/+admin/admin-workflow-page/admin-workflow-search-results/item-admin-workflow-search-result-actions.component.scss b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/item-admin-workflow-search-result-actions.component.scss new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/item-admin-workflow-search-result-actions.component.scss @@ -0,0 +1 @@ + diff --git a/src/app/+admin/admin-workflow-page/admin-workflow-search-results/item-admin-workflow-search-result-actions.component.spec.ts b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/item-admin-workflow-search-result-actions.component.spec.ts new file mode 100644 index 0000000000..c1d42341bc --- /dev/null +++ b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/item-admin-workflow-search-result-actions.component.spec.ts @@ -0,0 +1,144 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { TranslateModule } from '@ngx-translate/core'; +import { By } from '@angular/platform-browser'; +import { RouterTestingModule } from '@angular/router/testing'; +import { ItemAdminWorkflowSearchResultActionsComponent } from './item-admin-workflow-search-result-actions.component'; +import { Item } from '../../../core/shared/item.model'; +import { + ITEM_EDIT_DELETE_PATH, + ITEM_EDIT_MOVE_PATH, + ITEM_EDIT_PRIVATE_PATH, + ITEM_EDIT_PUBLIC_PATH, + ITEM_EDIT_REINSTATE_PATH, + ITEM_EDIT_WITHDRAW_PATH +} from '../../../+item-page/edit-item-page/edit-item-page.routing.module'; +import { getItemEditPath } from '../../../+item-page/item-page-routing.module'; +import { URLCombiner } from '../../../core/url-combiner/url-combiner'; + +describe('ItemAdminSearchResultActionsComponent', () => { + let component: ItemAdminWorkflowSearchResultActionsComponent; + let fixture: ComponentFixture; + let id; + let item; + + function init() { + id = '780b2588-bda5-4112-a1cd-0b15000a5339'; + item = new Item(); + item.uuid = id; + } + beforeEach(async(() => { + init(); + TestBed.configureTestingModule({ + imports: [ + TranslateModule.forRoot(), + RouterTestingModule.withRoutes([]) + ], + declarations: [ItemAdminWorkflowSearchResultActionsComponent], + schemas: [NO_ERRORS_SCHEMA] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ItemAdminWorkflowSearchResultActionsComponent); + component = fixture.componentInstance; + component.item = item; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should render an edit button with the correct link', () => { + const button = fixture.debugElement.query(By.css('a.edit-link')); + const link = button.nativeElement.href; + expect(link).toContain(getItemEditPath(id)); + }); + + it('should render a delete button with the correct link', () => { + const button = fixture.debugElement.query(By.css('a.delete-link')); + const link = button.nativeElement.href; + expect(link).toContain(new URLCombiner(getItemEditPath(id), ITEM_EDIT_DELETE_PATH).toString()); + }); + + it('should render a move button with the correct link', () => { + const a = fixture.debugElement.query(By.css('a.move-link')); + const link = a.nativeElement.href; + expect(link).toContain(new URLCombiner(getItemEditPath(id), ITEM_EDIT_MOVE_PATH).toString()); + }); + + describe('when the item is not withdrawn', () => { + beforeEach(() => { + component.item.isWithdrawn = false; + fixture.detectChanges(); + }); + + it('should render a withdraw button with the correct link', () => { + const a = fixture.debugElement.query(By.css('a.withdraw-link')); + const link = a.nativeElement.href; + expect(link).toContain(new URLCombiner(getItemEditPath(id), ITEM_EDIT_WITHDRAW_PATH).toString()); + }); + + it('should not render a reinstate button with the correct link', () => { + const a = fixture.debugElement.query(By.css('a.reinstate-link')); + expect(a).toBeNull(); + }); + }); + + describe('when the item is withdrawn', () => { + beforeEach(() => { + component.item.isWithdrawn = true; + fixture.detectChanges(); + }); + + it('should not render a withdraw button with the correct link', () => { + const a = fixture.debugElement.query(By.css('a.withdraw-link')); + expect(a).toBeNull(); + }); + + it('should render a reinstate button with the correct link', () => { + const a = fixture.debugElement.query(By.css('a.reinstate-link')); + const link = a.nativeElement.href; + expect(link).toContain(new URLCombiner(getItemEditPath(id), ITEM_EDIT_REINSTATE_PATH).toString()); + }); + }); + + describe('when the item is not private', () => { + beforeEach(() => { + component.item.isDiscoverable = true; + fixture.detectChanges(); + }); + + it('should render a make private button with the correct link', () => { + const a = fixture.debugElement.query(By.css('a.private-link')); + const link = a.nativeElement.href; + expect(link).toContain(new URLCombiner(getItemEditPath(id), ITEM_EDIT_PRIVATE_PATH).toString()); + }); + + it('should not render a make public button with the correct link', () => { + const a = fixture.debugElement.query(By.css('a.public-link')); + expect(a).toBeNull(); + }); + }); + + describe('when the item is private', () => { + beforeEach(() => { + component.item.isDiscoverable = false; + fixture.detectChanges(); + }); + + it('should not render a make private button with the correct link', () => { + const a = fixture.debugElement.query(By.css('a.private-link')); + expect(a).toBeNull(); + }); + + it('should render a make private button with the correct link', () => { + const a = fixture.debugElement.query(By.css('a.public-link')); + const link = a.nativeElement.href; + expect(link).toContain(new URLCombiner(getItemEditPath(id), ITEM_EDIT_PUBLIC_PATH).toString()); + }); + }) +}); diff --git a/src/app/+admin/admin-workflow-page/admin-workflow-search-results/item-admin-workflow-search-result-actions.component.ts b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/item-admin-workflow-search-result-actions.component.ts new file mode 100644 index 0000000000..3dc7b96391 --- /dev/null +++ b/src/app/+admin/admin-workflow-page/admin-workflow-search-results/item-admin-workflow-search-result-actions.component.ts @@ -0,0 +1,46 @@ +import { Component, Input } from '@angular/core'; +import { Item } from '../../../core/shared/item.model'; +import { getItemEditPath } from '../../../+item-page/item-page-routing.module'; +import { URLCombiner } from '../../../core/url-combiner/url-combiner'; +import { + ITEM_EDIT_DELETE_PATH, + ITEM_EDIT_MOVE_PATH, + ITEM_EDIT_PRIVATE_PATH, + ITEM_EDIT_PUBLIC_PATH, + ITEM_EDIT_REINSTATE_PATH, + ITEM_EDIT_WITHDRAW_PATH +} from '../../../+item-page/edit-item-page/edit-item-page.routing.module'; + +@Component({ + selector: 'ds-item-admin-workflow-search-result-actions-element', + styleUrls: ['./item-admin-workflow-search-result-actions.component.scss'], + templateUrl: './item-admin-workflow-search-result-actions.component.html' +}) +/** + * The component for displaying the actions for a list element for an item search result on the admin search page + */ +export class ItemAdminWorkflowSearchResultActionsComponent { + /** + * The item to perform the actions on + */ + @Input() public item: Item; + + /** + * Whether or not to use small buttons + */ + @Input() public small: boolean; + + /** + * Returns the path to the edit page of this item + */ + getEditPath(): string { + return getItemEditPath(this.item.uuid) + } + + /** + * Returns the path to the withdraw page of this item + */ + getWithdrawPath(): string { + return new URLCombiner(this.getEditPath(), ITEM_EDIT_WITHDRAW_PATH).toString(); + } +} diff --git a/src/app/+admin/admin.module.ts b/src/app/+admin/admin.module.ts index fa2480a6ad..d29d876d02 100644 --- a/src/app/+admin/admin.module.ts +++ b/src/app/+admin/admin.module.ts @@ -12,6 +12,10 @@ import { ItemAdminSearchResultGridElementComponent } from './admin-search-page/a import { CommunityAdminSearchResultGridElementComponent } from './admin-search-page/admin-search-results/admin-search-result-grid-element/community-search-result/community-admin-search-result-grid-element.component'; import { CollectionAdminSearchResultGridElementComponent } from './admin-search-page/admin-search-results/admin-search-result-grid-element/collection-search-result/collection-admin-search-result-grid-element.component'; import { ItemAdminSearchResultActionsComponent } from './admin-search-page/admin-search-results/item-admin-search-result-actions.component'; +import { ItemAdminWorkflowSearchResultGridElementComponent } from './admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-grid-element/item-search-result/item-admin-workflow-search-result-grid-element.component'; +import { ItemAdminWorkflowSearchResultActionsComponent } from './admin-workflow-page/admin-workflow-search-results/item-admin-workflow-search-result-actions.component'; +import { ItemAdminWorkflowSearchResultListElementComponent } from './admin-workflow-page/admin-workflow-search-results/admin-workflow-search-result-list-element/item-search-result/item-admin-workflow-search-result-list-element.component'; +import { AdminWorkflowPageComponent } from './admin-workflow-page/admin-workflow-page.component'; @NgModule({ imports: [ @@ -23,13 +27,18 @@ import { ItemAdminSearchResultActionsComponent } from './admin-search-page/admin ], declarations: [ AdminSearchPageComponent, + AdminWorkflowPageComponent, ItemAdminSearchResultListElementComponent, CommunityAdminSearchResultListElementComponent, CollectionAdminSearchResultListElementComponent, ItemAdminSearchResultGridElementComponent, CommunityAdminSearchResultGridElementComponent, CollectionAdminSearchResultGridElementComponent, - ItemAdminSearchResultActionsComponent + ItemAdminSearchResultActionsComponent, + + ItemAdminWorkflowSearchResultListElementComponent, + ItemAdminWorkflowSearchResultGridElementComponent, + ItemAdminWorkflowSearchResultActionsComponent, ], entryComponents: [ ItemAdminSearchResultListElementComponent, @@ -38,7 +47,11 @@ import { ItemAdminSearchResultActionsComponent } from './admin-search-page/admin ItemAdminSearchResultGridElementComponent, CommunityAdminSearchResultGridElementComponent, CollectionAdminSearchResultGridElementComponent, - ItemAdminSearchResultActionsComponent + ItemAdminSearchResultActionsComponent, + + ItemAdminWorkflowSearchResultListElementComponent, + ItemAdminWorkflowSearchResultGridElementComponent, + ItemAdminWorkflowSearchResultActionsComponent, ] }) export class AdminModule { diff --git a/src/app/+login-page/login-page-routing.module.ts b/src/app/+login-page/login-page-routing.module.ts index cd023da55c..9fa4a9e5ad 100644 --- a/src/app/+login-page/login-page-routing.module.ts +++ b/src/app/+login-page/login-page-routing.module.ts @@ -3,12 +3,17 @@ import { RouterModule } from '@angular/router'; import { LoginPageComponent } from './login-page.component'; import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.resolver'; +import { I18nBreadcrumbsService } from '../core/breadcrumbs/i18n-breadcrumbs.service'; @NgModule({ imports: [ RouterModule.forChild([ { path: '', pathMatch: 'full', component: LoginPageComponent, resolve: { breadcrumb: I18nBreadcrumbResolver }, data: { breadcrumbKey: 'login', title: 'login.title' } } ]) + ], + providers: [ + I18nBreadcrumbResolver, + I18nBreadcrumbsService ] }) export class LoginPageRoutingModule { diff --git a/src/app/+search-page/search-page-routing.module.ts b/src/app/+search-page/search-page-routing.module.ts index 6e36883394..f71c7b45ee 100644 --- a/src/app/+search-page/search-page-routing.module.ts +++ b/src/app/+search-page/search-page-routing.module.ts @@ -6,9 +6,11 @@ import { ConfigurationSearchPageComponent } from './configuration-search-page.co import { SearchPageComponent } from './search-page.component'; import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.resolver'; import { I18nBreadcrumbsService } from '../core/breadcrumbs/i18n-breadcrumbs.service'; +import { SearchPageModule } from './search-page.module'; @NgModule({ imports: [ + SearchPageModule, RouterModule.forChild([{ path: '', resolve: { breadcrumb: I18nBreadcrumbResolver }, data: { title: 'search.title', breadcrumbKey: 'search' }, diff --git a/src/app/+search-page/search-page.module.ts b/src/app/+search-page/search-page.module.ts index b69dcaf935..00c990c665 100644 --- a/src/app/+search-page/search-page.module.ts +++ b/src/app/+search-page/search-page.module.ts @@ -2,10 +2,8 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { CoreModule } from '../core/core.module'; import { SharedModule } from '../shared/shared.module'; -import { SearchPageRoutingModule } from './search-page-routing.module'; import { SearchComponent } from './search.component'; import { SidebarService } from '../shared/sidebar/sidebar.service'; -import { EffectsModule } from '@ngrx/effects'; import { ConfigurationSearchPageComponent } from './configuration-search-page.component'; import { ConfigurationSearchPageGuard } from './configuration-search-page.guard'; import { SearchTrackerComponent } from './search-tracker.component'; @@ -14,7 +12,6 @@ import { SearchPageComponent } from './search-page.component'; import { SidebarFilterService } from '../shared/sidebar/filter/sidebar-filter.service'; import { SearchFilterService } from '../core/shared/search/search-filter.service'; import { SearchConfigurationService } from '../core/shared/search/search-configuration.service'; -import { TranslateModule } from '@ngx-translate/core'; const components = [ SearchPageComponent, @@ -25,7 +22,6 @@ const components = [ @NgModule({ imports: [ - SearchPageRoutingModule, CommonModule, SharedModule, CoreModule.forRoot(), diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 2927cd4e65..06811abd08 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -68,7 +68,7 @@ export function getDSOPath(dso: DSpaceObject): string { loadChildren: './+my-dspace-page/my-dspace-page.module#MyDSpacePageModule', canActivate: [AuthenticatedGuard] }, - { path: 'search', loadChildren: './+search-page/search-page.module#SearchPageModule' }, + { path: 'search', loadChildren: './+search-page/search-page-routing.module#SearchPageRoutingModule' }, { path: 'browse', loadChildren: './+browse-by/browse-by.module#BrowseByModule'}, { path: ADMIN_MODULE_PATH, loadChildren: './+admin/admin.module#AdminModule', canActivate: [AuthenticatedGuard] }, { path: 'login', loadChildren: './+login-page/login-page.module#LoginPageModule' }, diff --git a/src/app/core/shared/context.model.ts b/src/app/core/shared/context.model.ts index 6bb3d77140..ff24b7d090 100644 --- a/src/app/core/shared/context.model.ts +++ b/src/app/core/shared/context.model.ts @@ -11,4 +11,5 @@ export enum Context { AdminMenu = 'adminMenu', SubmissionModal = 'submissionModal', AdminSearch = 'adminSearch', + AdminWorkflowSearch = 'adminWorkflowSearch', }