mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-15 14:03:06 +00:00
Merge branch 'main' into feature/CST-5729
This commit is contained in:
@@ -214,6 +214,9 @@ languages:
|
||||
- code: tr
|
||||
label: Türkçe
|
||||
active: true
|
||||
- code: vi
|
||||
label: Tiếng Việt
|
||||
active: true
|
||||
- code: kk
|
||||
label: Қазақ
|
||||
active: true
|
||||
|
@@ -19,7 +19,7 @@ import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/remote-
|
||||
import { getMockThemeService } from '../../../../../shared/mocks/theme-service.mock';
|
||||
import { ThemeService } from '../../../../../shared/theme-support/theme.service';
|
||||
import { AccessStatusDataService } from '../../../../../core/data/access-status-data.service';
|
||||
import { AccessStatusObject } from '../../../../../shared/object-list/access-status-badge/access-status.model';
|
||||
import { AccessStatusObject } from '../../../../../shared/object-collection/shared/badges/access-status-badge/access-status.model';
|
||||
import { AuthService } from '../../../../../core/auth/auth.service';
|
||||
import { AuthServiceStub } from '../../../../../shared/testing/auth-service.stub';
|
||||
import { FileService } from '../../../../../core/shared/file.service';
|
||||
|
@@ -2,6 +2,5 @@
|
||||
[viewMode]="viewModes.ListElement"
|
||||
[index]="index"
|
||||
[linkType]="linkType"
|
||||
[listID]="listID"
|
||||
[hideBadges]="true"></ds-listable-object-component-loader>
|
||||
[listID]="listID"></ds-listable-object-component-loader>
|
||||
<ds-item-admin-search-result-actions-element [item]="dso" [small]="false"></ds-item-admin-search-result-actions-element>
|
||||
|
@@ -8,10 +8,10 @@
|
||||
<span class="fa fa-chevron-right invisible" aria-hidden="true"></span>
|
||||
</button>
|
||||
<div class="align-middle pt-2">
|
||||
<a *ngIf="node!==loadingNode" [routerLink]="[]" (click)="getNextPage(node)"
|
||||
<button *ngIf="node!==loadingNode" (click)="getNextPage(node)"
|
||||
class="btn btn-outline-primary btn-sm" role="button">
|
||||
<i class="fas fa-angle-down"></i> {{ 'communityList.showMore' | translate }}
|
||||
</a>
|
||||
</button>
|
||||
<ds-themed-loading *ngIf="node===loadingNode && dataSource.loading$ | async" class="ds-themed-loading"></ds-themed-loading>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -16,6 +16,7 @@ import { of as observableOf } from 'rxjs';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { isEmpty, isNotEmpty } from '../../shared/empty.util';
|
||||
import { FlatNode } from '../flat-node.model';
|
||||
import { RouterLinkWithHref } from '@angular/router';
|
||||
|
||||
describe('CommunityListComponent', () => {
|
||||
let component: CommunityListComponent;
|
||||
@@ -194,7 +195,7 @@ describe('CommunityListComponent', () => {
|
||||
}),
|
||||
CdkTreeModule,
|
||||
RouterTestingModule],
|
||||
declarations: [CommunityListComponent],
|
||||
declarations: [CommunityListComponent, RouterLinkWithHref],
|
||||
providers: [CommunityListComponent,
|
||||
{ provide: CommunityListService, useValue: communityListServiceStub },],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
@@ -230,9 +231,14 @@ describe('CommunityListComponent', () => {
|
||||
expect(showMoreEl).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should not render the show more button as an empty link', () => {
|
||||
const debugElements = fixture.debugElement.queryAll(By.directive(RouterLinkWithHref));
|
||||
expect(debugElements).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('when show more of top communities is clicked', () => {
|
||||
beforeEach(fakeAsync(() => {
|
||||
const showMoreLink = fixture.debugElement.query(By.css('.show-more-node a'));
|
||||
const showMoreLink = fixture.debugElement.query(By.css('.show-more-node .btn-outline-primary'));
|
||||
showMoreLink.triggerEventHandler('click', {
|
||||
preventDefault: () => {/**/
|
||||
}
|
||||
@@ -240,6 +246,7 @@ describe('CommunityListComponent', () => {
|
||||
tick();
|
||||
fixture.detectChanges();
|
||||
}));
|
||||
|
||||
it('tree contains maximum of currentPage (2) * (2) elementsPerPage of first top communities, or less if there are less communities (3)', () => {
|
||||
const expandableNodesFound = fixture.debugElement.queryAll(By.css('.expandable-node a'));
|
||||
const childlessNodesFound = fixture.debugElement.queryAll(By.css('.childless-node a'));
|
||||
|
@@ -160,7 +160,7 @@ import { SubmissionAccessesModel } from './config/models/config-submission-acces
|
||||
import { RatingAdvancedWorkflowInfo } from './tasks/models/rating-advanced-workflow-info.model';
|
||||
import { AdvancedWorkflowInfo } from './tasks/models/advanced-workflow-info.model';
|
||||
import { SelectReviewerAdvancedWorkflowInfo } from './tasks/models/select-reviewer-advanced-workflow-info.model';
|
||||
import { AccessStatusObject } from '../shared/object-list/access-status-badge/access-status.model';
|
||||
import { AccessStatusObject } from '../shared/object-collection/shared/badges/access-status-badge/access-status.model';
|
||||
import { AccessStatusDataService } from './data/access-status-data.service';
|
||||
import { LinkHeadService } from './services/link-head.service';
|
||||
import { ResearcherProfileDataService } from './profile/researcher-profile-data.service';
|
||||
|
@@ -3,8 +3,8 @@ import { RemoteDataBuildService } from '../cache/builders/remote-data-build.serv
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { RequestService } from './request.service';
|
||||
import { AccessStatusObject } from 'src/app/shared/object-list/access-status-badge/access-status.model';
|
||||
import { ACCESS_STATUS } from 'src/app/shared/object-list/access-status-badge/access-status.resource-type';
|
||||
import { AccessStatusObject } from 'src/app/shared/object-collection/shared/badges/access-status-badge/access-status.model';
|
||||
import { ACCESS_STATUS } from 'src/app/shared/object-collection/shared/badges/access-status-badge/access-status.resource-type';
|
||||
import { Observable } from 'rxjs';
|
||||
import { RemoteData } from './remote-data';
|
||||
import { Item } from '../shared/item.model';
|
||||
|
@@ -641,6 +641,62 @@ describe('BaseDataService', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('hasCachedResponse', () => {
|
||||
it('should return false when the request will be dispatched', (done) => {
|
||||
const result = service.hasCachedResponse('test-href');
|
||||
|
||||
result.subscribe((hasCachedResponse) => {
|
||||
expect(hasCachedResponse).toBeFalse();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should return true when the request will not be dispatched', (done) => {
|
||||
(requestService.shouldDispatchRequest as jasmine.Spy).and.returnValue(false);
|
||||
const result = service.hasCachedResponse('test-href');
|
||||
|
||||
result.subscribe((hasCachedResponse) => {
|
||||
expect(hasCachedResponse).toBeTrue();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('hasCachedErrorResponse', () => {
|
||||
it('should return false when no response is cached', (done) => {
|
||||
spyOn(service,'hasCachedResponse').and.returnValue(observableOf(false));
|
||||
const result = service.hasCachedErrorResponse('test-href');
|
||||
|
||||
result.subscribe((hasCachedErrorResponse) => {
|
||||
expect(hasCachedErrorResponse).toBeFalse();
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('should return false when no error response is cached', (done) => {
|
||||
spyOn(service,'hasCachedResponse').and.returnValue(observableOf(true));
|
||||
spyOn(rdbService,'buildSingle').and.returnValue(createSuccessfulRemoteDataObject$({}));
|
||||
|
||||
const result = service.hasCachedErrorResponse('test-href');
|
||||
|
||||
result.subscribe((hasCachedErrorResponse) => {
|
||||
expect(hasCachedErrorResponse).toBeFalse();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should return true when an error response is cached', (done) => {
|
||||
spyOn(service,'hasCachedResponse').and.returnValue(observableOf(true));
|
||||
spyOn(rdbService,'buildSingle').and.returnValue(createFailedRemoteDataObject$());
|
||||
|
||||
const result = service.hasCachedErrorResponse('test-href');
|
||||
|
||||
result.subscribe((hasCachedErrorResponse) => {
|
||||
expect(hasCachedErrorResponse).toBeTrue();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('addDependency', () => {
|
||||
let addDependencySpy;
|
||||
|
||||
|
@@ -341,6 +341,48 @@ export class BaseDataService<T extends CacheableObject> implements HALDataServic
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for the provided href whether a response is already cached
|
||||
* @param href$ The url for which to check whether there is a cached response.
|
||||
* Can be a string or an Observable<string>
|
||||
*/
|
||||
hasCachedResponse(href$: string | Observable<string>): Observable<boolean> {
|
||||
if (isNotEmpty(href$)) {
|
||||
if (typeof href$ === 'string') {
|
||||
href$ = observableOf(href$);
|
||||
}
|
||||
return href$.pipe(
|
||||
isNotEmptyOperator(),
|
||||
take(1),
|
||||
map((href: string) => {
|
||||
const requestId = this.requestService.generateRequestId();
|
||||
const request = new GetRequest(requestId, href);
|
||||
return !this.requestService.shouldDispatchRequest(request, true);
|
||||
}),
|
||||
);
|
||||
}
|
||||
throw new Error(`Can't check whether there is a cached response for an empty href$`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for the provided href whether an ERROR response is currently cached
|
||||
* @param href$ The url for which to check whether there is a cached ERROR response.
|
||||
* Can be a string or an Observable<string>
|
||||
*/
|
||||
hasCachedErrorResponse(href$: string | Observable<string>): Observable<boolean> {
|
||||
return this.hasCachedResponse(href$).pipe(
|
||||
switchMap((hasCachedResponse) => {
|
||||
if (hasCachedResponse) {
|
||||
return this.rdbService.buildSingle(href$).pipe(
|
||||
getFirstCompletedRemoteData(),
|
||||
map((rd => rd.hasFailed))
|
||||
);
|
||||
}
|
||||
return observableOf(false);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the links to traverse from the root of the api to the
|
||||
* endpoint this DataService represents
|
||||
|
@@ -5,6 +5,7 @@ import { ExternalSourceEntry } from '../shared/external-source-entry.model';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { GetRequest } from './request.models';
|
||||
import { testSearchDataImplementation } from './base/search-data.spec';
|
||||
import { take } from 'rxjs/operators';
|
||||
|
||||
describe('ExternalSourceService', () => {
|
||||
let service: ExternalSourceDataService;
|
||||
@@ -64,19 +65,42 @@ describe('ExternalSourceService', () => {
|
||||
});
|
||||
|
||||
describe('getExternalSourceEntries', () => {
|
||||
let result;
|
||||
|
||||
beforeEach(() => {
|
||||
result = service.getExternalSourceEntries('test');
|
||||
describe('when no error response is cached', () => {
|
||||
let result;
|
||||
beforeEach(() => {
|
||||
spyOn(service, 'hasCachedErrorResponse').and.returnValue(observableOf(false));
|
||||
result = service.getExternalSourceEntries('test');
|
||||
});
|
||||
|
||||
it('should send a GetRequest', () => {
|
||||
result.pipe(take(1)).subscribe();
|
||||
expect(requestService.send).toHaveBeenCalledWith(jasmine.any(GetRequest), true);
|
||||
});
|
||||
|
||||
it('should return the entries', () => {
|
||||
result.subscribe((resultRD) => {
|
||||
expect(resultRD.payload.page).toBe(entries);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should send a GetRequest', () => {
|
||||
expect(requestService.send).toHaveBeenCalledWith(jasmine.any(GetRequest), true);
|
||||
});
|
||||
describe('when an error response is cached', () => {
|
||||
let result;
|
||||
beforeEach(() => {
|
||||
spyOn(service, 'hasCachedErrorResponse').and.returnValue(observableOf(true));
|
||||
result = service.getExternalSourceEntries('test');
|
||||
});
|
||||
|
||||
it('should return the entries', () => {
|
||||
result.subscribe((resultRD) => {
|
||||
expect(resultRD.payload.page).toBe(entries);
|
||||
it('should send a GetRequest', () => {
|
||||
result.pipe(take(1)).subscribe();
|
||||
expect(requestService.send).toHaveBeenCalledWith(jasmine.any(GetRequest), false);
|
||||
});
|
||||
|
||||
it('should return the entries', () => {
|
||||
result.subscribe((resultRD) => {
|
||||
expect(resultRD.payload.page).toBe(entries);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -74,7 +74,12 @@ export class ExternalSourceDataService extends IdentifiableDataService<ExternalS
|
||||
);
|
||||
|
||||
// TODO create a dedicated ExternalSourceEntryDataService and move this entire method to it. Then the "as any"s won't be necessary
|
||||
return this.findListByHref(href$, undefined, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow as any) as any;
|
||||
|
||||
return this.hasCachedErrorResponse(href$).pipe(
|
||||
switchMap((hasCachedErrorResponse) => {
|
||||
return this.findListByHref(href$, undefined, !hasCachedErrorResponse, reRequestOnStale, ...linksToFollow as any);
|
||||
})
|
||||
) as any;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -3,17 +3,38 @@
|
||||
*/
|
||||
|
||||
export enum Context {
|
||||
/** Default context */
|
||||
Any = 'undefined',
|
||||
|
||||
/** General item page context */
|
||||
ItemPage = 'itemPage',
|
||||
|
||||
/** General search page context */
|
||||
Search = 'search',
|
||||
|
||||
Workflow = 'workflow',
|
||||
Workspace = 'workspace',
|
||||
SupervisedItems = 'supervisedWorkspace',
|
||||
|
||||
/** Administrative menu context */
|
||||
AdminMenu = 'adminMenu',
|
||||
|
||||
EntitySearchModalWithNameVariants = 'EntitySearchModalWithNameVariants',
|
||||
EntitySearchModal = 'EntitySearchModal',
|
||||
|
||||
/** Administrative search page context */
|
||||
AdminSearch = 'adminSearch',
|
||||
AdminWorkflowSearch = 'adminWorkflowSearch',
|
||||
|
||||
SideBarSearchModal = 'sideBarSearchModal',
|
||||
SideBarSearchModalCurrent = 'sideBarSearchModalCurrent',
|
||||
|
||||
/** The MyDSpace* Context values below are used for badge display in MyDSpace. */
|
||||
MyDSpaceArchived = 'mydspaceArchived',
|
||||
MyDSpaceWorkspace = 'mydspaceWorkspace',
|
||||
MyDSpaceWorkflow = 'mydspaceWorkflow',
|
||||
MyDSpaceDeclined = 'mydspaceDeclined',
|
||||
MyDSpaceApproved = 'mydspaceApproved',
|
||||
MyDSpaceWaitingController = 'mydspaceWaitingController',
|
||||
MyDSpaceValidation = 'mydspaceValidation',
|
||||
}
|
||||
|
@@ -21,8 +21,8 @@ import { Version } from './version.model';
|
||||
import { VERSION } from './version.resource-type';
|
||||
import { BITSTREAM } from './bitstream.resource-type';
|
||||
import { Bitstream } from './bitstream.model';
|
||||
import { ACCESS_STATUS } from 'src/app/shared/object-list/access-status-badge/access-status.resource-type';
|
||||
import { AccessStatusObject } from 'src/app/shared/object-list/access-status-badge/access-status.model';
|
||||
import { ACCESS_STATUS } from 'src/app/shared/object-collection/shared/badges/access-status-badge/access-status.resource-type';
|
||||
import { AccessStatusObject } from 'src/app/shared/object-collection/shared/badges/access-status-badge/access-status.model';
|
||||
import { HandleObject } from './handle-object.model';
|
||||
import { IDENTIFIERS } from '../../shared/object-list/identifier-data/identifier-data.resource-type';
|
||||
import { IdentifierData } from '../../shared/object-list/identifier-data/identifier-data.model';
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { ChangeDetectorRef, Component, Input, OnInit } from '@angular/core';
|
||||
import { ScriptDataService } from '../core/data/processes/script-data.service';
|
||||
import { FormControl, FormGroup } from '@angular/forms';
|
||||
import { getFirstCompletedRemoteData } from '../core/shared/operators';
|
||||
@@ -40,7 +40,8 @@ export class CurationFormComponent implements OnInit {
|
||||
private notificationsService: NotificationsService,
|
||||
private translateService: TranslateService,
|
||||
private handleService: HandleService,
|
||||
private router: Router
|
||||
private router: Router,
|
||||
private cdr: ChangeDetectorRef
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -59,6 +60,7 @@ export class CurationFormComponent implements OnInit {
|
||||
.filter((value) => isNotEmpty(value) && value.includes('='))
|
||||
.map((value) => value.split('=')[1].trim());
|
||||
this.form.get('task').patchValue(this.tasks[0]);
|
||||
this.cdr.detectChanges();
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -7,7 +7,7 @@
|
||||
[dsDebounce]="300" (onDebounce)="confirm.emit(false)"></textarea>
|
||||
<div class="d-flex" *ngIf="mdRepresentation">
|
||||
<a class="mr-2" target="_blank" [routerLink]="mdRepresentationItemRoute$ | async">{{ mdRepresentationName$ | async }}</a>
|
||||
<ds-type-badge [object]="mdRepresentation"></ds-type-badge>
|
||||
<ds-themed-type-badge [object]="mdRepresentation"></ds-themed-type-badge>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ds-flex-cell ds-lang-cell" role="cell">
|
||||
|
@@ -68,7 +68,7 @@ describe('DsoEditMetadataValueComponent', () => {
|
||||
});
|
||||
|
||||
it('should not show a badge', () => {
|
||||
expect(fixture.debugElement.query(By.css('ds-type-badge'))).toBeNull();
|
||||
expect(fixture.debugElement.query(By.css('ds-themed-type-badge'))).toBeNull();
|
||||
});
|
||||
|
||||
describe('when no changes have been made', () => {
|
||||
@@ -134,7 +134,7 @@ describe('DsoEditMetadataValueComponent', () => {
|
||||
});
|
||||
|
||||
it('should show a badge', () => {
|
||||
expect(fixture.debugElement.query(By.css('ds-type-badge'))).toBeTruthy();
|
||||
expect(fixture.debugElement.query(By.css('ds-themed-type-badge'))).toBeTruthy();
|
||||
});
|
||||
|
||||
assertButton(EDIT_BTN, true, true);
|
||||
|
@@ -19,7 +19,7 @@
|
||||
</div>
|
||||
</span>
|
||||
<div class="card-body">
|
||||
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge>
|
||||
<ds-themed-badges *ngIf="showLabel" [object]="dso" [context]="context"></ds-themed-badges>
|
||||
<ds-truncatable-part [id]="dso.id" [minLines]="3" type="h4">
|
||||
<h4 class="card-title" [innerHTML]="dsoTitle"></h4>
|
||||
</ds-truncatable-part>
|
||||
|
@@ -19,7 +19,7 @@
|
||||
</div>
|
||||
</span>
|
||||
<div class="card-body">
|
||||
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge>
|
||||
<ds-themed-badges *ngIf="showLabel" [object]="dso" [context]="context"></ds-themed-badges>
|
||||
<ds-truncatable-part [id]="dso.id" [minLines]="3" type="h4">
|
||||
<h4 class="card-title" [innerHTML]="dsoTitle"></h4>
|
||||
</ds-truncatable-part>
|
||||
|
@@ -19,7 +19,7 @@
|
||||
</div>
|
||||
</span>
|
||||
<div class="card-body">
|
||||
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge>
|
||||
<ds-themed-badges *ngIf="showLabel" [object]="dso" [context]="context"></ds-themed-badges>
|
||||
<ds-truncatable-part [id]="dso.id" [minLines]="3" type="h4">
|
||||
<h4 class="card-title" [innerHTML]="dsoTitle"></h4>
|
||||
</ds-truncatable-part>
|
||||
|
@@ -12,7 +12,7 @@
|
||||
</span>
|
||||
</div>
|
||||
<div [ngClass]="showThumbnails ? 'col-9' : 'col-md-12'">
|
||||
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge>
|
||||
<ds-themed-badges *ngIf="showLabel" [object]="dso" [context]="context"></ds-themed-badges>
|
||||
<ds-truncatable [id]="dso.id">
|
||||
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'"
|
||||
rel="noopener noreferrer"
|
||||
|
@@ -12,7 +12,7 @@
|
||||
</span>
|
||||
</div>
|
||||
<div [ngClass]="showThumbnails ? 'col-9' : 'col-md-12'">
|
||||
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge>
|
||||
<ds-themed-badges *ngIf="showLabel" [object]="dso" [context]="context"></ds-themed-badges>
|
||||
<ds-truncatable [id]="dso.id">
|
||||
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'"
|
||||
rel="noopener noreferrer"
|
||||
|
@@ -11,7 +11,7 @@
|
||||
</span>
|
||||
</div>
|
||||
<div [ngClass]="showThumbnails ? 'col-9' : 'col-md-12'">
|
||||
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge>
|
||||
<ds-themed-badges *ngIf="showLabel" [object]="dso" [context]="context"></ds-themed-badges>
|
||||
<ds-truncatable [id]="dso.id">
|
||||
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'" rel="noopener noreferrer"
|
||||
[routerLink]="[itemPageRoute]" class="lead item-list-title dont-break-out"
|
||||
|
@@ -19,7 +19,7 @@
|
||||
</div>
|
||||
</span>
|
||||
<div class="card-body">
|
||||
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge>
|
||||
<ds-themed-badges *ngIf="showLabel" [object]="dso" [context]="context"></ds-themed-badges>
|
||||
<ds-truncatable-part [id]="dso.id" [minLines]="3" type="h4">
|
||||
<h4 class="card-title" [innerHTML]="dsoTitle"></h4>
|
||||
</ds-truncatable-part>
|
||||
|
@@ -19,7 +19,7 @@
|
||||
</div>
|
||||
</span>
|
||||
<div class="card-body">
|
||||
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge>
|
||||
<ds-themed-badges *ngIf="showLabel" [object]="dso" [context]="context"></ds-themed-badges>
|
||||
<ds-truncatable-part [id]="dso.id" [minLines]="3" type="h4">
|
||||
<h4 class="card-title" [innerHTML]="dsoTitle"></h4>
|
||||
</ds-truncatable-part>
|
||||
|
@@ -19,7 +19,7 @@
|
||||
</div>
|
||||
</span>
|
||||
<div class="card-body">
|
||||
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge>
|
||||
<ds-themed-badges *ngIf="showLabel" [object]="dso" [context]="context"></ds-themed-badges>
|
||||
<ds-truncatable-part [id]="dso.id" [minLines]="3" type="h4">
|
||||
<h4 class="card-title" [innerHTML]="dsoTitle"></h4>
|
||||
</ds-truncatable-part>
|
||||
|
@@ -18,7 +18,7 @@
|
||||
</span>
|
||||
</div>
|
||||
<div [ngClass]="showThumbnails ? 'col-9' : 'col-md-12'">
|
||||
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge>
|
||||
<ds-themed-badges *ngIf="showLabel" [object]="dso" [context]="context"></ds-themed-badges>
|
||||
<ds-truncatable [id]="dso.id">
|
||||
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'"
|
||||
rel="noopener noreferrer"
|
||||
|
@@ -18,7 +18,7 @@
|
||||
</span>
|
||||
</div>
|
||||
<div [ngClass]="showThumbnails ? 'col-9 col-md-10' : 'col-12'">
|
||||
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge>
|
||||
<ds-themed-badges *ngIf="showLabel" [object]="dso" [context]="context"></ds-themed-badges>
|
||||
<ds-truncatable [id]="dso.id">
|
||||
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'"
|
||||
rel="noopener noreferrer"
|
||||
|
@@ -19,7 +19,7 @@
|
||||
</div>
|
||||
<div [ngClass]="showThumbnails ? 'col-9' : 'col-md-12'">
|
||||
<ds-truncatable [id]="dso.id">
|
||||
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge>
|
||||
<ds-themed-badges *ngIf="showLabel" [object]="dso" [context]="context"></ds-themed-badges>
|
||||
<a *ngIf="linkType != linkTypes.None" [target]="(linkType == linkTypes.ExternalLink) ? '_blank' : '_self'"
|
||||
rel="noopener noreferrer"
|
||||
[routerLink]="[itemPageRoute]" class="lead item-list-title dont-break-out"
|
||||
|
@@ -1,7 +1,4 @@
|
||||
@media screen and (max-width: map-get($grid-breakpoints, md)) {
|
||||
:host.open {
|
||||
background-color: var(--bs-white);
|
||||
top: 0;
|
||||
position: sticky;
|
||||
}
|
||||
:host {
|
||||
position: relative;
|
||||
z-index: var(--ds-nav-z-index);
|
||||
}
|
||||
|
@@ -1,3 +0,0 @@
|
||||
:host {
|
||||
z-index: var(--ds-nav-z-index);
|
||||
}
|
@@ -11,13 +11,12 @@
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.navbar ::ng-deep {
|
||||
a {
|
||||
color: var(--ds-header-icon-color);
|
||||
.navbar-toggler {
|
||||
border: none;
|
||||
color: var(--ds-header-icon-color);
|
||||
|
||||
&:hover, &:focus {
|
||||
color: var(--ds-header-icon-color-hover);
|
||||
}
|
||||
&:hover, &:focus {
|
||||
color: var(--ds-header-icon-color-hover);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -4,6 +4,6 @@
|
||||
<ds-view-tracker [object]="site"></ds-view-tracker>
|
||||
</ng-container>
|
||||
<ds-themed-search-form [inPlaceSearch]="false" [searchPlaceholder]="'home.search-form.placeholder' | translate"></ds-themed-search-form>
|
||||
<ds-top-level-community-list></ds-top-level-community-list>
|
||||
<ds-themed-top-level-community-list></ds-themed-top-level-community-list>
|
||||
<ds-recent-item-list *ngIf="recentSubmissionspageSize>0"></ds-recent-item-list>
|
||||
</div>
|
||||
|
@@ -12,11 +12,13 @@ import { ThemedHomePageComponent } from './themed-home-page.component';
|
||||
import { RecentItemListComponent } from './recent-item-list/recent-item-list.component';
|
||||
import { JournalEntitiesModule } from '../entity-groups/journal-entities/journal-entities.module';
|
||||
import { ResearchEntitiesModule } from '../entity-groups/research-entities/research-entities.module';
|
||||
import { ThemedTopLevelCommunityListComponent } from './top-level-community-list/themed-top-level-community-list.component';
|
||||
|
||||
const DECLARATIONS = [
|
||||
HomePageComponent,
|
||||
ThemedHomePageComponent,
|
||||
TopLevelCommunityListComponent,
|
||||
ThemedTopLevelCommunityListComponent,
|
||||
ThemedHomeNewsComponent,
|
||||
HomeNewsComponent,
|
||||
RecentItemListComponent
|
||||
|
@@ -0,0 +1,25 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { TopLevelCommunityListComponent } from './top-level-community-list.component';
|
||||
import { ThemedComponent } from '../../shared/theme-support/themed.component';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-themed-top-level-community-list',
|
||||
styleUrls: [],
|
||||
templateUrl: '../../shared/theme-support/themed.component.html',
|
||||
})
|
||||
export class ThemedTopLevelCommunityListComponent extends ThemedComponent<TopLevelCommunityListComponent> {
|
||||
protected inAndOutputNames: (keyof TopLevelCommunityListComponent & keyof this)[];
|
||||
|
||||
protected getComponentName(): string {
|
||||
return 'TopLevelCommunityListComponent';
|
||||
}
|
||||
|
||||
protected importThemedComponent(themeName: string): Promise<any> {
|
||||
return import(`../../../themes/${themeName}/app/home-page/top-level-community-list/top-level-community-list.component`);
|
||||
}
|
||||
|
||||
protected importUnthemedComponent(): Promise<any> {
|
||||
return import(`./top-level-community-list.component`);
|
||||
}
|
||||
|
||||
}
|
@@ -38,7 +38,7 @@ import { IdentifierDataService } from '../../core/data/identifier-data.service';
|
||||
import { IdentifierDataComponent } from '../../shared/object-list/identifier-data/identifier-data.component';
|
||||
import { ItemRegisterDoiComponent } from './item-register-doi/item-register-doi.component';
|
||||
import { DsoSharedModule } from '../../dso-shared/dso-shared.module';
|
||||
|
||||
import { ItemCurateComponent } from './item-curate/item-curate.component';
|
||||
|
||||
/**
|
||||
* Module that contains all components related to the Edit Item page administrator functionality
|
||||
@@ -81,7 +81,8 @@ import { DsoSharedModule } from '../../dso-shared/dso-shared.module';
|
||||
VirtualMetadataComponent,
|
||||
ItemAuthorizationsComponent,
|
||||
IdentifierDataComponent,
|
||||
ItemRegisterDoiComponent
|
||||
ItemRegisterDoiComponent,
|
||||
ItemCurateComponent
|
||||
],
|
||||
providers: [
|
||||
BundleDataService,
|
||||
|
@@ -41,6 +41,7 @@ import { ItemPageVersionHistoryGuard } from './item-page-version-history.guard';
|
||||
import { ItemPageCollectionMapperGuard } from './item-page-collection-mapper.guard';
|
||||
import { ThemedDsoEditMetadataComponent } from '../../dso-shared/dso-edit-metadata/themed-dso-edit-metadata.component';
|
||||
import { ItemPageRegisterDoiGuard } from './item-page-register-doi.guard';
|
||||
import { ItemCurateComponent } from './item-curate/item-curate.component';
|
||||
|
||||
/**
|
||||
* Routing module that handles the routing for the Edit Item page administrator functionality
|
||||
@@ -82,6 +83,11 @@ import { ItemPageRegisterDoiGuard } from './item-page-register-doi.guard';
|
||||
data: { title: 'item.edit.tabs.metadata.title', showBreadcrumbs: true },
|
||||
canActivate: [ItemPageMetadataGuard]
|
||||
},
|
||||
{
|
||||
path: 'curate',
|
||||
component: ItemCurateComponent,
|
||||
data: { title: 'item.edit.tabs.curate.title', showBreadcrumbs: true }
|
||||
},
|
||||
{
|
||||
path: 'relationships',
|
||||
component: ItemRelationshipsComponent,
|
||||
|
@@ -0,0 +1,7 @@
|
||||
<div class="container mt-3">
|
||||
<h3>{{'item.edit.curate.title' |translate:{item: (itemName$ |async)} }}</h3>
|
||||
<ds-curation-form
|
||||
*ngIf="dsoRD$ | async as dsoRD"
|
||||
[dsoHandle]="dsoRD?.payload.handle"
|
||||
></ds-curation-form>
|
||||
</div>
|
@@ -0,0 +1,75 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA, DebugElement } from '@angular/core';
|
||||
import { ItemCurateComponent } from './item-curate.component';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { createSuccessfulRemoteDataObject } from '../../../shared/remote-data.utils';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
|
||||
import { Item } from '../../../core/shared/item.model';
|
||||
|
||||
describe('ItemCurateComponent', () => {
|
||||
let comp: ItemCurateComponent;
|
||||
let fixture: ComponentFixture<ItemCurateComponent>;
|
||||
let debugEl: DebugElement;
|
||||
|
||||
let routeStub;
|
||||
let dsoNameService;
|
||||
|
||||
const item = Object.assign(new Item(), {
|
||||
handle: '123456789/1',
|
||||
metadata: {'dc.title': ['Item Name']}
|
||||
});
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
routeStub = {
|
||||
parent: {
|
||||
data: observableOf({
|
||||
dso: createSuccessfulRemoteDataObject(item)
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
dsoNameService = jasmine.createSpyObj('dsoNameService', {
|
||||
getName: 'Item Name'
|
||||
});
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
imports: [TranslateModule.forRoot()],
|
||||
declarations: [ItemCurateComponent],
|
||||
providers: [
|
||||
{provide: ActivatedRoute, useValue: routeStub},
|
||||
{provide: DSONameService, useValue: dsoNameService}
|
||||
],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ItemCurateComponent);
|
||||
comp = fixture.componentInstance;
|
||||
debugEl = fixture.debugElement;
|
||||
|
||||
fixture.detectChanges();
|
||||
});
|
||||
describe('init', () => {
|
||||
it('should initialise the comp', () => {
|
||||
expect(comp).toBeDefined();
|
||||
expect(debugEl.nativeElement.innerHTML).toContain('ds-curation-form');
|
||||
});
|
||||
|
||||
it('should contain the item information provided in the route', (done) => {
|
||||
comp.dsoRD$.subscribe((value) => {
|
||||
expect(value.payload.handle).toEqual('123456789/1');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should contain the item name', (done) => {
|
||||
comp.itemName$.subscribe((value) => {
|
||||
expect(value).toEqual('Item Name');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@@ -0,0 +1,39 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { filter, map, take } from 'rxjs/operators';
|
||||
import { RemoteData } from '../../../core/data/remote-data';
|
||||
import { Observable } from 'rxjs';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
|
||||
import { hasValue } from '../../../shared/empty.util';
|
||||
import { Item } from '../../../core/shared/item.model';
|
||||
|
||||
/**
|
||||
* Component for managing a collection's curation tasks
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-item-curate',
|
||||
templateUrl: './item-curate.component.html',
|
||||
})
|
||||
export class ItemCurateComponent implements OnInit {
|
||||
dsoRD$: Observable<RemoteData<Item>>;
|
||||
itemName$: Observable<string>;
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private dsoNameService: DSONameService,
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.dsoRD$ = this.route.parent.data.pipe(
|
||||
take(1),
|
||||
map((data) => data.dso),
|
||||
);
|
||||
|
||||
this.itemName$ = this.dsoRD$.pipe(
|
||||
filter((rd: RemoteData<Item>) => hasValue(rd)),
|
||||
map((rd: RemoteData<Item>) => {
|
||||
return this.dsoNameService.getName(rd.payload);
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
@@ -8,10 +8,10 @@
|
||||
</ds-themed-file-download-link>
|
||||
<ds-themed-loading *ngIf="isLoading" message="{{'loading.default' | translate}}" [showMessage]="false"></ds-themed-loading>
|
||||
<div *ngIf="!isLastPage" class="mt-1" id="view-more">
|
||||
<a class="bitstream-view-more btn btn-outline-secondary btn-sm" [routerLink]="[]" (click)="getNextPage()">{{'item.page.bitstreams.view-more' | translate}}</a>
|
||||
<button class="bitstream-view-more btn btn-outline-secondary btn-sm" (click)="getNextPage()">{{'item.page.bitstreams.view-more' | translate}}</button>
|
||||
</div>
|
||||
<div *ngIf="isLastPage && currentPage != 1" class="mt-1" id="collapse">
|
||||
<a class="bitstream-collapse btn btn-outline-secondary btn-sm" [routerLink]="[]" (click)="currentPage = undefined; getNextPage();">{{'item.page.bitstreams.collapse' | translate}}</a>
|
||||
<button class="bitstream-collapse btn btn-outline-secondary btn-sm" (click)="currentPage = undefined; getNextPage();">{{'item.page.bitstreams.collapse' | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</ds-metadata-field-wrapper>
|
||||
|
@@ -7,12 +7,12 @@
|
||||
<ds-themed-loading *ngIf="(i + 1) === objects.length && (i > 0) && (!representations || representations?.length === 0)" message="{{'loading.default' | translate}}"></ds-themed-loading>
|
||||
<div class="d-inline-block w-100 mt-2" *ngIf="(i + 1) === objects.length && representations?.length > 0">
|
||||
<div *ngIf="(objects.length * incrementBy) < total" class="float-left">
|
||||
<a [routerLink]="[]" (click)="increase()">{{'item.page.related-items.view-more' |
|
||||
translate:{ amount: (total - (objects.length * incrementBy) < incrementBy) ? total - (objects.length * incrementBy) : incrementBy } }}</a>
|
||||
<button class="btn btn-link btn-link-inline" (click)="increase()">{{'item.page.related-items.view-more' |
|
||||
translate:{ amount: (total - (objects.length * incrementBy) < incrementBy) ? total - (objects.length * incrementBy) : incrementBy } }}</button>
|
||||
</div>
|
||||
<div *ngIf="objects.length > 1" class="float-right">
|
||||
<a [routerLink]="[]" (click)="decrease()">{{'item.page.related-items.view-less' |
|
||||
translate:{ amount: representations?.length } }}</a>
|
||||
<button class="btn btn-link btn-link-inline" (click)="decrease()">{{'item.page.related-items.view-less' |
|
||||
translate:{ amount: representations?.length } }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
@@ -7,12 +7,12 @@
|
||||
<ds-themed-loading *ngIf="(i + 1) === objects.length && (itemsRD || i > 0) && !(itemsRD?.hasSucceeded && itemsRD?.payload && itemsRD?.payload?.page?.length > 0)" message="{{'loading.default' | translate}}"></ds-themed-loading>
|
||||
<div class="d-inline-block w-100 mt-2" *ngIf="(i + 1) === objects.length && itemsRD?.payload?.page?.length > 0">
|
||||
<div *ngIf="itemsRD?.payload?.totalPages > objects.length" class="float-left" id="view-more">
|
||||
<a [routerLink]="[]" (click)="increase()">{{'item.page.related-items.view-more' |
|
||||
translate:{ amount: (itemsRD?.payload?.totalElements - (incrementBy * objects.length) < incrementBy) ? itemsRD?.payload?.totalElements - (incrementBy * objects.length) : incrementBy } }}</a>
|
||||
<button class="btn btn-link btn-link-inline" (click)="increase()">{{'item.page.related-items.view-more' |
|
||||
translate:{ amount: (itemsRD?.payload?.totalElements - (incrementBy * objects.length) < incrementBy) ? itemsRD?.payload?.totalElements - (incrementBy * objects.length) : incrementBy } }}</button>
|
||||
</div>
|
||||
<div *ngIf="objects.length > 1" class="float-right" id="view-less">
|
||||
<a [routerLink]="[]" (click)="decrease()">{{'item.page.related-items.view-less' |
|
||||
translate:{ amount: itemsRD?.payload?.page?.length } }}</a>
|
||||
<button class="btn btn-link btn-link-inline" (click)="decrease()">{{'item.page.related-items.view-less' |
|
||||
translate:{ amount: itemsRD?.payload?.page?.length } }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
@@ -23,7 +23,6 @@ import { ItemDetailPreviewComponent } from '../shared/object-detail/my-dspace-re
|
||||
import { ItemDetailPreviewFieldComponent } from '../shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/item-detail-preview-field.component';
|
||||
import { ItemListPreviewComponent } from '../shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component';
|
||||
import { ThemedItemListPreviewComponent } from '../shared/object-list/my-dspace-result-list-element/item-list-preview/themed-item-list-preview.component';
|
||||
import { MyDSpaceItemStatusComponent } from '../shared/object-collection/shared/mydspace-item-status/my-dspace-item-status.component';
|
||||
import { JournalEntitiesModule } from '../entity-groups/journal-entities/journal-entities.module';
|
||||
import { MyDSpaceActionsModule } from '../shared/mydspace-actions/mydspace-actions.module';
|
||||
import { ClaimedDeclinedTaskSearchResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-declined-task-search-result/claimed-declined-task-search-result-list-element.component';
|
||||
@@ -52,7 +51,6 @@ const DECLARATIONS = [
|
||||
ItemDetailPreviewFieldComponent,
|
||||
ItemListPreviewComponent,
|
||||
ThemedItemListPreviewComponent,
|
||||
MyDSpaceItemStatusComponent,
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
@@ -1,11 +1,11 @@
|
||||
<div class="form-group" *ngIf="script">
|
||||
<label>{{'process.new.select-parameters' | translate}}</label>
|
||||
<ds-parameter-select
|
||||
*ngFor="let value of parameterValues; let i = index; let last = last"
|
||||
[parameters]="script.parameters"
|
||||
[parameterValue]="value"
|
||||
[removable]="!last"
|
||||
[index]="i"
|
||||
(removeParameter)="removeParameter(i)"
|
||||
(changeParameter)="updateParameter($event, i)"></ds-parameter-select>
|
||||
<div class="form-group" *ngIf="script?.parameters?.length" data-testID="parameters-select-container">
|
||||
<label>{{'process.new.select-parameters' | translate}}</label>
|
||||
<ds-parameter-select
|
||||
*ngFor="let value of parameterValues; let i = index; let last = last"
|
||||
[parameters]="script.parameters"
|
||||
[parameterValue]="value"
|
||||
[removable]="!last"
|
||||
[index]="i"
|
||||
(removeParameter)="removeParameter(i)"
|
||||
(changeParameter)="updateParameter($event, i)"></ds-parameter-select>
|
||||
</div>
|
||||
|
@@ -14,14 +14,14 @@ import { TranslateLoaderMock } from '../../../shared/mocks/translate-loader.mock
|
||||
describe('ProcessParametersComponent', () => {
|
||||
let component: ProcessParametersComponent;
|
||||
let fixture: ComponentFixture<ProcessParametersComponent>;
|
||||
let parameterValues;
|
||||
let script;
|
||||
let mockParameterValues: ProcessParameter[];
|
||||
let mockScript: Script;
|
||||
|
||||
function init() {
|
||||
function initParametersAndScriptMockValues() {
|
||||
const param1 = new ScriptParameter();
|
||||
const param2 = new ScriptParameter();
|
||||
script = Object.assign(new Script(), { parameters: [param1, param2] });
|
||||
parameterValues = [
|
||||
mockScript = Object.assign(new Script(), { parameters: [param1, param2] });
|
||||
mockParameterValues = [
|
||||
Object.assign(new ProcessParameter(), { name: '-a', value: 'bla' }),
|
||||
Object.assign(new ProcessParameter(), { name: '-b', value: '123' }),
|
||||
Object.assign(new ProcessParameter(), { name: '-c', value: 'value' }),
|
||||
@@ -29,7 +29,6 @@ describe('ProcessParametersComponent', () => {
|
||||
}
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
init();
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
FormsModule,
|
||||
@@ -48,17 +47,34 @@ describe('ProcessParametersComponent', () => {
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ProcessParametersComponent);
|
||||
component = fixture.componentInstance;
|
||||
component.script = script;
|
||||
component.parameterValues = parameterValues;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should render a ParameterSelectComponent for each parameter value of the component', () => {
|
||||
const selectComponents = fixture.debugElement.queryAll(By.directive(ParameterSelectComponent));
|
||||
expect(selectComponents.length).toBe(parameterValues.length);
|
||||
describe('when parameter values and script are initialized', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
initParametersAndScriptMockValues();
|
||||
component.parameterValues = mockParameterValues;
|
||||
component.script = mockScript;
|
||||
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it(`should render a ${ParameterSelectComponent.name} for each parameter value`, () => {
|
||||
const selectComponents = fixture.debugElement.queryAll(By.directive(ParameterSelectComponent));
|
||||
expect(selectComponents.length).toBe(mockParameterValues.length);
|
||||
});
|
||||
|
||||
it('should not render a selector box if the parameter array is empty',() => {
|
||||
fixture.componentInstance.script.parameters = [];
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const formGroupComponent = fixture.debugElement.query(By.css('[data-testID=parameters-select-container]'));
|
||||
expect(formGroupComponent).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
48
src/app/process-page/process-page-shared.module.ts
Normal file
48
src/app/process-page/process-page-shared.module.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { SharedModule } from '../shared/shared.module';
|
||||
import { NewProcessComponent } from './new/new-process.component';
|
||||
import { ScriptsSelectComponent } from './form/scripts-select/scripts-select.component';
|
||||
import { ScriptHelpComponent } from './form/script-help/script-help.component';
|
||||
import { ParameterSelectComponent } from './form/process-parameters/parameter-select/parameter-select.component';
|
||||
import { ProcessParametersComponent } from './form/process-parameters/process-parameters.component';
|
||||
import { StringValueInputComponent } from './form/process-parameters/parameter-value-input/string-value-input/string-value-input.component';
|
||||
import { ParameterValueInputComponent } from './form/process-parameters/parameter-value-input/parameter-value-input.component';
|
||||
import { FileValueInputComponent } from './form/process-parameters/parameter-value-input/file-value-input/file-value-input.component';
|
||||
import { BooleanValueInputComponent } from './form/process-parameters/parameter-value-input/boolean-value-input/boolean-value-input.component';
|
||||
import { DateValueInputComponent } from './form/process-parameters/parameter-value-input/date-value-input/date-value-input.component';
|
||||
import { ProcessOverviewComponent } from './overview/process-overview.component';
|
||||
import { ProcessDetailComponent } from './detail/process-detail.component';
|
||||
import { ProcessDetailFieldComponent } from './detail/process-detail-field/process-detail-field.component';
|
||||
import { ProcessBreadcrumbsService } from './process-breadcrumbs.service';
|
||||
import { ProcessBreadcrumbResolver } from './process-breadcrumb.resolver';
|
||||
import { ProcessFormComponent } from './form/process-form.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
SharedModule,
|
||||
],
|
||||
declarations: [
|
||||
NewProcessComponent,
|
||||
ScriptsSelectComponent,
|
||||
ScriptHelpComponent,
|
||||
ParameterSelectComponent,
|
||||
ProcessParametersComponent,
|
||||
StringValueInputComponent,
|
||||
ParameterValueInputComponent,
|
||||
FileValueInputComponent,
|
||||
BooleanValueInputComponent,
|
||||
DateValueInputComponent,
|
||||
ProcessOverviewComponent,
|
||||
ProcessDetailComponent,
|
||||
ProcessDetailFieldComponent,
|
||||
ProcessFormComponent
|
||||
],
|
||||
providers: [
|
||||
ProcessBreadcrumbResolver,
|
||||
ProcessBreadcrumbsService
|
||||
]
|
||||
})
|
||||
|
||||
export class ProcessPageSharedModule {
|
||||
|
||||
}
|
@@ -1,47 +1,17 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { SharedModule } from '../shared/shared.module';
|
||||
import { ProcessPageRoutingModule } from './process-page-routing.module';
|
||||
import { NewProcessComponent } from './new/new-process.component';
|
||||
import { ScriptsSelectComponent } from './form/scripts-select/scripts-select.component';
|
||||
import { ScriptHelpComponent } from './form/script-help/script-help.component';
|
||||
import { ParameterSelectComponent } from './form/process-parameters/parameter-select/parameter-select.component';
|
||||
import { ProcessParametersComponent } from './form/process-parameters/process-parameters.component';
|
||||
import { StringValueInputComponent } from './form/process-parameters/parameter-value-input/string-value-input/string-value-input.component';
|
||||
import { ParameterValueInputComponent } from './form/process-parameters/parameter-value-input/parameter-value-input.component';
|
||||
import { FileValueInputComponent } from './form/process-parameters/parameter-value-input/file-value-input/file-value-input.component';
|
||||
import { BooleanValueInputComponent } from './form/process-parameters/parameter-value-input/boolean-value-input/boolean-value-input.component';
|
||||
import { DateValueInputComponent } from './form/process-parameters/parameter-value-input/date-value-input/date-value-input.component';
|
||||
import { ProcessOverviewComponent } from './overview/process-overview.component';
|
||||
import { ProcessDetailComponent } from './detail/process-detail.component';
|
||||
import { ProcessDetailFieldComponent } from './detail/process-detail-field/process-detail-field.component';
|
||||
import { ProcessBreadcrumbsService } from './process-breadcrumbs.service';
|
||||
import { ProcessBreadcrumbResolver } from './process-breadcrumb.resolver';
|
||||
import { ProcessFormComponent } from './form/process-form.component';
|
||||
import { ProcessPageSharedModule } from './process-page-shared.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
ProcessPageRoutingModule,
|
||||
SharedModule,
|
||||
ProcessPageSharedModule,
|
||||
],
|
||||
declarations: [
|
||||
NewProcessComponent,
|
||||
ScriptsSelectComponent,
|
||||
ScriptHelpComponent,
|
||||
ParameterSelectComponent,
|
||||
ProcessParametersComponent,
|
||||
StringValueInputComponent,
|
||||
ParameterValueInputComponent,
|
||||
FileValueInputComponent,
|
||||
BooleanValueInputComponent,
|
||||
DateValueInputComponent,
|
||||
ProcessOverviewComponent,
|
||||
ProcessDetailComponent,
|
||||
ProcessDetailFieldComponent,
|
||||
ProcessFormComponent
|
||||
],
|
||||
providers: [
|
||||
ProcessBreadcrumbResolver,
|
||||
ProcessBreadcrumbsService
|
||||
]
|
||||
})
|
||||
|
||||
|
@@ -4,9 +4,9 @@
|
||||
<input #searchInput [@toggleAnimation]="isExpanded" [attr.aria-label]="('nav.search' | translate)" name="query"
|
||||
formControlName="query" type="text" placeholder="{{searchExpanded ? ('nav.search' | translate) : ''}}"
|
||||
class="d-inline-block bg-transparent position-absolute form-control dropdown-menu-right p-1" [attr.data-test]="'header-search-box' | dsBrowserOnly">
|
||||
<a class="submit-icon" [routerLink]="" (click)="searchExpanded ? onSubmit(searchForm.value) : expand()" [attr.data-test]="'header-search-icon' | dsBrowserOnly">
|
||||
<button class="submit-icon btn btn-link btn-link-inline" [attr.aria-label]="'nav.search.button' | translate" type="button" (click)="searchExpanded ? onSubmit(searchForm.value) : expand()" [attr.data-test]="'header-search-icon' | dsBrowserOnly">
|
||||
<em class="fas fa-search fa-lg fa-fw"></em>
|
||||
</a>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -1,13 +1,14 @@
|
||||
input[type="text"] {
|
||||
margin-top: calc(-0.5 * var(--bs-font-size-base));
|
||||
background-color: #fff !important;
|
||||
border-color: var(--ds-header-icon-color);
|
||||
|
||||
&.collapsed {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
a.submit-icon {
|
||||
.submit-icon {
|
||||
cursor: pointer;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
|
@@ -19,7 +19,7 @@
|
||||
</li>
|
||||
<li *ngIf="(isAuthenticated | async) && !(isXsOrSm$ | async) && (showAuth | async)" class="nav-item">
|
||||
<div ngbDropdown display="dynamic" placement="bottom-right" class="d-inline-block" @fadeInOut>
|
||||
<a href="javascript:void(0);" role="button" [attr.aria-label]="'nav.user-profile-menu-and-logout' |translate" (click)="$event.preventDefault()" [title]="'nav.user-profile-menu-and-logout' | translate" class="px-1" [attr.data-test]="'user-menu' | dsBrowserOnly" ngbDropdownToggle>
|
||||
<a href="javascript:void(0);" role="button" [attr.aria-label]="'nav.user-profile-menu-and-logout' |translate" (click)="$event.preventDefault()" [title]="'nav.user-profile-menu-and-logout' | translate" class="dropdownLogout px-1" [attr.data-test]="'user-menu' | dsBrowserOnly" ngbDropdownToggle>
|
||||
<i class="fas fa-user-circle fa-lg fa-fw"></i></a>
|
||||
<div class="logoutDropdownMenu" ngbDropdownMenu [attr.aria-label]="'nav.user-profile-menu-and-logout' |translate">
|
||||
<ds-user-menu></ds-user-menu>
|
||||
@@ -27,7 +27,7 @@
|
||||
</div>
|
||||
</li>
|
||||
<li *ngIf="(isAuthenticated | async) && (isXsOrSm$ | async)" class="nav-item">
|
||||
<a id="logoutLink" role="button" [attr.aria-label]="'nav.logout' |translate" [title]="'nav.logout' | translate" routerLink="/logout" routerLinkActive="active" class="px-1">
|
||||
<a role="button" [attr.aria-label]="'nav.logout' |translate" [title]="'nav.logout' | translate" routerLink="/logout" routerLinkActive="active" class="logoutLink px-1">
|
||||
<i class="fas fa-sign-out-alt fa-lg fa-fw"></i>
|
||||
<span class="sr-only">(current)</span>
|
||||
</a>
|
||||
|
@@ -12,7 +12,7 @@
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.dropdown-toggle {
|
||||
.loginLink, .dropdownLogin, .logoutLink, .dropdownLogout {
|
||||
color: var(--ds-header-icon-color);
|
||||
|
||||
&:hover, &:focus {
|
||||
|
@@ -358,7 +358,7 @@ describe('AuthNavMenuComponent', () => {
|
||||
});
|
||||
|
||||
it('should render logout link', inject([Store], (store: Store<AppState>) => {
|
||||
const logoutDropdownMenu = deNavMenuItem.query(By.css('a[id=logoutLink]'));
|
||||
const logoutDropdownMenu = deNavMenuItem.query(By.css('a.logoutLink'));
|
||||
expect(logoutDropdownMenu.nativeElement).toBeDefined();
|
||||
}));
|
||||
});
|
||||
|
@@ -14,6 +14,7 @@ export function getMockRequestService(requestEntry$: Observable<RequestEntry> =
|
||||
removeByHrefSubstring: observableOf(true),
|
||||
setStaleByHrefSubstring: observableOf(true),
|
||||
setStaleByUUID: observableOf(true),
|
||||
hasByHref$: observableOf(false)
|
||||
hasByHref$: observableOf(false),
|
||||
shouldDispatchRequest: true
|
||||
});
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<ng-container *ngIf="showAccessStatus">
|
||||
<div *ngIf="accessStatus$ | async as accessStatus">
|
||||
<span *ngIf="accessStatus$ | async as accessStatus">
|
||||
<span class="badge badge-secondary">{{ accessStatus | translate }}</span>
|
||||
</div>
|
||||
</span>
|
||||
</ng-container>
|
@@ -1,10 +1,10 @@
|
||||
import { Item } from '../../../core/shared/item.model';
|
||||
import { Item } from '../../../../../core/shared/item.model';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { TruncatePipe } from '../../utils/truncate.pipe';
|
||||
import { TruncatePipe } from '../../../../utils/truncate.pipe';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { AccessStatusBadgeComponent } from './access-status-badge.component';
|
||||
import { createSuccessfulRemoteDataObject$ } from '../../remote-data.utils';
|
||||
import { createSuccessfulRemoteDataObject$ } from '../../../../remote-data.utils';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { AccessStatusObject } from './access-status.model';
|
||||
import { AccessStatusDataService } from 'src/app/core/data/access-status-data.service';
|
||||
@@ -50,7 +50,8 @@ describe('ItemAccessStatusBadgeComponent', () => {
|
||||
});
|
||||
|
||||
item = Object.assign(new Item(), {
|
||||
uuid: 'item-uuid'
|
||||
uuid: 'item-uuid',
|
||||
type: 'item'
|
||||
});
|
||||
}
|
||||
|
||||
@@ -69,7 +70,7 @@ describe('ItemAccessStatusBadgeComponent', () => {
|
||||
environment.item.showAccessStatuses = true;
|
||||
fixture = TestBed.createComponent(AccessStatusBadgeComponent);
|
||||
component = fixture.componentInstance;
|
||||
component.item = item;
|
||||
component.object = item;
|
||||
fixture.detectChanges();
|
||||
environment.item.showAccessStatuses = false;
|
||||
}
|
@@ -2,10 +2,12 @@ import { Component, Input } from '@angular/core';
|
||||
import { catchError, map } from 'rxjs/operators';
|
||||
import { Observable, of as observableOf } from 'rxjs';
|
||||
import { AccessStatusObject } from './access-status.model';
|
||||
import { hasValue } from '../../empty.util';
|
||||
import { hasValue } from '../../../../empty.util';
|
||||
import { environment } from 'src/environments/environment';
|
||||
import { Item } from 'src/app/core/shared/item.model';
|
||||
import { AccessStatusDataService } from 'src/app/core/data/access-status-data.service';
|
||||
import { DSpaceObject } from '../../../../../core/shared/dspace-object.model';
|
||||
import { Item } from '../../../../../core/shared/item.model';
|
||||
import { ITEM } from '../../../../../core/shared/item.resource-type';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-access-status-badge',
|
||||
@@ -16,7 +18,7 @@ import { AccessStatusDataService } from 'src/app/core/data/access-status-data.se
|
||||
*/
|
||||
export class AccessStatusBadgeComponent {
|
||||
|
||||
@Input() item: Item;
|
||||
@Input() object: DSpaceObject;
|
||||
accessStatus$: Observable<string>;
|
||||
|
||||
/**
|
||||
@@ -33,15 +35,17 @@ export class AccessStatusBadgeComponent {
|
||||
|
||||
ngOnInit(): void {
|
||||
this.showAccessStatus = environment.item.showAccessStatuses;
|
||||
if (!this.showAccessStatus || this.item == null) {
|
||||
if (this.object.type.toString() !== ITEM.value || !this.showAccessStatus || this.object == null) {
|
||||
// Do not show the badge if the feature is inactive or if the item is null.
|
||||
return;
|
||||
}
|
||||
if (this.item.accessStatus == null) {
|
||||
|
||||
const item = this.object as Item;
|
||||
if (item.accessStatus == null) {
|
||||
// In case the access status has not been loaded, do it individually.
|
||||
this.item.accessStatus = this.accessStatusDataService.findAccessStatusFor(this.item);
|
||||
item.accessStatus = this.accessStatusDataService.findAccessStatusFor(item);
|
||||
}
|
||||
this.accessStatus$ = this.item.accessStatus.pipe(
|
||||
this.accessStatus$ = item.accessStatus.pipe(
|
||||
map((accessStatusRD) => {
|
||||
if (accessStatusRD.statusCode !== 401 && hasValue(accessStatusRD.payload)) {
|
||||
return accessStatusRD.payload;
|
@@ -0,0 +1,30 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { ThemedComponent } from '../../../../theme-support/themed.component';
|
||||
import { AccessStatusBadgeComponent } from './access-status-badge.component';
|
||||
import { DSpaceObject } from '../../../../../core/shared/dspace-object.model';
|
||||
|
||||
/**
|
||||
* Themed wrapper for AccessStatusBadgeComponent
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-themed-access-status-badge',
|
||||
styleUrls: [],
|
||||
templateUrl: '../../../../theme-support/themed.component.html',
|
||||
})
|
||||
export class ThemedAccessStatusBadgeComponent extends ThemedComponent<AccessStatusBadgeComponent> {
|
||||
@Input() object: DSpaceObject;
|
||||
|
||||
protected inAndOutputNames: (keyof AccessStatusBadgeComponent & keyof this)[] = ['object'];
|
||||
|
||||
protected getComponentName(): string {
|
||||
return 'AccessStatusBadgeComponent';
|
||||
}
|
||||
|
||||
protected importThemedComponent(themeName: string): Promise<any> {
|
||||
return import(`../../../../../../themes/${themeName}/app/shared/object-collection/shared/badges/access-status-badge/access-status-badge.component`);
|
||||
}
|
||||
|
||||
protected importUnthemedComponent(): Promise<any> {
|
||||
return import(`./access-status-badge.component`);
|
||||
}
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
<ds-themed-status-badge [object]="object"></ds-themed-status-badge>
|
||||
<ng-container *ngIf="isMyDSpaceStatus">
|
||||
<ds-themed-my-dspace-status-badge [context]="context"></ds-themed-my-dspace-status-badge>
|
||||
</ng-container>
|
||||
<div>
|
||||
<ds-themed-type-badge class="pr-1" [object]="object"></ds-themed-type-badge>
|
||||
<ng-container *ngIf="showAccessStatus">
|
||||
<ds-themed-access-status-badge [object]="object"></ds-themed-access-status-badge>
|
||||
</ng-container>
|
||||
</div>
|
@@ -0,0 +1,30 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { BadgesComponent } from './badges.component';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { ThemeService } from '../../../theme-support/theme.service';
|
||||
import { getMockThemeService } from '../../../mocks/theme-service.mock';
|
||||
|
||||
describe('BadgesComponent', () => {
|
||||
let component: BadgesComponent;
|
||||
let fixture: ComponentFixture<BadgesComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ BadgesComponent ],
|
||||
providers: [{provide: ThemeService, useValue: getMockThemeService()}],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(BadgesComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@@ -0,0 +1,47 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { Context } from 'src/app/core/shared/context.model';
|
||||
import { DSpaceObject } from '../../../../core/shared/dspace-object.model';
|
||||
|
||||
/**
|
||||
* List of MyDSpace Status Contexts
|
||||
*/
|
||||
const MY_DSPACE_STATUS_CONTEXTS = [
|
||||
Context.MyDSpaceArchived,
|
||||
Context.MyDSpaceWorkspace,
|
||||
Context.MyDSpaceWorkflow,
|
||||
Context.MyDSpaceDeclined,
|
||||
Context.MyDSpaceApproved,
|
||||
Context.MyDSpaceWaitingController,
|
||||
Context.MyDSpaceValidation
|
||||
];
|
||||
|
||||
/**
|
||||
* Component that renders all the badges for a listable object
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-badges',
|
||||
templateUrl: './badges.component.html',
|
||||
styleUrls: ['./badges.component.scss']
|
||||
})
|
||||
export class BadgesComponent {
|
||||
/**
|
||||
* The DSpaceObject to render the badge for
|
||||
*/
|
||||
@Input() object: DSpaceObject;
|
||||
/**
|
||||
* The context that the badge is rendered in
|
||||
*/
|
||||
@Input() context?: Context;
|
||||
|
||||
/**
|
||||
* Whether or not to show the access status
|
||||
*/
|
||||
@Input() showAccessStatus = false;
|
||||
|
||||
/**
|
||||
* Returns whether or not this context is a MyDSpace status context
|
||||
*/
|
||||
get isMyDSpaceStatus(): boolean {
|
||||
return MY_DSPACE_STATUS_CONTEXTS.includes(this.context);
|
||||
}
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
<div>
|
||||
<span [className]="badgeClass">
|
||||
{{badgeContent | translate}}
|
||||
{{('mydspace.status.' + badgeContent) | translate}}
|
||||
</span>
|
||||
</div>
|
@@ -4,17 +4,17 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model';
|
||||
import { PoolTask } from '../../../../core/tasks/models/pool-task-object.model';
|
||||
import { EPersonMock } from '../../../testing/eperson.mock';
|
||||
import { MyDSpaceItemStatusComponent } from './my-dspace-item-status.component';
|
||||
import { MyDspaceItemStatusType } from './my-dspace-item-status-type';
|
||||
import { TranslateLoaderMock } from '../../../mocks/translate-loader.mock';
|
||||
import { WorkflowItem } from '../../../../../core/submission/models/workflowitem.model';
|
||||
import { PoolTask } from '../../../../../core/tasks/models/pool-task-object.model';
|
||||
import { EPersonMock } from '../../../../testing/eperson.mock';
|
||||
import { MyDSpaceStatusBadgeComponent } from './my-dspace-status-badge.component';
|
||||
import { TranslateLoaderMock } from '../../../../mocks/translate-loader.mock';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { createSuccessfulRemoteDataObject } from '../../../remote-data.utils';
|
||||
import { createSuccessfulRemoteDataObject } from '../../../../remote-data.utils';
|
||||
import { Context } from '../../../../../core/shared/context.model';
|
||||
|
||||
let component: MyDSpaceItemStatusComponent;
|
||||
let fixture: ComponentFixture<MyDSpaceItemStatusComponent>;
|
||||
let component: MyDSpaceStatusBadgeComponent;
|
||||
let fixture: ComponentFixture<MyDSpaceStatusBadgeComponent>;
|
||||
|
||||
let mockResultObject: PoolTask;
|
||||
|
||||
@@ -34,15 +34,15 @@ describe('MyDSpaceItemStatusComponent', () => {
|
||||
}
|
||||
})
|
||||
],
|
||||
declarations: [MyDSpaceItemStatusComponent],
|
||||
declarations: [MyDSpaceStatusBadgeComponent],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
}).overrideComponent(MyDSpaceItemStatusComponent, {
|
||||
}).overrideComponent(MyDSpaceStatusBadgeComponent, {
|
||||
set: { changeDetection: ChangeDetectionStrategy.Default }
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(MyDSpaceItemStatusComponent);
|
||||
fixture = TestBed.createComponent(MyDSpaceStatusBadgeComponent);
|
||||
component = fixture.componentInstance;
|
||||
});
|
||||
|
||||
@@ -52,37 +52,37 @@ describe('MyDSpaceItemStatusComponent', () => {
|
||||
});
|
||||
|
||||
it('should init badge content and class', () => {
|
||||
component.status = MyDspaceItemStatusType.VALIDATION;
|
||||
component.context = Context.MyDSpaceValidation;
|
||||
fixture.detectChanges();
|
||||
expect(component.badgeContent).toBe(MyDspaceItemStatusType.VALIDATION);
|
||||
expect(component.badgeContent).toBe(Context.MyDSpaceValidation);
|
||||
expect(component.badgeClass).toBe('text-light badge badge-validation');
|
||||
});
|
||||
|
||||
it('should init badge content and class', () => {
|
||||
component.status = MyDspaceItemStatusType.WAITING_CONTROLLER;
|
||||
component.context = Context.MyDSpaceWaitingController;
|
||||
fixture.detectChanges();
|
||||
expect(component.badgeContent).toBe(MyDspaceItemStatusType.WAITING_CONTROLLER);
|
||||
expect(component.badgeContent).toBe(Context.MyDSpaceWaitingController);
|
||||
expect(component.badgeClass).toBe('text-light badge badge-waiting-controller');
|
||||
});
|
||||
|
||||
it('should init badge content and class', () => {
|
||||
component.status = MyDspaceItemStatusType.WORKSPACE;
|
||||
component.context = Context.MyDSpaceWorkspace;
|
||||
fixture.detectChanges();
|
||||
expect(component.badgeContent).toBe(MyDspaceItemStatusType.WORKSPACE);
|
||||
expect(component.badgeContent).toBe(Context.MyDSpaceWorkspace);
|
||||
expect(component.badgeClass).toBe('text-light badge badge-workspace');
|
||||
});
|
||||
|
||||
it('should init badge content and class', () => {
|
||||
component.status = MyDspaceItemStatusType.ARCHIVED;
|
||||
component.context = Context.MyDSpaceArchived;
|
||||
fixture.detectChanges();
|
||||
expect(component.badgeContent).toBe(MyDspaceItemStatusType.ARCHIVED);
|
||||
expect(component.badgeContent).toBe(Context.MyDSpaceArchived);
|
||||
expect(component.badgeClass).toBe('text-light badge badge-archived');
|
||||
});
|
||||
|
||||
it('should init badge content and class', () => {
|
||||
component.status = MyDspaceItemStatusType.WORKFLOW;
|
||||
component.context = Context.MyDSpaceWorkflow;
|
||||
fixture.detectChanges();
|
||||
expect(component.badgeContent).toBe(MyDspaceItemStatusType.WORKFLOW);
|
||||
expect(component.badgeContent).toBe(Context.MyDSpaceWorkflow);
|
||||
expect(component.badgeClass).toBe('text-light badge badge-workflow');
|
||||
});
|
||||
});
|
@@ -1,20 +1,20 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { MyDspaceItemStatusType } from './my-dspace-item-status-type';
|
||||
import { Context } from 'src/app/core/shared/context.model';
|
||||
|
||||
/**
|
||||
* This component represents a badge with mydspace item status
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-mydspace-item-status',
|
||||
styleUrls: ['./my-dspace-item-status.component.scss'],
|
||||
templateUrl: './my-dspace-item-status.component.html'
|
||||
selector: 'ds-my-dspace-status-badge',
|
||||
styleUrls: ['./my-dspace-status-badge.component.scss'],
|
||||
templateUrl: './my-dspace-status-badge.component.html'
|
||||
})
|
||||
export class MyDSpaceItemStatusComponent implements OnInit {
|
||||
export class MyDSpaceStatusBadgeComponent implements OnInit {
|
||||
|
||||
/**
|
||||
* This mydspace item status
|
||||
* This mydspace item context
|
||||
*/
|
||||
@Input() status: MyDspaceItemStatusType;
|
||||
@Input() context: Context;
|
||||
|
||||
/**
|
||||
* This badge class
|
||||
@@ -30,22 +30,22 @@ export class MyDSpaceItemStatusComponent implements OnInit {
|
||||
* Initialize badge content and class
|
||||
*/
|
||||
ngOnInit() {
|
||||
this.badgeContent = this.status;
|
||||
this.badgeContent = this.context;
|
||||
this.badgeClass = 'text-light badge ';
|
||||
switch (this.status) {
|
||||
case MyDspaceItemStatusType.VALIDATION:
|
||||
switch (this.context) {
|
||||
case Context.MyDSpaceValidation:
|
||||
this.badgeClass += 'badge-validation';
|
||||
break;
|
||||
case MyDspaceItemStatusType.WAITING_CONTROLLER:
|
||||
case Context.MyDSpaceWaitingController:
|
||||
this.badgeClass += 'badge-waiting-controller';
|
||||
break;
|
||||
case MyDspaceItemStatusType.WORKSPACE:
|
||||
case Context.MyDSpaceWorkspace:
|
||||
this.badgeClass += 'badge-workspace';
|
||||
break;
|
||||
case MyDspaceItemStatusType.ARCHIVED:
|
||||
case Context.MyDSpaceArchived:
|
||||
this.badgeClass += 'badge-archived';
|
||||
break;
|
||||
case MyDspaceItemStatusType.WORKFLOW:
|
||||
case Context.MyDSpaceWorkflow:
|
||||
this.badgeClass += 'badge-workflow';
|
||||
break;
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { Context } from 'src/app/core/shared/context.model';
|
||||
import { ThemedComponent } from '../../../../theme-support/themed.component';
|
||||
import { MyDSpaceStatusBadgeComponent } from './my-dspace-status-badge.component';
|
||||
|
||||
/**
|
||||
* Themed wrapper for MyDSpaceStatusBadge
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-themed-my-dspace-status-badge',
|
||||
styleUrls: [],
|
||||
templateUrl: '../../../../theme-support/themed.component.html',
|
||||
})
|
||||
export class ThemedMyDSpaceStatusBadgeComponent extends ThemedComponent<MyDSpaceStatusBadgeComponent> {
|
||||
@Input() context: Context;
|
||||
|
||||
protected inAndOutputNames: (keyof MyDSpaceStatusBadgeComponent & keyof this)[] = ['context'];
|
||||
|
||||
protected getComponentName(): string {
|
||||
return 'MyDSpaceStatusBadgeComponent';
|
||||
}
|
||||
|
||||
protected importThemedComponent(themeName: string): Promise<any> {
|
||||
return import(`../../../../../../themes/${themeName}/app/shared/object-collection/shared/badges/my-dspace-status-badge/my-dspace-status-badge.component`);
|
||||
}
|
||||
|
||||
protected importUnthemedComponent(): Promise<any> {
|
||||
return import(`./my-dspace-status-badge.component`);
|
||||
}
|
||||
}
|
@@ -0,0 +1,6 @@
|
||||
<div *ngIf="privateBadge" class="private-badge">
|
||||
<span class="badge badge-danger">{{ "item.badge.private" | translate }}</span>
|
||||
</div>
|
||||
<div *ngIf="withdrawnBadge" class="withdrawn-badge">
|
||||
<span class="badge badge-warning">{{ "item.badge.withdrawn" | translate }}</span>
|
||||
</div>
|
@@ -0,0 +1,91 @@
|
||||
import { Item } from '../../../../../core/shared/item.model';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { TruncatePipe } from '../../../../utils/truncate.pipe';
|
||||
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { StatusBadgeComponent } from './status-badge.component';
|
||||
|
||||
let comp: StatusBadgeComponent;
|
||||
let fixture: ComponentFixture<StatusBadgeComponent>;
|
||||
|
||||
let withdrawnItem = Object.assign(new Item(), { isWithdrawn: true });
|
||||
let notWithdrawnItem = Object.assign(new Item(), { isWithdrawn: false });
|
||||
let privateItem = Object.assign(new Item(), { isDiscoverable: false });
|
||||
let notPrivateItem = Object.assign(new Item(), { isDiscoverable: true });
|
||||
|
||||
describe('ItemStatusBadgeComponent', () => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [TranslateModule.forRoot()],
|
||||
declarations: [StatusBadgeComponent, TruncatePipe],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
}).overrideComponent(StatusBadgeComponent, {
|
||||
set: { changeDetection: ChangeDetectionStrategy.Default }
|
||||
}).compileComponents();
|
||||
init();
|
||||
}));
|
||||
|
||||
function init() {
|
||||
withdrawnItem = Object.assign(new Item(), { isWithdrawn: true });
|
||||
notWithdrawnItem = Object.assign(new Item(), { isWithdrawn: false });
|
||||
privateItem = Object.assign(new Item(), { isDiscoverable: false });
|
||||
notPrivateItem = Object.assign(new Item(), { isDiscoverable: true });
|
||||
}
|
||||
beforeEach(waitForAsync(() => {
|
||||
fixture = TestBed.createComponent(StatusBadgeComponent);
|
||||
comp = fixture.componentInstance;
|
||||
}));
|
||||
|
||||
|
||||
describe('when the item is not withdrawn', () => {
|
||||
beforeEach(() => {
|
||||
comp.object = notWithdrawnItem;
|
||||
comp.ngOnInit();
|
||||
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(() => {
|
||||
comp.object = withdrawnItem;
|
||||
comp.ngOnInit();
|
||||
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(() => {
|
||||
comp.object = notPrivateItem;
|
||||
comp.ngOnInit();
|
||||
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(() => {
|
||||
comp.object = privateItem;
|
||||
comp.ngOnInit();
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should show the private badge', () => {
|
||||
const badge = fixture.debugElement.query(By.css('div.private-badge'));
|
||||
expect(badge).not.toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
@@ -0,0 +1,41 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { DSpaceObject } from '../../../../../core/shared/dspace-object.model';
|
||||
import { hasValue } from '../../../../empty.util';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-status-badge',
|
||||
templateUrl: './status-badge.component.html'
|
||||
})
|
||||
/**
|
||||
* Component rendering the status of an item as a badge
|
||||
*/
|
||||
export class StatusBadgeComponent implements OnInit {
|
||||
|
||||
/**
|
||||
* The component used to retrieve the status from
|
||||
*/
|
||||
@Input() object: DSpaceObject;
|
||||
|
||||
/**
|
||||
* Whether or not the "Private" badge should be displayed for this listable object
|
||||
*/
|
||||
privateBadge = false;
|
||||
|
||||
/**
|
||||
* Whether or not the "Withdrawn" badge should be displayed for this listable object
|
||||
*/
|
||||
withdrawnBadge = false;
|
||||
|
||||
/**
|
||||
* Initialize which badges should be visible
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
let objectAsAny = this.object as any;
|
||||
if (hasValue(objectAsAny.indexableObject)) {
|
||||
objectAsAny = objectAsAny.indexableObject;
|
||||
}
|
||||
const objectExists = hasValue(objectAsAny);
|
||||
this.privateBadge = objectExists && hasValue(objectAsAny.isDiscoverable) && !objectAsAny.isDiscoverable;
|
||||
this.withdrawnBadge = objectExists && hasValue(objectAsAny.isWithdrawn) && objectAsAny.isWithdrawn;
|
||||
}
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { ThemedComponent } from '../../../../theme-support/themed.component';
|
||||
import { StatusBadgeComponent } from './status-badge.component';
|
||||
import { DSpaceObject } from '../../../../../core/shared/dspace-object.model';
|
||||
|
||||
/**
|
||||
* Themed wrapper for StatusBadgeComponent
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-themed-status-badge',
|
||||
styleUrls: [],
|
||||
templateUrl: '../../../../theme-support/themed.component.html',
|
||||
})
|
||||
export class ThemedStatusBadgeComponent extends ThemedComponent<StatusBadgeComponent> {
|
||||
@Input() object: DSpaceObject;
|
||||
|
||||
protected inAndOutputNames: (keyof StatusBadgeComponent & keyof this)[] = ['object'];
|
||||
|
||||
protected getComponentName(): string {
|
||||
return 'StatusBadgeComponent';
|
||||
}
|
||||
|
||||
protected importThemedComponent(themeName: string): Promise<any> {
|
||||
return import(`../../../../../../themes/${themeName}/app/shared/object-collection/shared/badges/status-badge/status-badge.component`);
|
||||
}
|
||||
|
||||
protected importUnthemedComponent(): Promise<any> {
|
||||
return import(`./status-badge.component`);
|
||||
}
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { BadgesComponent } from './badges.component';
|
||||
import { ThemedComponent } from '../../../theme-support/themed.component';
|
||||
import { DSpaceObject } from '../../../../core/shared/dspace-object.model';
|
||||
import { Context } from 'src/app/core/shared/context.model';
|
||||
|
||||
/**
|
||||
* Themed wrapper for BadgesComponent
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-themed-badges',
|
||||
styleUrls: [],
|
||||
templateUrl: '../../../theme-support/themed.component.html',
|
||||
})
|
||||
export class ThemedBadgesComponent extends ThemedComponent<BadgesComponent> {
|
||||
@Input() object: DSpaceObject;
|
||||
@Input() context: Context;
|
||||
@Input() showAccessStatus = false;
|
||||
|
||||
protected inAndOutputNames: (keyof BadgesComponent & keyof this)[] = ['object', 'context', 'showAccessStatus'];
|
||||
|
||||
protected getComponentName(): string {
|
||||
return 'BadgesComponent';
|
||||
}
|
||||
|
||||
protected importThemedComponent(themeName: string): Promise<any> {
|
||||
return import(`../../../../../themes/${themeName}/app/shared/object-collection/shared/badges/badges.component`);
|
||||
}
|
||||
|
||||
protected importUnthemedComponent(): Promise<any> {
|
||||
return import(`./badges.component`);
|
||||
}
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { ThemedComponent } from '../../../../theme-support/themed.component';
|
||||
import { TypeBadgeComponent } from './type-badge.component';
|
||||
import { DSpaceObject } from '../../../../../core/shared/dspace-object.model';
|
||||
|
||||
/**
|
||||
* Themed wrapper for TypeBadgeComponent
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ds-themed-type-badge',
|
||||
styleUrls: [],
|
||||
templateUrl: '../../../../theme-support/themed.component.html',
|
||||
})
|
||||
export class ThemedTypeBadgeComponent extends ThemedComponent<TypeBadgeComponent> {
|
||||
@Input() object: DSpaceObject;
|
||||
|
||||
protected inAndOutputNames: (keyof TypeBadgeComponent & keyof this)[] = ['object'];
|
||||
|
||||
protected getComponentName(): string {
|
||||
return 'TypeBadgeComponent';
|
||||
}
|
||||
|
||||
protected importThemedComponent(themeName: string): Promise<any> {
|
||||
return import(`../../../../../../themes/${themeName}/app/shared/object-collection/shared/badges/type-badge/type-badge.component`);
|
||||
}
|
||||
|
||||
protected importUnthemedComponent(): Promise<any> {
|
||||
return import(`./type-badge.component`);
|
||||
}
|
||||
}
|
@@ -1,3 +1,3 @@
|
||||
<div *ngIf="typeMessage">
|
||||
<span *ngIf="typeMessage">
|
||||
<span class="badge badge-info">{{ typeMessage | translate }}</span>
|
||||
</div>
|
||||
</span>
|
@@ -1,8 +1,8 @@
|
||||
import { Item } from '../../../core/shared/item.model';
|
||||
import { Item } from '../../../../../core/shared/item.model';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { TruncatePipe } from '../../utils/truncate.pipe';
|
||||
import { TruncatePipe } from '../../../../utils/truncate.pipe';
|
||||
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { TypeBadgeComponent } from './type-badge.component';
|
@@ -1,7 +1,7 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
|
||||
import { hasValue, isEmpty } from '../../empty.util';
|
||||
import { getResourceTypeValueFor } from '../../../core/cache/object-cache.reducer';
|
||||
import { DSpaceObject } from '../../../../../core/shared/dspace-object.model';
|
||||
import { hasValue, isEmpty } from '../../../../empty.util';
|
||||
import { getResourceTypeValueFor } from '../../../../../core/cache/object-cache.reducer';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-type-badge',
|
@@ -1,9 +1 @@
|
||||
<div [ngClass]="{'d-none' : hideBadges}" #badges>
|
||||
<div *ngIf="privateBadge" class="private-badge">
|
||||
<span class="badge badge-danger">{{ "item.badge.private" | translate }}</span>
|
||||
</div>
|
||||
<div *ngIf="withdrawnBadge" class="withdrawn-badge">
|
||||
<span class="badge badge-warning">{{ "item.badge.withdrawn" | translate }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<ng-template dsListableObject></ng-template>
|
||||
|
@@ -11,7 +11,6 @@ import {
|
||||
import { ListableObjectDirective } from './listable-object.directive';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { Item } from '../../../../core/shared/item.model';
|
||||
import { provideMockStore } from '@ngrx/store/testing';
|
||||
import { ThemeService } from '../../../theme-support/theme.service';
|
||||
|
||||
@@ -74,64 +73,6 @@ describe('ListableObjectComponentLoaderComponent', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the object is an item and viewMode is a list', () => {
|
||||
beforeEach(() => {
|
||||
comp.object = Object.assign(new Item());
|
||||
comp.viewMode = ViewMode.ListElement;
|
||||
});
|
||||
|
||||
describe('when the item is not withdrawn', () => {
|
||||
beforeEach(() => {
|
||||
(comp.object as any).isWithdrawn = false;
|
||||
comp.initBadges();
|
||||
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(() => {
|
||||
(comp.object as any).isWithdrawn = true;
|
||||
comp.initBadges();
|
||||
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(() => {
|
||||
(comp.object as any).isDiscoverable = true;
|
||||
comp.initBadges();
|
||||
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(() => {
|
||||
(comp.object as any).isDiscoverable = false;
|
||||
comp.initBadges();
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should show the private badge', () => {
|
||||
const badge = fixture.debugElement.query(By.css('div.private-badge'));
|
||||
expect(badge).not.toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('When a reloadedObject is emitted', () => {
|
||||
let listableComponent;
|
||||
let reloadedObject: any;
|
||||
|
@@ -2,7 +2,6 @@ import {
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
ComponentRef,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnChanges,
|
||||
@@ -76,37 +75,16 @@ export class ListableObjectComponentLoaderComponent implements OnInit, OnChanges
|
||||
*/
|
||||
@Input() value: string;
|
||||
|
||||
/**
|
||||
* Whether or not informational badges (e.g. Private, Withdrawn) should be hidden
|
||||
*/
|
||||
@Input() hideBadges = false;
|
||||
|
||||
/**
|
||||
* Directive hook used to place the dynamic child component
|
||||
*/
|
||||
@ViewChild(ListableObjectDirective, { static: true }) listableObjectDirective: ListableObjectDirective;
|
||||
|
||||
/**
|
||||
* View on the badges template, to be passed on to the loaded component (which will place the badges in the desired
|
||||
* location, or on top if not specified)
|
||||
*/
|
||||
@ViewChild('badges', { static: true }) badges: ElementRef;
|
||||
|
||||
/**
|
||||
* Emit when the listable object has been reloaded.
|
||||
*/
|
||||
@Output() contentChange = new EventEmitter<ListableObject>();
|
||||
|
||||
/**
|
||||
* Whether or not the "Private" badge should be displayed for this listable object
|
||||
*/
|
||||
privateBadge = false;
|
||||
|
||||
/**
|
||||
* Whether or not the "Withdrawn" badge should be displayed for this listable object
|
||||
*/
|
||||
withdrawnBadge = false;
|
||||
|
||||
/**
|
||||
* Array to track all subscriptions and unsubscribe them onDestroy
|
||||
* @type {Array}
|
||||
@@ -161,8 +139,6 @@ export class ListableObjectComponentLoaderComponent implements OnInit, OnChanges
|
||||
|
||||
private instantiateComponent(object) {
|
||||
|
||||
this.initBadges();
|
||||
|
||||
const component = this.getComponent(object.getRenderTypes(), this.viewMode, this.context);
|
||||
|
||||
const viewContainerRef = this.listableObjectDirective.viewContainerRef;
|
||||
@@ -171,10 +147,7 @@ export class ListableObjectComponentLoaderComponent implements OnInit, OnChanges
|
||||
this.compRef = viewContainerRef.createComponent(
|
||||
component, {
|
||||
index: 0,
|
||||
injector: undefined,
|
||||
projectableNodes: [
|
||||
[this.badges.nativeElement],
|
||||
]
|
||||
injector: undefined
|
||||
}
|
||||
);
|
||||
|
||||
@@ -195,19 +168,6 @@ export class ListableObjectComponentLoaderComponent implements OnInit, OnChanges
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize which badges should be visible in the listable component
|
||||
*/
|
||||
initBadges() {
|
||||
let objectAsAny = this.object as any;
|
||||
if (hasValue(objectAsAny.indexableObject)) {
|
||||
objectAsAny = objectAsAny.indexableObject;
|
||||
}
|
||||
const objectExistsAndValidViewMode = hasValue(objectAsAny) && this.viewMode !== ViewMode.StandalonePage;
|
||||
this.privateBadge = objectExistsAndValidViewMode && hasValue(objectAsAny.isDiscoverable) && !objectAsAny.isDiscoverable;
|
||||
this.withdrawnBadge = objectExistsAndValidViewMode && hasValue(objectAsAny.isWithdrawn) && objectAsAny.isWithdrawn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the component depending on the item's entity type, view mode and context
|
||||
* @returns {GenericConstructor<Component>}
|
||||
|
@@ -2,7 +2,7 @@
|
||||
<ds-item-detail-preview [item]="item$?.value"
|
||||
[object]="object"
|
||||
[showSubmitter]="showSubmitter"
|
||||
[status]="status">
|
||||
[badgeContext]="badgeContext">
|
||||
</ds-item-detail-preview>
|
||||
|
||||
<ds-claimed-task-actions [item]="item$.value"
|
||||
|
@@ -1,5 +1,12 @@
|
||||
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { ComponentFixture, fakeAsync, flush, TestBed, tick, waitForAsync } from '@angular/core/testing';
|
||||
import {
|
||||
ComponentFixture,
|
||||
fakeAsync,
|
||||
flush,
|
||||
TestBed,
|
||||
tick,
|
||||
waitForAsync
|
||||
} from '@angular/core/testing';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
||||
import { of as observableOf } from 'rxjs';
|
||||
@@ -7,9 +14,6 @@ import { of as observableOf } from 'rxjs';
|
||||
import { Item } from '../../../../core/shared/item.model';
|
||||
import { ClaimedTaskSearchResultDetailElementComponent } from './claimed-task-search-result-detail-element.component';
|
||||
import { ClaimedTask } from '../../../../core/tasks/models/claimed-task-object.model';
|
||||
import {
|
||||
MyDspaceItemStatusType
|
||||
} from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type';
|
||||
import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model';
|
||||
import { createSuccessfulRemoteDataObject } from '../../../remote-data.utils';
|
||||
import { ClaimedTaskSearchResult } from '../../../object-collection/shared/claimed-task-search-result.model';
|
||||
@@ -18,6 +22,7 @@ import { LinkService } from '../../../../core/cache/builders/link.service';
|
||||
import { getMockLinkService } from '../../../mocks/link-service.mock';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { ObjectCacheService } from '../../../../core/cache/object-cache.service';
|
||||
import { Context } from '../../../../core/shared/context.model';
|
||||
|
||||
let component: ClaimedTaskSearchResultDetailElementComponent;
|
||||
let fixture: ComponentFixture<ClaimedTaskSearchResultDetailElementComponent>;
|
||||
@@ -101,8 +106,8 @@ describe('ClaimedTaskSearchResultDetailElementComponent', () => {
|
||||
expect(component.item$.value).toEqual(item);
|
||||
}));
|
||||
|
||||
it('should have properly status', () => {
|
||||
expect(component.status).toEqual(MyDspaceItemStatusType.VALIDATION);
|
||||
it('should have the correct badge context', () => {
|
||||
expect(component.badgeContext).toEqual(Context.MyDSpaceValidation);
|
||||
});
|
||||
|
||||
it('should forward claimed-task-actions processComplete event to reloadObject event emitter', fakeAsync(() => {
|
||||
|
@@ -8,9 +8,6 @@ import { ViewMode } from '../../../../core/shared/view-mode.model';
|
||||
import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model';
|
||||
import { ClaimedTask } from '../../../../core/tasks/models/claimed-task-object.model';
|
||||
import { SearchResultDetailElementComponent } from '../search-result-detail-element.component';
|
||||
import {
|
||||
MyDspaceItemStatusType
|
||||
} from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type';
|
||||
import { listableObjectComponent } from '../../../object-collection/shared/listable-object/listable-object.decorator';
|
||||
import { ClaimedTaskSearchResult } from '../../../object-collection/shared/claimed-task-search-result.model';
|
||||
import { followLink } from '../../../utils/follow-link-config.model';
|
||||
@@ -19,6 +16,7 @@ import { Item } from '../../../../core/shared/item.model';
|
||||
import { getFirstCompletedRemoteData } from '../../../../core/shared/operators';
|
||||
import { isNotEmpty } from '../../../empty.util';
|
||||
import { ObjectCacheService } from '../../../../core/cache/object-cache.service';
|
||||
import { Context } from 'src/app/core/shared/context.model';
|
||||
|
||||
/**
|
||||
* This component renders claimed task object for the search result in the detail view.
|
||||
@@ -43,9 +41,9 @@ export class ClaimedTaskSearchResultDetailElementComponent extends SearchResultD
|
||||
public showSubmitter = true;
|
||||
|
||||
/**
|
||||
* Represent item's status
|
||||
* Represents the badge context
|
||||
*/
|
||||
public status = MyDspaceItemStatusType.VALIDATION;
|
||||
public badgeContext = Context.MyDSpaceValidation;
|
||||
|
||||
/**
|
||||
* The workflowitem object that belonging to the result object
|
||||
|
@@ -1,7 +1,5 @@
|
||||
<div *ngIf="item" class="item-page" @fadeInOut>
|
||||
<ng-container *ngIf="status">
|
||||
<ds-mydspace-item-status [status]="status"></ds-mydspace-item-status>
|
||||
</ng-container>
|
||||
<ds-themed-badges [object]="item" [context]="badgeContext"></ds-themed-badges>
|
||||
<div *ngIf="item">
|
||||
<ds-themed-item-page-title-field [item]="item">
|
||||
</ds-themed-item-page-title-field>
|
||||
|
@@ -6,12 +6,12 @@ import { BitstreamDataService } from '../../../../core/data/bitstream-data.servi
|
||||
|
||||
import { Item } from '../../../../core/shared/item.model';
|
||||
import { getFirstSucceededRemoteListPayload } from '../../../../core/shared/operators';
|
||||
import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type';
|
||||
import { fadeInOut } from '../../../animations/fade';
|
||||
import { Bitstream } from '../../../../core/shared/bitstream.model';
|
||||
import { FileService } from '../../../../core/shared/file.service';
|
||||
import { HALEndpointService } from '../../../../core/shared/hal-endpoint.service';
|
||||
import { SearchResult } from '../../../search/models/search-result.model';
|
||||
import { Context } from '../../../../core/shared/context.model';
|
||||
|
||||
/**
|
||||
* This component show metadata for the given item object in the detail view.
|
||||
@@ -23,7 +23,6 @@ import { SearchResult } from '../../../search/models/search-result.model';
|
||||
animations: [fadeInOut]
|
||||
})
|
||||
export class ItemDetailPreviewComponent {
|
||||
|
||||
/**
|
||||
* The item to display
|
||||
*/
|
||||
@@ -35,9 +34,9 @@ export class ItemDetailPreviewComponent {
|
||||
@Input() object: SearchResult<any>;
|
||||
|
||||
/**
|
||||
* Represent item's status
|
||||
* Represents the badge context
|
||||
*/
|
||||
@Input() status: MyDspaceItemStatusType;
|
||||
@Input() badgeContext: Context;
|
||||
|
||||
/**
|
||||
* A boolean representing if to show submitter information
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<ds-item-detail-preview [item]="dso"
|
||||
[object]="object"
|
||||
[status]="status">
|
||||
[badgeContext]="badgeContext">
|
||||
</ds-item-detail-preview>
|
||||
|
||||
<ds-item-actions [object]="dso"></ds-item-actions>
|
||||
|
@@ -6,8 +6,8 @@ import { of as observableOf } from 'rxjs';
|
||||
|
||||
import { Item } from '../../../../core/shared/item.model';
|
||||
import { ItemSearchResultDetailElementComponent } from './item-search-result-detail-element.component';
|
||||
import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type';
|
||||
import { ItemSearchResult } from '../../../object-collection/shared/item-search-result.model';
|
||||
import { Context } from 'src/app/core/shared/context.model';
|
||||
|
||||
let component: ItemSearchResultDetailElementComponent;
|
||||
let fixture: ComponentFixture<ItemSearchResultDetailElementComponent>;
|
||||
@@ -68,7 +68,7 @@ describe('ItemSearchResultDetailElementComponent', () => {
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should have properly status', () => {
|
||||
expect(component.status).toEqual(MyDspaceItemStatusType.ARCHIVED);
|
||||
it('should have the correct badge context', () => {
|
||||
expect(component.badgeContext).toEqual(Context.MyDSpaceArchived);
|
||||
});
|
||||
});
|
||||
|
@@ -3,9 +3,6 @@ import { Component } from '@angular/core';
|
||||
import { ViewMode } from '../../../../core/shared/view-mode.model';
|
||||
import { Item } from '../../../../core/shared/item.model';
|
||||
import { SearchResultDetailElementComponent } from '../search-result-detail-element.component';
|
||||
import {
|
||||
MyDspaceItemStatusType
|
||||
} from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type';
|
||||
import { listableObjectComponent } from '../../../object-collection/shared/listable-object/listable-object.decorator';
|
||||
import { ItemSearchResult } from '../../../object-collection/shared/item-search-result.model';
|
||||
import { Context } from '../../../../core/shared/context.model';
|
||||
@@ -24,8 +21,8 @@ import { Context } from '../../../../core/shared/context.model';
|
||||
export class ItemSearchResultDetailElementComponent extends SearchResultDetailElementComponent<ItemSearchResult, Item> {
|
||||
|
||||
/**
|
||||
* Represent item's status
|
||||
* Represents the badge context
|
||||
*/
|
||||
public status = MyDspaceItemStatusType.ARCHIVED;
|
||||
public badgeContext = Context.MyDSpaceArchived;
|
||||
|
||||
}
|
||||
|
@@ -2,7 +2,7 @@
|
||||
<ds-item-detail-preview [item]="item$?.value"
|
||||
[object]="object"
|
||||
[showSubmitter]="showSubmitter"
|
||||
[status]="status"></ds-item-detail-preview>
|
||||
[badgeContext]="badgeContext"></ds-item-detail-preview>
|
||||
|
||||
<ds-pool-task-actions [item]="item$.value"
|
||||
[object]="dso"
|
||||
|
@@ -6,9 +6,6 @@ import { of as observableOf } from 'rxjs';
|
||||
|
||||
import { Item } from '../../../../core/shared/item.model';
|
||||
import { PoolTask } from '../../../../core/tasks/models/pool-task-object.model';
|
||||
import {
|
||||
MyDspaceItemStatusType
|
||||
} from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type';
|
||||
import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model';
|
||||
import { createSuccessfulRemoteDataObject } from '../../../remote-data.utils';
|
||||
import { PoolSearchResultDetailElementComponent } from './pool-search-result-detail-element.component';
|
||||
@@ -18,6 +15,7 @@ import { LinkService } from '../../../../core/cache/builders/link.service';
|
||||
import { getMockLinkService } from '../../../mocks/link-service.mock';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { ObjectCacheService } from '../../../../core/cache/object-cache.service';
|
||||
import { Context } from 'src/app/core/shared/context.model';
|
||||
|
||||
let component: PoolSearchResultDetailElementComponent;
|
||||
let fixture: ComponentFixture<PoolSearchResultDetailElementComponent>;
|
||||
@@ -103,8 +101,8 @@ describe('PoolSearchResultDetailElementComponent', () => {
|
||||
expect(component.item$.value).toEqual(item);
|
||||
}));
|
||||
|
||||
it('should have properly status', () => {
|
||||
expect(component.status).toEqual(MyDspaceItemStatusType.WAITING_CONTROLLER);
|
||||
it('should have the correct badge context', () => {
|
||||
expect(component.badgeContext).toEqual(Context.MyDSpaceWaitingController);
|
||||
});
|
||||
|
||||
it('should forward pool-task-actions processCompleted event to the reloadedObject event emitter', fakeAsync(() => {
|
||||
|
@@ -6,9 +6,6 @@ import { mergeMap, tap } from 'rxjs/operators';
|
||||
import { RemoteData } from '../../../../core/data/remote-data';
|
||||
import { PoolTask } from '../../../../core/tasks/models/pool-task-object.model';
|
||||
import { SearchResultDetailElementComponent } from '../search-result-detail-element.component';
|
||||
import {
|
||||
MyDspaceItemStatusType
|
||||
} from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type';
|
||||
import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model';
|
||||
import { ViewMode } from '../../../../core/shared/view-mode.model';
|
||||
import { listableObjectComponent } from '../../../object-collection/shared/listable-object/listable-object.decorator';
|
||||
@@ -19,6 +16,7 @@ import { Item } from '../../../../core/shared/item.model';
|
||||
import { getFirstCompletedRemoteData } from '../../../../core/shared/operators';
|
||||
import { isNotEmpty } from '../../../empty.util';
|
||||
import { ObjectCacheService } from '../../../../core/cache/object-cache.service';
|
||||
import { Context } from 'src/app/core/shared/context.model';
|
||||
|
||||
/**
|
||||
* This component renders pool task object for the search result in the detail view.
|
||||
@@ -43,9 +41,9 @@ export class PoolSearchResultDetailElementComponent extends SearchResultDetailEl
|
||||
public showSubmitter = true;
|
||||
|
||||
/**
|
||||
* Represent item's status
|
||||
* Represents the badge context
|
||||
*/
|
||||
public status = MyDspaceItemStatusType.WAITING_CONTROLLER;
|
||||
public badgeContext = Context.MyDSpaceWaitingController;
|
||||
|
||||
/**
|
||||
* The workflowitem object that belonging to the result object
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<ds-item-detail-preview [item]="item"
|
||||
[object]="object"
|
||||
[status]="status"></ds-item-detail-preview>
|
||||
[badgeContext]="badgeContext"></ds-item-detail-preview>
|
||||
|
||||
<ds-workflowitem-actions [object]="dso"></ds-workflowitem-actions>
|
||||
|
||||
|
@@ -7,13 +7,13 @@ import { of as observableOf } from 'rxjs';
|
||||
import { Item } from '../../../../core/shared/item.model';
|
||||
import { WorkflowItemSearchResultDetailElementComponent } from './workflow-item-search-result-detail-element.component';
|
||||
import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model';
|
||||
import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type';
|
||||
import { createSuccessfulRemoteDataObject } from '../../../remote-data.utils';
|
||||
import { WorkflowItemSearchResult } from '../../../object-collection/shared/workflow-item-search-result.model';
|
||||
import { getMockLinkService } from '../../../mocks/link-service.mock';
|
||||
import { LinkService } from '../../../../core/cache/builders/link.service';
|
||||
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
|
||||
import { DSONameServiceMock } from '../../../mocks/dso-name.service.mock';
|
||||
import { Context } from '../../../../core/shared/context.model';
|
||||
|
||||
let component: WorkflowItemSearchResultDetailElementComponent;
|
||||
let fixture: ComponentFixture<WorkflowItemSearchResultDetailElementComponent>;
|
||||
@@ -87,7 +87,7 @@ describe('WorkflowItemSearchResultDetailElementComponent', () => {
|
||||
expect(component.item).toEqual(item);
|
||||
});
|
||||
|
||||
it('should have properly status', () => {
|
||||
expect(component.status).toEqual(MyDspaceItemStatusType.WORKFLOW);
|
||||
it('should have the correct badge context', () => {
|
||||
expect(component.badgeContext).toEqual(Context.MyDSpaceWorkflow);
|
||||
});
|
||||
});
|
||||
|
@@ -4,7 +4,6 @@ import { ViewMode } from '../../../../core/shared/view-mode.model';
|
||||
import { Item } from '../../../../core/shared/item.model';
|
||||
import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model';
|
||||
import { SearchResultDetailElementComponent } from '../search-result-detail-element.component';
|
||||
import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type';
|
||||
import { Observable } from 'rxjs';
|
||||
import { RemoteData } from '../../../../core/data/remote-data';
|
||||
import { find } from 'rxjs/operators';
|
||||
@@ -13,6 +12,7 @@ import { listableObjectComponent } from '../../../object-collection/shared/lista
|
||||
import { WorkflowItemSearchResult } from '../../../object-collection/shared/workflow-item-search-result.model';
|
||||
import { LinkService } from '../../../../core/cache/builders/link.service';
|
||||
import { followLink } from '../../../utils/follow-link-config.model';
|
||||
import { Context } from 'src/app/core/shared/context.model';
|
||||
|
||||
/**
|
||||
* This component renders workflowitem object for the search result in the detail view.
|
||||
@@ -32,9 +32,9 @@ export class WorkflowItemSearchResultDetailElementComponent extends SearchResult
|
||||
public item: Item;
|
||||
|
||||
/**
|
||||
* Represent item's status
|
||||
* Represents the badge context
|
||||
*/
|
||||
public status = MyDspaceItemStatusType.WORKFLOW;
|
||||
public badgeContext = Context.MyDSpaceWorkflow;
|
||||
|
||||
constructor(
|
||||
protected linkService: LinkService
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<ds-item-detail-preview [item]="item"
|
||||
[object]="object"
|
||||
[status]="status"></ds-item-detail-preview>
|
||||
[badgeContext]="badgeContext"></ds-item-detail-preview>
|
||||
|
||||
<ds-workspaceitem-actions [object]="dso"></ds-workspaceitem-actions>
|
||||
|
@@ -7,13 +7,13 @@ import { of as observableOf } from 'rxjs';
|
||||
import { Item } from '../../../../core/shared/item.model';
|
||||
import { WorkspaceItemSearchResultDetailElementComponent } from './workspace-item-search-result-detail-element.component';
|
||||
import { WorkspaceItem } from '../../../../core/submission/models/workspaceitem.model';
|
||||
import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type';
|
||||
import { createSuccessfulRemoteDataObject } from '../../../remote-data.utils';
|
||||
import { WorkflowItemSearchResult } from '../../../object-collection/shared/workflow-item-search-result.model';
|
||||
import { getMockLinkService } from '../../../mocks/link-service.mock';
|
||||
import { LinkService } from '../../../../core/cache/builders/link.service';
|
||||
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
|
||||
import { DSONameServiceMock } from '../../../mocks/dso-name.service.mock';
|
||||
import { Context } from 'src/app/core/shared/context.model';
|
||||
|
||||
let component: WorkspaceItemSearchResultDetailElementComponent;
|
||||
let fixture: ComponentFixture<WorkspaceItemSearchResultDetailElementComponent>;
|
||||
@@ -87,7 +87,7 @@ describe('WorkspaceItemSearchResultDetailElementComponent', () => {
|
||||
expect(component.item).toEqual(item);
|
||||
});
|
||||
|
||||
it('should have properly status', () => {
|
||||
expect(component.status).toEqual(MyDspaceItemStatusType.WORKSPACE);
|
||||
it('should have the correct badge context', () => {
|
||||
expect(component.badgeContext).toEqual(Context.MyDSpaceWorkspace);
|
||||
});
|
||||
});
|
||||
|
@@ -8,12 +8,12 @@ import { Item } from '../../../../core/shared/item.model';
|
||||
import { RemoteData } from '../../../../core/data/remote-data';
|
||||
import { isNotUndefined } from '../../../empty.util';
|
||||
import { SearchResultDetailElementComponent } from '../search-result-detail-element.component';
|
||||
import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type';
|
||||
import { ViewMode } from '../../../../core/shared/view-mode.model';
|
||||
import { listableObjectComponent } from '../../../object-collection/shared/listable-object/listable-object.decorator';
|
||||
import { WorkspaceItemSearchResult } from '../../../object-collection/shared/workspace-item-search-result.model';
|
||||
import { followLink } from '../../../utils/follow-link-config.model';
|
||||
import { LinkService } from '../../../../core/cache/builders/link.service';
|
||||
import { Context } from '../../../../core/shared/context.model';
|
||||
|
||||
/**
|
||||
* This component renders workspace item object for the search result in the detail view.
|
||||
@@ -33,9 +33,9 @@ export class WorkspaceItemSearchResultDetailElementComponent extends SearchResul
|
||||
public item: Item;
|
||||
|
||||
/**
|
||||
* Represent item's status
|
||||
* Represents the badge context
|
||||
*/
|
||||
status = MyDspaceItemStatusType.WORKSPACE;
|
||||
public badgeContext = Context.MyDSpaceWorkspace;
|
||||
|
||||
constructor(
|
||||
protected linkService: LinkService
|
||||
|
@@ -8,7 +8,7 @@
|
||||
</ds-thumbnail>
|
||||
</span>
|
||||
<div class="card-body">
|
||||
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge>
|
||||
<ds-themed-badges *ngIf="showLabel" [object]="dso" [context]="context"></ds-themed-badges>
|
||||
<h4 class="card-title">{{dso.name}}</h4>
|
||||
<p *ngIf="dso.shortDescription" class="card-text">{{dso.shortDescription}}</p>
|
||||
<div *ngIf="linkType != linkTypes.None" class="text-center">
|
||||
|
@@ -8,7 +8,7 @@
|
||||
</ds-thumbnail>
|
||||
</span>
|
||||
<div class="card-body">
|
||||
<ds-type-badge *ngIf="showLabel" [object]="dso"></ds-type-badge>
|
||||
<ds-themed-badges *ngIf="showLabel" [object]="dso" [context]="context"></ds-themed-badges>
|
||||
<h4 class="card-title">{{dso.name}}</h4>
|
||||
<p *ngIf="dso.shortDescription" class="card-text">{{dso.shortDescription}}</p>
|
||||
<div *ngIf="linkType != linkTypes.None" class="text-center">
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user