diff --git a/config/config.example.yml b/config/config.example.yml
index 771c7b1653..898b47784f 100644
--- a/config/config.example.yml
+++ b/config/config.example.yml
@@ -148,6 +148,9 @@ languages:
- code: fi
label: Suomi
active: true
+ - code: tr
+ label: Türkçe
+ active: true
- code: bn
label: বাংলা
active: true
@@ -161,10 +164,12 @@ browseBy:
# The absolute lowest year to display in the dropdown (only used when no lowest date can be found for all items)
defaultLowerLimit: 1900
-# Item Page Config
+# Item Config
item:
edit:
undoTimeout: 10000 # 10 seconds
+ # Show the item access status label in items lists
+ showAccessStatuses: false
# Collection Page Config
collection:
@@ -231,6 +236,10 @@ themes:
rel: manifest
href: assets/dspace/images/favicons/manifest.webmanifest
+# The default bundles that should always be displayed as suggestions when you upload a new bundle
+bundle:
+ - standardBundles: [ ORIGINAL, THUMBNAIL, LICENSE ]
+
# Whether to enable media viewer for image and/or video Bitstreams (i.e. Bitstreams whose MIME type starts with 'image' or 'video').
# For images, this enables a gallery viewer where you can zoom or page through images.
# For videos, this enables embedded video streaming
diff --git a/package.json b/package.json
index 236e4a7be5..dd63ca0a00 100644
--- a/package.json
+++ b/package.json
@@ -68,8 +68,8 @@
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"@ng-bootstrap/ng-bootstrap": "^11.0.0",
- "@ng-dynamic-forms/core": "^14.0.1",
- "@ng-dynamic-forms/ui-ng-bootstrap": "^14.0.1",
+ "@ng-dynamic-forms/core": "^15.0.0",
+ "@ng-dynamic-forms/ui-ng-bootstrap": "^15.0.0",
"@ngrx/effects": "^13.0.2",
"@ngrx/router-store": "^13.0.2",
"@ngrx/store": "^13.0.2",
@@ -77,7 +77,7 @@
"@ngx-translate/core": "^13.0.0",
"@nicky-lenaers/ngx-scroll-to": "^9.0.0",
"angular-idle-preload": "3.0.0",
- "angulartics2": "^10.0.0",
+ "angulartics2": "^12.0.0",
"bootstrap": "4.3.1",
"caniuse-lite": "^1.0.30001165",
"cerialize": "0.1.18",
@@ -119,7 +119,7 @@
"prop-types": "^15.7.2",
"react-copy-to-clipboard": "^5.0.1",
"reflect-metadata": "^0.1.13",
- "rxjs": "^6.6.3",
+ "rxjs": "^7.5.5",
"sortablejs": "1.13.0",
"tslib": "^2.0.0",
"url-parse": "^1.5.6",
@@ -162,7 +162,7 @@
"css-minimizer-webpack-plugin": "^3.4.1",
"cssnano": "^5.0.6",
"cypress": "9.5.1",
- "cypress-axe": "^0.13.0",
+ "cypress-axe": "^0.14.0",
"debug-loader": "^0.0.1",
"deep-freeze": "0.0.1",
"dotenv": "^8.2.0",
@@ -174,7 +174,7 @@
"fork-ts-checker-webpack-plugin": "^6.0.3",
"html-loader": "^1.3.2",
"jasmine-core": "^3.8.0",
- "jasmine-marbles": "0.6.0",
+ "jasmine-marbles": "0.9.2",
"jasmine-spec-reporter": "~5.0.0",
"karma": "^6.3.14",
"karma-chrome-launcher": "~3.1.0",
@@ -182,7 +182,7 @@
"karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "^1.5.0",
"karma-mocha-reporter": "2.2.5",
- "ngx-mask": "^12.0.0",
+ "ngx-mask": "^13.1.7",
"nodemon": "^2.0.15",
"postcss": "^8.1",
"postcss-apply": "0.12.0",
@@ -196,7 +196,7 @@
"react": "^16.14.0",
"react-dom": "^16.14.0",
"rimraf": "^3.0.2",
- "rxjs-spy": "^7.5.3",
+ "rxjs-spy": "^8.0.2",
"sass": "~1.32.6",
"sass-loader": "^12.6.0",
"sass-resources-loader": "^2.1.1",
@@ -210,4 +210,4 @@
"webpack-cli": "^4.2.0",
"webpack-dev-server": "^4.5.0"
}
-}
+}
\ No newline at end of file
diff --git a/src/app/admin/admin-import-metadata-page/metadata-import-page.component.html b/src/app/admin/admin-import-metadata-page/metadata-import-page.component.html
index 42a04b0de6..24901cc11d 100644
--- a/src/app/admin/admin-import-metadata-page/metadata-import-page.component.html
+++ b/src/app/admin/admin-import-metadata-page/metadata-import-page.component.html
@@ -1,6 +1,17 @@
{{'admin.metadata-import.page.help' | translate}}
+
-
-
+
+
+
+
diff --git a/src/app/admin/admin-import-metadata-page/metadata-import-page.component.spec.ts b/src/app/admin/admin-import-metadata-page/metadata-import-page.component.spec.ts
index d663481b8c..814757ec71 100644
--- a/src/app/admin/admin-import-metadata-page/metadata-import-page.component.spec.ts
+++ b/src/app/admin/admin-import-metadata-page/metadata-import-page.component.spec.ts
@@ -87,8 +87,9 @@ describe('MetadataImportPageComponent', () => {
comp.setFile(fileMock);
});
- describe('if proceed button is pressed', () => {
+ describe('if proceed button is pressed without validate only', () => {
beforeEach(fakeAsync(() => {
+ comp.validateOnly = false;
const proceed = fixture.debugElement.query(By.css('#proceedButton')).nativeElement;
proceed.click();
fixture.detectChanges();
@@ -107,6 +108,28 @@ describe('MetadataImportPageComponent', () => {
});
});
+ describe('if proceed button is pressed with validate only', () => {
+ beforeEach(fakeAsync(() => {
+ comp.validateOnly = true;
+ const proceed = fixture.debugElement.query(By.css('#proceedButton')).nativeElement;
+ proceed.click();
+ fixture.detectChanges();
+ }));
+ it('metadata-import script is invoked with -f fileName and the mockFile and -v validate-only', () => {
+ const parameterValues: ProcessParameter[] = [
+ Object.assign(new ProcessParameter(), { name: '-f', value: 'filename.txt' }),
+ Object.assign(new ProcessParameter(), { name: '-v', value: true }),
+ ];
+ expect(scriptService.invoke).toHaveBeenCalledWith(METADATA_IMPORT_SCRIPT_NAME, parameterValues, [fileMock]);
+ });
+ it('success notification is shown', () => {
+ expect(notificationService.success).toHaveBeenCalled();
+ });
+ it('redirected to process page', () => {
+ expect(router.navigateByUrl).toHaveBeenCalledWith('/processes/45');
+ });
+ });
+
describe('if proceed is pressed; but script invoke fails', () => {
beforeEach(fakeAsync(() => {
jasmine.getEnv().allowRespy(true);
diff --git a/src/app/admin/admin-import-metadata-page/metadata-import-page.component.ts b/src/app/admin/admin-import-metadata-page/metadata-import-page.component.ts
index 3bdcca3084..deb16c0d73 100644
--- a/src/app/admin/admin-import-metadata-page/metadata-import-page.component.ts
+++ b/src/app/admin/admin-import-metadata-page/metadata-import-page.component.ts
@@ -30,6 +30,11 @@ export class MetadataImportPageComponent {
*/
fileObject: File;
+ /**
+ * The validate only flag
+ */
+ validateOnly = true;
+
public constructor(private location: Location,
protected translate: TranslateService,
protected notificationsService: NotificationsService,
@@ -62,6 +67,9 @@ export class MetadataImportPageComponent {
const parameterValues: ProcessParameter[] = [
Object.assign(new ProcessParameter(), { name: '-f', value: this.fileObject.name }),
];
+ if (this.validateOnly) {
+ parameterValues.push(Object.assign(new ProcessParameter(), { name: '-v', value: true }));
+ }
this.scriptDataService.invoke(METADATA_IMPORT_SCRIPT_NAME, parameterValues, [this.fileObject]).pipe(
getFirstCompletedRemoteData(),
diff --git a/src/app/admin/admin-search-page/admin-search-results/admin-search-result-grid-element/item-search-result/item-admin-search-result-grid-element.component.spec.ts b/src/app/admin/admin-search-page/admin-search-results/admin-search-result-grid-element/item-search-result/item-admin-search-result-grid-element.component.spec.ts
index dedada5f5f..334d69f19a 100644
--- a/src/app/admin/admin-search-page/admin-search-results/admin-search-result-grid-element/item-search-result/item-admin-search-result-grid-element.component.spec.ts
+++ b/src/app/admin/admin-search-page/admin-search-results/admin-search-result-grid-element/item-search-result/item-admin-search-result-grid-element.component.spec.ts
@@ -18,6 +18,8 @@ import { ItemAdminSearchResultGridElementComponent } from './item-admin-search-r
import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/remote-data.utils';
import { getMockThemeService } from '../../../../../shared/mocks/theme-service.mock';
import { ThemeService } from '../../../../../shared/theme-support/theme.service';
+import { AccessStatusDataService } from 'src/app/core/data/access-status-data.service';
+import { AccessStatusObject } from 'src/app/shared/object-list/access-status-badge/access-status.model';
describe('ItemAdminSearchResultGridElementComponent', () => {
let component: ItemAdminSearchResultGridElementComponent;
@@ -31,6 +33,12 @@ describe('ItemAdminSearchResultGridElementComponent', () => {
}
};
+ const mockAccessStatusDataService = {
+ findAccessStatusFor(item: Item): Observable> {
+ return createSuccessfulRemoteDataObject$(new AccessStatusObject());
+ }
+ };
+
const mockThemeService = getMockThemeService();
function init() {
@@ -55,6 +63,7 @@ describe('ItemAdminSearchResultGridElementComponent', () => {
{ provide: TruncatableService, useValue: mockTruncatableService },
{ provide: BitstreamDataService, useValue: mockBitstreamDataService },
{ provide: ThemeService, useValue: mockThemeService },
+ { provide: AccessStatusDataService, useValue: mockAccessStatusDataService },
],
schemas: [NO_ERRORS_SCHEMA]
})
diff --git a/src/app/app-routing-paths.ts b/src/app/app-routing-paths.ts
index 57767b6f3e..6524edef77 100644
--- a/src/app/app-routing-paths.ts
+++ b/src/app/app-routing-paths.ts
@@ -70,6 +70,12 @@ export function getWorkflowItemModuleRoute() {
return `/${WORKFLOW_ITEM_MODULE_PATH}`;
}
+export const WORKSPACE_ITEM_MODULE_PATH = 'workspaceitems';
+
+export function getWorkspaceItemModuleRoute() {
+ return `/${WORKSPACE_ITEM_MODULE_PATH}`;
+}
+
export function getDSORoute(dso: DSpaceObject): string {
if (hasValue(dso)) {
switch ((dso as any).type) {
diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts
index a892e34a5a..9f215da46d 100644
--- a/src/app/app.component.spec.ts
+++ b/src/app/app.component.spec.ts
@@ -4,7 +4,7 @@ import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { CommonModule, DOCUMENT } from '@angular/common';
import { ActivatedRoute, Router } from '@angular/router';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
-import { Angulartics2GoogleAnalytics } from 'angulartics2/ga';
+import { Angulartics2GoogleAnalytics } from 'angulartics2';
// Load the implementations that should be tested
import { AppComponent } from './app.component';
diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index db217ce161..35686ee3ad 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -23,7 +23,7 @@ import { BehaviorSubject, Observable, of } from 'rxjs';
import { select, Store } from '@ngrx/store';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { TranslateService } from '@ngx-translate/core';
-import { Angulartics2GoogleAnalytics } from 'angulartics2/ga';
+import { Angulartics2GoogleAnalytics } from 'angulartics2';
import { MetadataService } from './core/metadata/metadata.service';
import { HostWindowResizeAction } from './shared/host-window.actions';
diff --git a/src/app/bitstream-page/bitstream-page-routing.module.ts b/src/app/bitstream-page/bitstream-page-routing.module.ts
index 27b9db9a05..0bdda29ddf 100644
--- a/src/app/bitstream-page/bitstream-page-routing.module.ts
+++ b/src/app/bitstream-page/bitstream-page-routing.module.ts
@@ -10,6 +10,9 @@ import { ResourcePolicyResolver } from '../shared/resource-policies/resolvers/re
import { ResourcePolicyEditComponent } from '../shared/resource-policies/edit/resource-policy-edit.component';
import { BitstreamAuthorizationsComponent } from './bitstream-authorizations/bitstream-authorizations.component';
import { LegacyBitstreamUrlResolver } from './legacy-bitstream-url.resolver';
+import { BitstreamBreadcrumbResolver } from '../core/breadcrumbs/bitstream-breadcrumb.resolver';
+import { BitstreamBreadcrumbsService } from '../core/breadcrumbs/bitstream-breadcrumbs.service';
+import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.resolver';
const EDIT_BITSTREAM_PATH = ':id/edit';
const EDIT_BITSTREAM_AUTHORIZATIONS_PATH = ':id/authorizations';
@@ -48,7 +51,8 @@ const EDIT_BITSTREAM_AUTHORIZATIONS_PATH = ':id/authorizations';
path: EDIT_BITSTREAM_PATH,
component: EditBitstreamPageComponent,
resolve: {
- bitstream: BitstreamPageResolver
+ bitstream: BitstreamPageResolver,
+ breadcrumb: BitstreamBreadcrumbResolver,
},
canActivate: [AuthenticatedGuard]
},
@@ -67,15 +71,17 @@ const EDIT_BITSTREAM_AUTHORIZATIONS_PATH = ':id/authorizations';
{
path: 'edit',
resolve: {
+ breadcrumb: I18nBreadcrumbResolver,
resourcePolicy: ResourcePolicyResolver
},
component: ResourcePolicyEditComponent,
- data: { title: 'resource-policies.edit.page.title', showBreadcrumbs: true }
+ data: { breadcrumbKey: 'item.edit', title: 'resource-policies.edit.page.title', showBreadcrumbs: true }
},
{
path: '',
resolve: {
- bitstream: BitstreamPageResolver
+ bitstream: BitstreamPageResolver,
+ breadcrumb: BitstreamBreadcrumbResolver,
},
component: BitstreamAuthorizationsComponent,
data: { title: 'bitstream.edit.authorizations.title', showBreadcrumbs: true }
@@ -86,6 +92,8 @@ const EDIT_BITSTREAM_AUTHORIZATIONS_PATH = ':id/authorizations';
],
providers: [
BitstreamPageResolver,
+ BitstreamBreadcrumbResolver,
+ BitstreamBreadcrumbsService
]
})
export class BitstreamPageRoutingModule {
diff --git a/src/app/bitstream-page/bitstream-page.resolver.ts b/src/app/bitstream-page/bitstream-page.resolver.ts
index fd9d5b351b..be92041dfc 100644
--- a/src/app/bitstream-page/bitstream-page.resolver.ts
+++ b/src/app/bitstream-page/bitstream-page.resolver.ts
@@ -7,6 +7,15 @@ import { BitstreamDataService } from '../core/data/bitstream-data.service';
import { followLink, FollowLinkConfig } from '../shared/utils/follow-link-config.model';
import { getFirstCompletedRemoteData } from '../core/shared/operators';
+/**
+ * The self links defined in this list are expected to be requested somewhere in the near future
+ * Requesting them as embeds will limit the number of requests
+ */
+ export const BITSTREAM_PAGE_LINKS_TO_FOLLOW: FollowLinkConfig[] = [
+ followLink('bundle', {}, followLink('item')),
+ followLink('format')
+];
+
/**
* This class represents a resolver that requests a specific bitstream before the route is activated
*/
@@ -34,9 +43,6 @@ export class BitstreamPageResolver implements Resolve> {
* Requesting them as embeds will limit the number of requests
*/
get followLinks(): FollowLinkConfig[] {
- return [
- followLink('bundle', {}, followLink('item')),
- followLink('format')
- ];
+ return BITSTREAM_PAGE_LINKS_TO_FOLLOW;
}
}
diff --git a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.html b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.html
index cd5f4f03a2..107ef99b3e 100644
--- a/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.html
+++ b/src/app/browse-by/browse-by-metadata-page/browse-by-metadata-page.component.html
@@ -24,7 +24,13 @@