Merge remote-tracking branch 'dspaceMain/main' into issue-815-controlled-vocabulary-hierarchical-facets-7.4

# Conflicts:
#	config/config.example.yml
#	src/assets/i18n/en.json5
This commit is contained in:
Jens Vannerum
2022-12-08 17:08:52 +01:00
29 changed files with 5847 additions and 77 deletions

View File

@@ -1,7 +1,7 @@
## References
_Add references/links to any related issues or PRs. These may include:_
* Fixes #[issue-number]
* Requires DSpace/DSpace#[pr-number] (if a REST API PR is required to test this)
* Fixes #`issue-number` (if this fixes an issue ticket)
* Requires DSpace/DSpace#`pr-number` (if a REST API PR is required to test this)
## Description
Short summary of changes (1-2 sentences).
@@ -19,8 +19,10 @@ List of changes in this PR:
_This checklist provides a reminder of what we are going to look for when reviewing your PR. You need not complete this checklist prior to creating your PR (draft PRs are always welcome). If you are unsure about an item in the checklist, don't hesitate to ask. We're here to help!_
- [ ] My PR is small in size (e.g. less than 1,000 lines of code, not including comments & specs/tests), or I have provided reasons as to why that's not possible.
- [ ] My PR passes [TSLint](https://palantir.github.io/tslint/) validation using `yarn run lint`
- [ ] My PR doesn't introduce circular dependencies
- [ ] My PR passes [ESLint](https://eslint.org/) validation using `yarn lint`
- [ ] My PR doesn't introduce circular dependencies (verified via `yarn check-circ-deps`)
- [ ] My PR includes [TypeDoc](https://typedoc.org/) comments for _all new (or modified) public methods and classes_. It also includes TypeDoc for large or complex private methods.
- [ ] My PR passes all specs/tests and includes new/updated specs or tests based on the [Code Testing Guide](https://wiki.lyrasis.org/display/DSPACE/Code+Testing+Guide).
- [ ] If my PR includes new, third-party dependencies (in `package.json`), I've made sure their licenses align with the [DSpace BSD License](https://github.com/DSpace/DSpace/blob/main/LICENSE) based on the [Licensing of Contributions](https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines#CodeContributionGuidelines-LicensingofContributions) documentation.
- [ ] If my PR includes new libraries/dependencies (in `package.json`), I've made sure their licenses align with the [DSpace BSD License](https://github.com/DSpace/DSpace/blob/main/LICENSE) based on the [Licensing of Contributions](https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines#CodeContributionGuidelines-LicensingofContributions) documentation.
- [ ] If my PR includes new features or configurations, I've provided basic technical documentation in the PR itself.
- [ ] If my PR fixes an issue ticket, I've [linked them together](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue).

49
.github/workflows/codescan.yml vendored Normal file
View File

@@ -0,0 +1,49 @@
# DSpace CodeQL code scanning configuration for GitHub
# https://docs.github.com/en/code-security/code-scanning
#
# NOTE: Code scanning must be run separate from our default build.yml
# because CodeQL requires a fresh build with all tests *disabled*.
name: "Code Scanning"
# Run this code scan for all pushes / PRs to main branch. Also run once a week.
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
# Don't run if PR is only updating static documentation
paths-ignore:
- '**/*.md'
- '**/*.txt'
schedule:
- cron: "37 0 * * 1"
jobs:
analyze:
name: Analyze Code
runs-on: ubuntu-latest
# Limit permissions of this GitHub action. Can only write to security-events
permissions:
actions: read
contents: read
security-events: write
steps:
# https://github.com/actions/checkout
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
# https://github.com/github/codeql-action
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: javascript
# Autobuild attempts to build any compiled languages
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# Perform GitHub Code Scanning.
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2

46
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,46 @@
# How to Contribute
DSpace is a community built and supported project. We do not have a centralized development or support team, but have a dedicated group of volunteers who help us improve the software, documentation, resources, etc.
* [Contribute new code via a Pull Request](#contribute-new-code-via-a-pull-request)
* [Contribute documentation](#contribute-documentation)
* [Help others on mailing lists or Slack](#help-others-on-mailing-lists-or-slack)
* [Join a working or interest group](#join-a-working-or-interest-group)
## Contribute new code via a Pull Request
We accept [GitHub Pull Requests (PRs)](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork) at any time from anyone.
Contributors to each release are recognized in our [Release Notes](https://wiki.lyrasis.org/display/DSDOC7x/Release+Notes).
Code Contribution Checklist
- [ ] PRs _should_ be smaller in size (ideally less than 1,000 lines of code, not including comments & tests)
- [ ] PRs **must** pass [ESLint](https://eslint.org/) validation using `yarn lint`
- [ ] PRs **must** not introduce circular dependencies (verified via `yarn check-circ-deps`)
- [ ] PRs **must** include [TypeDoc](https://typedoc.org/) comments for _all new (or modified) public methods and classes_. Large or complex private methods should also have TypeDoc.
- [ ] PRs **must** pass all automated pecs/tests and includes new/updated specs or tests based on the [Code Testing Guide](https://wiki.lyrasis.org/display/DSPACE/Code+Testing+Guide).
- [ ] If a PR includes new libraries/dependencies (in `package.json`), then their software licenses **must** align with the [DSpace BSD License](https://github.com/DSpace/dspace-angular/blob/main/LICENSE) based on the [Licensing of Contributions](https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines#CodeContributionGuidelines-LicensingofContributions) documentation.
- [ ] Basic technical documentation _should_ be provided for any new features or configuration, either in the PR itself or in the DSpace Wiki documentation.
- [ ] If a PR fixes an issue ticket, please [link them together](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue).
Additional details on the code contribution process can be found in our [Code Contribution Guidelines](https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines)
## Contribute documentation
DSpace Documentation is a collaborative effort in a shared Wiki. The latest documentation is at https://wiki.lyrasis.org/display/DSDOC7x
If you find areas of the DSpace Documentation which you wish to improve, please request a Wiki account by emailing wikihelp@lyrasis.org.
Once you have an account setup, contact @tdonohue (via [Slack](https://wiki.lyrasis.org/display/DSPACE/Slack) or email) for access to edit our Documentation.
## Help others on mailing lists or Slack
DSpace has our own [Slack](https://wiki.lyrasis.org/display/DSPACE/Slack) community and [Mailing Lists](https://wiki.lyrasis.org/display/DSPACE/Mailing+Lists) where discussions take place and questions are answered.
Anyone is welcome to join and help others. We just ask you to follow our [Code of Conduct](https://www.lyrasis.org/about/Pages/Code-of-Conduct.aspx) (adopted via LYRASIS).
## Join a working or interest group
Most of the work in building/improving DSpace comes via [Working Groups](https://wiki.lyrasis.org/display/DSPACE/DSpace+Working+Groups) or [Interest Groups](https://wiki.lyrasis.org/display/DSPACE/DSpace+Interest+Groups).
All working/interest groups are open to anyone to join and participate. A few key groups to be aware of include:
* [DSpace 7 Working Group](https://wiki.lyrasis.org/display/DSPACE/DSpace+7+Working+Group) - This is the main (mostly volunteer) development team. We meet weekly to review our current development [project board](https://github.com/orgs/DSpace/projects), assigning tickets and/or PRs.
* [DSpace Community Advisory Team (DCAT)](https://wiki.lyrasis.org/display/cmtygp/DSpace+Community+Advisory+Team) - This is an interest group for repository managers/administrators. We meet monthly to discuss DSpace, share tips & provide feedback back to developers.

View File

@@ -379,10 +379,10 @@ To get the most out of TypeScript, you'll need a TypeScript-aware editor. We've
- [Sublime Text](http://www.sublimetext.com/3)
- [Typescript-Sublime-Plugin](https://github.com/Microsoft/Typescript-Sublime-plugin#installation)
Collaborating
Contributing
-------------
See [the guide on the wiki](https://wiki.lyrasis.org/display/DSPACE/DSpace+7+-+Angular+UI+Development#DSpace7-AngularUIDevelopment-Howtocontribute)
See [Contributing documentation](CONTRIBUTING.md)
File Structure
--------------

View File

@@ -170,6 +170,9 @@ languages:
- code: el
label: Ελληνικά
active: true
- code: uk
label: раї́нська
active: true
# Browse-By Pages
browseBy:
@@ -207,6 +210,11 @@ item:
undoTimeout: 10000 # 10 seconds
# Show the item access status label in items lists
showAccessStatuses: false
bitstream:
# Number of entries in the bitstream list in the item view page.
# Rounded to the nearest size in the list of selectable sizes on the
# settings menu. See pageSizeOptions in 'pagination-component-options.model.ts'.
pageSize: 5
# Collection Page Config
collection:

View File

@@ -18,6 +18,8 @@ import { NotificationsService } from '../../../../shared/notifications/notificat
import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service.stub';
import { PaginationService } from '../../../../core/pagination/pagination.service';
import { PaginationServiceStub } from '../../../../shared/testing/pagination-service.stub';
import { APP_CONFIG } from 'src/config/app-config.interface';
import { environment } from 'src/environments/environment';
describe('FullFileSectionComponent', () => {
let comp: FullFileSectionComponent;
@@ -69,7 +71,8 @@ describe('FullFileSectionComponent', () => {
providers: [
{ provide: BitstreamDataService, useValue: bitstreamDataService },
{ provide: NotificationsService, useValue: new NotificationsServiceStub() },
{ provide: PaginationService, useValue: paginationService }
{ provide: PaginationService, useValue: paginationService },
{ provide: APP_CONFIG, useValue: environment },
],
schemas: [NO_ERRORS_SCHEMA]

View File

@@ -1,4 +1,4 @@
import { Component, Input, OnInit } from '@angular/core';
import { Component, Inject, Input, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { BitstreamDataService } from '../../../../core/data/bitstream-data.service';
@@ -14,6 +14,7 @@ import { NotificationsService } from '../../../../shared/notifications/notificat
import { TranslateService } from '@ngx-translate/core';
import { hasValue, isEmpty } from '../../../../shared/empty.util';
import { PaginationService } from '../../../../core/pagination/pagination.service';
import { AppConfig, APP_CONFIG } from 'src/config/app-config.interface';
/**
* This component renders the file section of the item
@@ -34,26 +35,26 @@ export class FullFileSectionComponent extends FileSectionComponent implements On
originals$: Observable<RemoteData<PaginatedList<Bitstream>>>;
licenses$: Observable<RemoteData<PaginatedList<Bitstream>>>;
pageSize = 5;
originalOptions = Object.assign(new PaginationComponentOptions(), {
id: 'obo',
currentPage: 1,
pageSize: this.pageSize
pageSize: this.appConfig.item.bitstream.pageSize
});
licenseOptions = Object.assign(new PaginationComponentOptions(), {
id: 'lbo',
currentPage: 1,
pageSize: this.pageSize
pageSize: this.appConfig.item.bitstream.pageSize
});
constructor(
bitstreamDataService: BitstreamDataService,
protected notificationsService: NotificationsService,
protected translateService: TranslateService,
protected paginationService: PaginationService
protected paginationService: PaginationService,
@Inject(APP_CONFIG) protected appConfig: AppConfig
) {
super(bitstreamDataService, notificationsService, translateService);
super(bitstreamDataService, notificationsService, translateService, appConfig);
}
ngOnInit(): void {

View File

@@ -17,6 +17,8 @@ import { MetadataFieldWrapperComponent } from '../../../field-components/metadat
import { createPaginatedList } from '../../../../shared/testing/utils.test';
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service.stub';
import { APP_CONFIG } from 'src/config/app-config.interface';
import { environment } from 'src/environments/environment';
describe('FileSectionComponent', () => {
let comp: FileSectionComponent;
@@ -65,7 +67,8 @@ describe('FileSectionComponent', () => {
declarations: [FileSectionComponent, VarDirective, FileSizePipe, MetadataFieldWrapperComponent],
providers: [
{ provide: BitstreamDataService, useValue: bitstreamDataService },
{ provide: NotificationsService, useValue: new NotificationsServiceStub() }
{ provide: NotificationsService, useValue: new NotificationsServiceStub() },
{ provide: APP_CONFIG, useValue: environment }
],
schemas: [NO_ERRORS_SCHEMA]

View File

@@ -1,4 +1,4 @@
import { Component, Input, OnInit } from '@angular/core';
import { Component, Inject, Input, OnInit } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { BitstreamDataService } from '../../../../core/data/bitstream-data.service';
@@ -10,6 +10,7 @@ import { PaginatedList } from '../../../../core/data/paginated-list.model';
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
import { TranslateService } from '@ngx-translate/core';
import { getFirstCompletedRemoteData } from '../../../../core/shared/operators';
import { AppConfig, APP_CONFIG } from 'src/config/app-config.interface';
/**
* This component renders the file section of the item
@@ -35,13 +36,15 @@ export class FileSectionComponent implements OnInit {
isLastPage: boolean;
pageSize = 5;
pageSize: number;
constructor(
protected bitstreamDataService: BitstreamDataService,
protected notificationsService: NotificationsService,
protected translateService: TranslateService
protected translateService: TranslateService,
@Inject(APP_CONFIG) protected appConfig: AppConfig
) {
this.pageSize = this.appConfig.item.bitstream.pageSize;
}
ngOnInit(): void {

View File

@@ -21,6 +21,7 @@ const effects = [
const ENTRY_COMPONENTS = [
// put only entry components that use custom decorator
NavbarSectionComponent,
ExpandableNavbarSectionComponent,
ThemedExpandableNavbarSectionComponent,
];
@@ -34,11 +35,9 @@ const ENTRY_COMPONENTS = [
CoreModule.forRoot()
],
declarations: [
...ENTRY_COMPONENTS,
NavbarComponent,
ThemedNavbarComponent,
NavbarSectionComponent,
ExpandableNavbarSectionComponent,
ThemedExpandableNavbarSectionComponent,
],
providers: [],
exports: [

View File

@@ -53,8 +53,9 @@ export class AuthorizedCollectionSelectorComponent extends DSOSelectorComponent
* Perform a search for authorized collections with the current query and page
* @param query Query to search objects for
* @param page Page to retrieve
* @param useCache Whether or not to use the cache
*/
search(query: string, page: number): Observable<RemoteData<PaginatedList<SearchResult<DSpaceObject>>>> {
search(query: string, page: number, useCache: boolean = true): Observable<RemoteData<PaginatedList<SearchResult<DSpaceObject>>>> {
let searchListService$: Observable<RemoteData<PaginatedList<Collection>>> = null;
const findOptions: FindListOptions = {
currentPage: page,
@@ -69,7 +70,7 @@ export class AuthorizedCollectionSelectorComponent extends DSOSelectorComponent
findOptions);
} else {
searchListService$ = this.collectionDataService
.getAuthorizedCollection(query, findOptions, true, false, followLink('parentCommunity'));
.getAuthorizedCollection(query, findOptions, useCache, false, followLink('parentCommunity'));
}
return searchListService$.pipe(
getFirstCompletedRemoteData(),

View File

@@ -21,12 +21,12 @@
</button>
<button *ngFor="let listEntry of (listEntries$ | async)"
class="list-group-item list-group-item-action border-0 list-entry"
[ngClass]="{'bg-primary': listEntry.indexableObject.id === currentDSOId}"
[ngClass]="{'bg-primary': listEntry['id'] === currentDSOId}"
title="{{ getName(listEntry) }}"
dsHoverClass="ds-hover"
(click)="onSelect.emit(listEntry.indexableObject)" #listEntryElement>
(click)="onClick(listEntry)" #listEntryElement>
<ds-listable-object-component-loader [object]="listEntry" [viewMode]="viewMode"
[linkType]=linkTypes.None [context]="getContext(listEntry.indexableObject.id)"></ds-listable-object-component-loader>
[linkType]=linkTypes.None [context]="getContext(listEntry['id'])"></ds-listable-object-component-loader>
</button>
</ng-container>
<button *ngIf="loading"

View File

@@ -35,6 +35,14 @@ import { RemoteData } from '../../../core/data/remote-data';
import { NotificationsService } from '../../notifications/notifications.service';
import { TranslateService } from '@ngx-translate/core';
import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
import {
ListableNotificationObject
} from '../../object-list/listable-notification-object/listable-notification-object.model';
import { ListableObject } from '../../object-collection/shared/listable-object.model';
import { NotificationType } from '../../notifications/models/notification-type';
import {
LISTABLE_NOTIFICATION_OBJECT
} from '../../object-list/listable-notification-object/listable-notification-object.resource-type';
@Component({
selector: 'ds-dso-selector',
@@ -82,7 +90,7 @@ export class DSOSelectorComponent implements OnInit, OnDestroy {
/**
* List with search results of DSpace objects for the current query
*/
listEntries$: BehaviorSubject<SearchResult<DSpaceObject>[]> = new BehaviorSubject(null);
listEntries$: BehaviorSubject<ListableObject[]> = new BehaviorSubject(null);
/**
* The current page to load
@@ -116,11 +124,6 @@ export class DSOSelectorComponent implements OnInit, OnDestroy {
*/
linkTypes = CollectionElementLinkType;
/**
* Track whether the element has the mouse over it
*/
isMouseOver = false;
/**
* Array to track all subscriptions and unsubscribe them onDestroy
* @type {Array}
@@ -182,10 +185,15 @@ export class DSOSelectorComponent implements OnInit, OnDestroy {
})
);
})
).subscribe((rd) => {
).subscribe((rd: RemoteData<PaginatedList<SearchResult<DSpaceObject>>>) => {
this.updateList(rd);
}));
}
updateList(rd: RemoteData<PaginatedList<SearchResult<DSpaceObject>>>) {
this.loading = false;
if (rd.hasSucceeded) {
const currentEntries = this.listEntries$.getValue();
if (rd.hasSucceeded) {
if (hasNoValue(currentEntries)) {
this.listEntries$.next(rd.payload.page);
} else {
@@ -194,10 +202,9 @@ export class DSOSelectorComponent implements OnInit, OnDestroy {
// Check if there are more pages available after the current one
this.hasNextPage = rd.payload.totalElements > this.listEntries$.getValue().length;
} else {
this.listEntries$.next(null);
this.listEntries$.next([...(hasNoValue(currentEntries) ? [] : this.listEntries$.getValue()), new ListableNotificationObject(NotificationType.Error, 'dso-selector.results-could-not-be-retrieved', LISTABLE_NOTIFICATION_OBJECT.value)]);
this.hasNextPage = false;
}
}));
}
/**
@@ -211,8 +218,9 @@ export class DSOSelectorComponent implements OnInit, OnDestroy {
* Perform a search for the current query and page
* @param query Query to search objects for
* @param page Page to retrieve
* @param useCache Whether or not to use the cache
*/
search(query: string, page: number): Observable<RemoteData<PaginatedList<SearchResult<DSpaceObject>>>> {
search(query: string, page: number, useCache: boolean = true): Observable<RemoteData<PaginatedList<SearchResult<DSpaceObject>>>> {
return this.searchService.search(
new PaginatedSearchOptions({
query: query,
@@ -220,7 +228,9 @@ export class DSOSelectorComponent implements OnInit, OnDestroy {
pagination: Object.assign({}, this.defaultPagination, {
currentPage: page
})
})
}),
null,
useCache,
).pipe(
getFirstCompletedRemoteData()
);
@@ -262,7 +272,28 @@ export class DSOSelectorComponent implements OnInit, OnDestroy {
this.subs.filter((sub) => hasValue(sub)).forEach((sub) => sub.unsubscribe());
}
getName(searchResult: SearchResult<DSpaceObject>): string {
return this.dsoNameService.getName(searchResult.indexableObject);
/**
* Handles the user clicks on the {@link ListableObject}s. When the {@link listableObject} is a
* {@link ListableObject} it will retry the error when the user clicks it. Otherwise it will emit the {@link onSelect}.
*
* @param listableObject The {@link ListableObject} to evaluate
*/
onClick(listableObject: ListableObject): void {
if (hasValue((listableObject as SearchResult<DSpaceObject>).indexableObject)) {
this.onSelect.emit((listableObject as SearchResult<DSpaceObject>).indexableObject);
} else {
this.listEntries$.value.pop();
this.hasNextPage = true;
this.search(this.input.value ? this.input.value : '', this.currentPage$.value, false).pipe(
getFirstCompletedRemoteData(),
).subscribe((rd: RemoteData<PaginatedList<SearchResult<DSpaceObject>>>) => {
this.updateList(rd);
});
}
}
getName(listableObject: ListableObject): string {
return hasValue((listableObject as SearchResult<DSpaceObject>).indexableObject) ?
this.dsoNameService.getName((listableObject as SearchResult<DSpaceObject>).indexableObject) : null;
}
}

View File

@@ -9,7 +9,7 @@
<h3 class="position-relative py-1 my-3 font-weight-normal">
<hr>
<div id="create-community-or-separator" class="text-center position-absolute w-100">
<span class="px-4 bg-white">or</span>
<span class="px-4 bg-white">{{'dso-selector.create.community.or-divider' | translate}}</span>
</div>
</h3>

View File

@@ -0,0 +1 @@
<div class="alert d-block {{ object?.notificationType }} m-0">{{ object?.message | translate }}</div>

View File

@@ -0,0 +1,43 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ListableNotificationObjectComponent } from './listable-notification-object.component';
import { NotificationType } from '../../notifications/models/notification-type';
import { ListableNotificationObject } from './listable-notification-object.model';
import { By } from '@angular/platform-browser';
import { TranslateModule } from '@ngx-translate/core';
describe('ListableNotificationObjectComponent', () => {
let component: ListableNotificationObjectComponent;
let fixture: ComponentFixture<ListableNotificationObjectComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
],
declarations: [
ListableNotificationObjectComponent,
],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ListableNotificationObjectComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
describe('ui', () => {
it('should display the given error message', () => {
component.object = new ListableNotificationObject(NotificationType.Error, 'test error message');
fixture.detectChanges();
const listableNotificationObject: Element = fixture.debugElement.query(By.css('.alert')).nativeElement;
expect(listableNotificationObject.className).toContain(NotificationType.Error);
expect(listableNotificationObject.innerHTML).toBe('test error message');
});
});
afterEach(() => {
fixture.debugElement.nativeElement.remove();
});
});

View File

@@ -0,0 +1,21 @@
import { Component } from '@angular/core';
import {
AbstractListableElementComponent
} from '../../object-collection/shared/object-collection-element/abstract-listable-element.component';
import { ListableNotificationObject } from './listable-notification-object.model';
import { listableObjectComponent } from '../../object-collection/shared/listable-object/listable-object.decorator';
import { ViewMode } from '../../../core/shared/view-mode.model';
import { LISTABLE_NOTIFICATION_OBJECT } from './listable-notification-object.resource-type';
/**
* The component for displaying a notifications inside an object list
*/
@listableObjectComponent(ListableNotificationObject, ViewMode.ListElement)
@listableObjectComponent(LISTABLE_NOTIFICATION_OBJECT.value, ViewMode.ListElement)
@Component({
selector: 'ds-listable-notification-object',
templateUrl: './listable-notification-object.component.html',
styleUrls: ['./listable-notification-object.component.scss'],
})
export class ListableNotificationObjectComponent extends AbstractListableElementComponent<ListableNotificationObject> {
}

View File

@@ -0,0 +1,36 @@
import { ListableObject } from '../../object-collection/shared/listable-object.model';
import { typedObject } from '../../../core/cache/builders/build-decorators';
import { TypedObject } from '../../../core/cache/typed-object.model';
import { LISTABLE_NOTIFICATION_OBJECT } from './listable-notification-object.resource-type';
import { GenericConstructor } from '../../../core/shared/generic-constructor';
import { NotificationType } from '../../notifications/models/notification-type';
import { ResourceType } from '../../../core/shared/resource-type';
/**
* Object representing a notification message inside a list of objects
*/
@typedObject
export class ListableNotificationObject extends ListableObject implements TypedObject {
static type: ResourceType = LISTABLE_NOTIFICATION_OBJECT;
type: ResourceType = LISTABLE_NOTIFICATION_OBJECT;
protected renderTypes: string[];
constructor(
public notificationType: NotificationType = NotificationType.Error,
public message: string = 'listable-notification-object.default-message',
...renderTypes: string[]
) {
super();
this.renderTypes = renderTypes;
}
/**
* Method that returns as which type of object this object should be rendered.
*/
getRenderTypes(): (string | GenericConstructor<ListableObject>)[] {
return [...this.renderTypes, this.constructor as GenericConstructor<ListableObject>];
}
}

View File

@@ -0,0 +1,9 @@
import { ResourceType } from '../../../core/shared/resource-type';
/**
* The resource type for {@link ListableNotificationObject}
*
* Needs to be in a separate file to prevent circular
* dependencies in webpack.
*/
export const LISTABLE_NOTIFICATION_OBJECT = new ResourceType('listable-notification-object');

View File

@@ -9,7 +9,7 @@
<h3 class="position-relative py-1 my-3 font-weight-normal">
<hr>
<div id="create-community-or-separator" class="text-center position-absolute w-100">
<span class="px-4 bg-white">or</span>
<span class="px-4 bg-white">{{'dso-selector.' + action + '.' + objectType.toString().toLowerCase() + '.or-divider' | translate}}</span>
</div>
</h3>

View File

@@ -323,6 +323,9 @@ import {
} from '../item-page/simple/field-components/specific-field/title/item-page-title-field.component';
import { MarkdownPipe } from './utils/markdown.pipe';
import { GoogleRecaptchaModule } from '../core/google-recaptcha/google-recaptcha.module';
import {
ListableNotificationObjectComponent
} from './object-list/listable-notification-object/listable-notification-object.component';
const MODULES = [
CommonModule,
@@ -510,6 +513,7 @@ const COMPONENTS = [
ScopeSelectorModalComponent,
ItemPageTitleFieldComponent,
ThemedSearchNavbarComponent,
ListableNotificationObjectComponent,
];
const ENTRY_COMPONENTS = [
@@ -575,7 +579,8 @@ const ENTRY_COMPONENTS = [
OnClickMenuItemComponent,
TextMenuItemComponent,
ScopeSelectorModalComponent,
ExternalLinkMenuItemComponent
ExternalLinkMenuItemComponent,
ListableNotificationObjectComponent,
];
const SHARED_ITEM_PAGE_COMPONENTS = [

View File

@@ -1320,6 +1320,8 @@
"curation-task.task.vscan.label": "Virus Scan",
"curation-task.task.registerdoi.label": "Register DOI",
"curation.form.task-select.label": "Task:",
@@ -1366,6 +1368,8 @@
"dso-selector.create.community.head": "New community",
"dso-selector.create.community.or-divider": "or",
"dso-selector.create.community.sub-level": "Create a new community in",
"dso-selector.create.community.top-level": "Create a new top-level community",
@@ -1400,6 +1404,8 @@
"dso-selector.set-scope.community.button": "Search all of DSpace",
"dso-selector.set-scope.community.or-divider": "or",
"dso-selector.set-scope.community.input-header": "Search for a community or collection",
"dso-selector.claim.item.head": "Profile tips",
@@ -1410,6 +1416,8 @@
"dso-selector.claim.item.create-from-scratch": "Create a new one",
"dso-selector.results-could-not-be-retrieved": "Something went wrong, please refresh again ↻",
"confirmation-modal.export-metadata.header": "Export metadata for {{ dsoName }}",
"confirmation-modal.export-metadata.info": "Are you sure you want to export metadata for {{ dsoName }}",
@@ -4037,6 +4045,8 @@
"submission.sections.describe.relationship-lookup.search-tab.tab-title.isFundingAgencyOfProject": "Funder of the Project",
"submission.sections.describe.relationship-lookup.search-tab.tab-title.isPublicationOfAuthor": "Publication of the Author",
"submission.sections.describe.relationship-lookup.selection-tab.title.openAIREFunding": "Funding OpenAIRE API",
"submission.sections.describe.relationship-lookup.selection-tab.title.isProjectOfPublication": "Project",
@@ -4081,6 +4091,8 @@
"submission.sections.describe.relationship-lookup.title.isChildOrgUnitOf": "Parent Organizational Unit",
"submission.sections.describe.relationship-lookup.title.isPublicationOfAuthor": "Publication",
"submission.sections.describe.relationship-lookup.search-tab.toggle-dropdown": "Toggle dropdown",
"submission.sections.describe.relationship-lookup.selection-tab.settings": "Settings",
@@ -4826,6 +4838,8 @@
"person.orcid.registry.auth": "ORCID Authorizations",
"home.recent-submissions.head": "Recent Submissions",
"listable-notification-object.default-message": "This object couldn't be retrieved",
"search.filters.filter.show-tree": "Browse {{ name }} tree",
"vocabulary-treeview.info": "Select a subject to add as search filter"

5475
src/assets/i18n/uk.json5 Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -205,7 +205,8 @@ export class DefaultAppConfig implements AppConfig {
{ code: 'kk', label: 'Қазақ', active: true },
{ code: 'bn', label: 'বাংলা', active: true },
{ code: 'hi', label: 'हिंदी', active: true},
{ code: 'el', label: 'Ελληνικά', active: true }
{ code: 'el', label: 'Ελληνικά', active: true },
{ code: 'uk', label: 'Yкраї́нська', active: true}
];
// Browse-By Pages
@@ -246,7 +247,13 @@ export class DefaultAppConfig implements AppConfig {
undoTimeout: 10000 // 10 seconds
},
// Show the item access status label in items lists
showAccessStatuses: false
showAccessStatuses: false,
bitstream: {
// Number of entries in the bitstream list in the item view page.
// Rounded to the nearest size in the list of selectable sizes on the
// settings menu. See pageSizeOptions in 'pagination-component-options.model.ts'.
pageSize: 5
}
};
// Collection Page Config

View File

@@ -6,4 +6,11 @@ export interface ItemConfig extends Config {
};
// This is used to show the access status label of items in results lists
showAccessStatuses: boolean;
bitstream: {
// Number of entries in the bitstream list in the item view page.
// Rounded to the nearest size in the list of selectable sizes on the
// settings menu. See pageSizeOptions in 'pagination-component-options.model.ts'.
pageSize: number;
}
}

View File

@@ -229,7 +229,13 @@ export const environment: BuildConfig = {
undoTimeout: 10000 // 10 seconds
},
// Show the item access status label in items lists
showAccessStatuses: false
showAccessStatuses: false,
bitstream: {
// Number of entries in the bitstream list in the item view page.
// Rounded to the nearest size in the list of selectable sizes on the
// settings menu. See pageSizeOptions in 'pagination-component-options.model.ts'.
pageSize: 5
}
},
collection: {
edit: {

View File

@@ -9,7 +9,7 @@
<h3 class="position-relative py-1 my-3 font-weight-normal">
<hr>
<div id="create-community-or-separator" class="text-center position-absolute w-100">
<span class="px-4 bg-white">or</span>
<span class="px-4 bg-white">{{'dso-selector.create.community.or-divider' | translate}}</span>
</div>
</h3>

View File

@@ -4793,10 +4793,10 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9:
dependencies:
ms "2.0.0"
debug@4, debug@4.3.3, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@~4.3.1, debug@~4.3.2:
version "4.3.3"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664"
integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==
debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
dependencies:
ms "2.1.2"
@@ -4807,6 +4807,13 @@ debug@4.3.2:
dependencies:
ms "2.1.2"
debug@4.3.3:
version "4.3.3"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664"
integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==
dependencies:
ms "2.1.2"
debug@^3.1.0, debug@^3.1.1, debug@^3.2.6, debug@^3.2.7:
version "3.2.7"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
@@ -4814,13 +4821,6 @@ debug@^3.1.0, debug@^3.1.1, debug@^3.2.6, debug@^3.2.7:
dependencies:
ms "^2.1.1"
debug@^4.3.4:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
dependencies:
ms "2.1.2"
debug@~3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
@@ -4846,9 +4846,9 @@ decimal.js@^10.2.1, decimal.js@^10.3.1:
integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==
decode-uri-component@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=
version "0.2.2"
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9"
integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==
decompress-response@^3.3.0:
version "3.3.0"
@@ -7583,7 +7583,7 @@ isarray@1.0.0, isarray@~1.0.0:
isarray@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e"
integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=
integrity sha512-c2cu3UxbI+b6kR3fy0nRnAhodsvR9dx7U5+znCOzdj6IfP3upFURTr0Xl5BlQZNKZjEtxrmVyfSdeE3O57smoQ==
isbinaryfile@^4.0.8:
version "4.0.8"
@@ -8974,7 +8974,7 @@ mrmime@^1.0.0:
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==
ms@2.1.2:
version "2.1.2"
@@ -11913,9 +11913,9 @@ socket.io-client@2.4.0, socket.io-client@^2.4.0:
to-array "0.1.4"
socket.io-parser@~3.3.0:
version "3.3.2"
resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.2.tgz#ef872009d0adcf704f2fbe830191a14752ad50b6"
integrity sha512-FJvDBuOALxdCI9qwRrO/Rfp9yfndRtc1jSgVgV8FDraihmSP/MLGD5PEuJrNfjALvcQ+vMDM/33AWOYP/JSjDg==
version "3.3.3"
resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.3.tgz#3a8b84823eba87f3f7624e64a8aaab6d6318a72f"
integrity sha512-qOg87q1PMWWTeO01768Yh9ogn7chB9zkKtQnya41Y355S0UmpXgpcrFwAgjYJxu9BdKug5r5e9YtVSeWhKBUZg==
dependencies:
component-emitter "~1.3.0"
debug "~3.1.0"