Merge branch 'main' into main-optimize-metadata-represenation-rendering

# Conflicts:
#	src/app/item-page/simple/field-components/specific-field/item-page-field.component.ts
#	src/app/item-page/simple/metadata-representation-list/metadata-representation-list.component.ts
This commit is contained in:
Giuseppe Digilio
2024-03-13 16:18:28 +01:00
2696 changed files with 52947 additions and 36877 deletions

View File

@@ -8,7 +8,10 @@
"eslint-plugin-deprecation",
"unused-imports",
"eslint-plugin-lodash",
"eslint-plugin-jsonc"
"eslint-plugin-jsonc",
"eslint-plugin-rxjs",
"eslint-plugin-simple-import-sort",
"eslint-plugin-import-newlines"
],
"overrides": [
{
@@ -27,17 +30,29 @@
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking",
"plugin:@angular-eslint/recommended",
"plugin:@angular-eslint/template/process-inline-templates"
"plugin:@angular-eslint/template/process-inline-templates",
"plugin:rxjs/recommended"
],
"rules": {
"indent": [
"error",
2,
{
"SwitchCase": 1
}
],
"max-classes-per-file": [
"error",
1
],
"comma-dangle": [
"off",
"error",
"always-multiline"
],
"object-curly-spacing": [
"error",
"always"
],
"eol-last": [
"error",
"always"
@@ -104,15 +119,13 @@
"allowTernary": true
}
],
"prefer-const": "off", // todo: re-enable & fix errors (more strict than it used to be in TSLint)
"prefer-const": "error",
"no-case-declarations": "error",
"no-extra-boolean-cast": "error",
"prefer-spread": "off",
"no-underscore-dangle": "off",
// todo: disabled rules from eslint:recommended, consider re-enabling & fixing
"no-prototype-builtins": "off",
"no-useless-escape": "off",
"no-case-declarations": "off",
"no-extra-boolean-cast": "off",
"@angular-eslint/directive-selector": [
"error",
@@ -183,7 +196,7 @@
],
"@typescript-eslint/type-annotation-spacing": "error",
"@typescript-eslint/unified-signatures": "error",
"@typescript-eslint/ban-types": "warn", // todo: deal with {} type issues & re-enable
"@typescript-eslint/ban-types": "error",
"@typescript-eslint/no-floating-promises": "warn",
"@typescript-eslint/no-misused-promises": "warn",
"@typescript-eslint/restrict-plus-operands": "warn",
@@ -203,14 +216,45 @@
"deprecation/deprecation": "warn",
"simple-import-sort/imports": "error",
"simple-import-sort/exports": "error",
"import/order": "off",
"import/first": "error",
"import/newline-after-import": "error",
"import/no-duplicates": "error",
"import/no-deprecated": "warn",
"import/no-namespace": "error",
"import-newlines/enforce": [
"error",
{
"items": 1,
"semi": true,
"forceSingleLine": true
}
],
"unused-imports/no-unused-imports": "error",
"lodash/import-scope": [
"error",
"method"
]
],
"rxjs/no-nested-subscribe": "off" // todo: go over _all_ cases
}
},
{
"files": [
"*.spec.ts"
],
"parserOptions": {
"project": [
"./tsconfig.json",
"./cypress/tsconfig.json"
],
"createDefaultProgram": true
},
"rules": {
"prefer-const": "off"
}
},
{
@@ -219,12 +263,7 @@
],
"extends": [
"plugin:@angular-eslint/template/recommended"
],
"rules": {
// todo: re-enable & fix errors
"@angular-eslint/template/no-negated-async": "off",
"@angular-eslint/template/eqeqeq": "off"
}
]
},
{
"files": [

View File

@@ -21,7 +21,6 @@ import './commands';
import 'cypress-axe';
import { DSPACE_XSRF_COOKIE } from 'src/app/core/xsrf/xsrf.constants';
// Runs once before all tests
before(() => {
// Cypress doesn't have access to the running application in Node.js.

View File

@@ -170,9 +170,12 @@
"eslint": "^8.39.0",
"eslint-plugin-deprecation": "^1.4.1",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-import-newlines": "^1.3.1",
"eslint-plugin-jsdoc": "^45.0.0",
"eslint-plugin-jsonc": "^2.6.0",
"eslint-plugin-lodash": "^7.4.0",
"eslint-plugin-rxjs": "^5.0.3",
"eslint-plugin-simple-import-sort": "^10.0.0",
"eslint-plugin-unused-imports": "^2.0.0",
"express-static-gzip": "^2.1.7",
"jasmine-core": "^3.8.0",

View File

@@ -1,5 +1,5 @@
import { URLCombiner } from '../core/url-combiner/url-combiner';
import { getAccessControlModuleRoute } from '../app-routing-paths';
import { URLCombiner } from '../core/url-combiner/url-combiner';
export const EPERSON_PATH = 'epeople';

View File

@@ -1,20 +1,20 @@
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { EPeopleRegistryComponent } from './epeople-registry/epeople-registry.component';
import { GroupFormComponent } from './group-registry/group-form/group-form.component';
import { GroupsRegistryComponent } from './group-registry/groups-registry.component';
import { EPERSON_PATH, GROUP_PATH } from './access-control-routing-paths';
import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.resolver';
import { GroupPageGuard } from './group-registry/group-page.guard';
import { GroupAdministratorGuard } from '../core/data/feature-authorization/feature-authorization-guard/group-administrator.guard';
import { SiteAdministratorGuard } from '../core/data/feature-authorization/feature-authorization-guard/site-administrator.guard';
import {
GroupAdministratorGuard
} from '../core/data/feature-authorization/feature-authorization-guard/group-administrator.guard';
import {
SiteAdministratorGuard
} from '../core/data/feature-authorization/feature-authorization-guard/site-administrator.guard';
EPERSON_PATH,
GROUP_PATH,
} from './access-control-routing-paths';
import { BulkAccessComponent } from './bulk-access/bulk-access.component';
import { EPeopleRegistryComponent } from './epeople-registry/epeople-registry.component';
import { EPersonFormComponent } from './epeople-registry/eperson-form/eperson-form.component';
import { EPersonResolver } from './epeople-registry/eperson-resolver.service';
import { GroupFormComponent } from './group-registry/group-form/group-form.component';
import { GroupPageGuard } from './group-registry/group-page.guard';
import { GroupsRegistryComponent } from './group-registry/groups-registry.component';
@NgModule({
imports: [
@@ -23,10 +23,10 @@ import { EPersonResolver } from './epeople-registry/eperson-resolver.service';
path: EPERSON_PATH,
component: EPeopleRegistryComponent,
resolve: {
breadcrumb: I18nBreadcrumbResolver
breadcrumb: I18nBreadcrumbResolver,
},
data: { title: 'admin.access-control.epeople.title', breadcrumbKey: 'admin.access-control.epeople' },
canActivate: [SiteAdministratorGuard]
canActivate: [SiteAdministratorGuard],
},
{
path: `${EPERSON_PATH}/create`,
@@ -51,40 +51,40 @@ import { EPersonResolver } from './epeople-registry/eperson-resolver.service';
path: GROUP_PATH,
component: GroupsRegistryComponent,
resolve: {
breadcrumb: I18nBreadcrumbResolver
breadcrumb: I18nBreadcrumbResolver,
},
data: { title: 'admin.access-control.groups.title', breadcrumbKey: 'admin.access-control.groups' },
canActivate: [GroupAdministratorGuard]
canActivate: [GroupAdministratorGuard],
},
{
path: `${GROUP_PATH}/create`,
component: GroupFormComponent,
resolve: {
breadcrumb: I18nBreadcrumbResolver
breadcrumb: I18nBreadcrumbResolver,
},
data: { title: 'admin.access-control.groups.title.addGroup', breadcrumbKey: 'admin.access-control.groups.addGroup' },
canActivate: [GroupAdministratorGuard]
canActivate: [GroupAdministratorGuard],
},
{
path: `${GROUP_PATH}/:groupId/edit`,
component: GroupFormComponent,
resolve: {
breadcrumb: I18nBreadcrumbResolver
breadcrumb: I18nBreadcrumbResolver,
},
data: { title: 'admin.access-control.groups.title.singleGroup', breadcrumbKey: 'admin.access-control.groups.singleGroup' },
canActivate: [GroupPageGuard]
canActivate: [GroupPageGuard],
},
{
path: 'bulk-access',
component: BulkAccessComponent,
resolve: {
breadcrumb: I18nBreadcrumbResolver
breadcrumb: I18nBreadcrumbResolver,
},
data: { title: 'admin.access-control.bulk-access.title', breadcrumbKey: 'admin.access-control.bulk-access' },
canActivate: [SiteAdministratorGuard]
canActivate: [SiteAdministratorGuard],
},
])
]
]),
],
})
/**
* Routing module for the AccessControl section of the admin sidebar

View File

@@ -1,23 +1,27 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { AbstractControl } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { NgbAccordionModule } from '@ng-bootstrap/ng-bootstrap';
import {
DYNAMIC_ERROR_MESSAGES_MATCHER,
DynamicErrorMessagesMatcher,
} from '@ng-dynamic-forms/core';
import { AccessControlFormModule } from '../shared/access-control-form-container/access-control-form.module';
import { FormModule } from '../shared/form/form.module';
import { SearchModule } from '../shared/search/search.module';
import { SharedModule } from '../shared/shared.module';
import { AccessControlRoutingModule } from './access-control-routing.module';
import { BulkAccessBrowseComponent } from './bulk-access/browse/bulk-access-browse.component';
import { BulkAccessComponent } from './bulk-access/bulk-access.component';
import { BulkAccessSettingsComponent } from './bulk-access/settings/bulk-access-settings.component';
import { EPeopleRegistryComponent } from './epeople-registry/epeople-registry.component';
import { EPersonFormComponent } from './epeople-registry/eperson-form/eperson-form.component';
import { GroupFormComponent } from './group-registry/group-form/group-form.component';
import { MembersListComponent } from './group-registry/group-form/members-list/members-list.component';
import { SubgroupsListComponent } from './group-registry/group-form/subgroup-list/subgroups-list.component';
import { GroupsRegistryComponent } from './group-registry/groups-registry.component';
import { FormModule } from '../shared/form/form.module';
import { DYNAMIC_ERROR_MESSAGES_MATCHER, DynamicErrorMessagesMatcher } from '@ng-dynamic-forms/core';
import { AbstractControl } from '@angular/forms';
import { BulkAccessComponent } from './bulk-access/bulk-access.component';
import { NgbAccordionModule } from '@ng-bootstrap/ng-bootstrap';
import { BulkAccessBrowseComponent } from './bulk-access/browse/bulk-access-browse.component';
import { BulkAccessSettingsComponent } from './bulk-access/settings/bulk-access-settings.component';
import { SearchModule } from '../shared/search/search.module';
import { AccessControlFormModule } from '../shared/access-control-form-container/access-control-form.module';
/**
* Condition for displaying error messages on email form field
@@ -55,9 +59,9 @@ export const ValidateEmailErrorStateMatcher: DynamicErrorMessagesMatcher =
providers: [
{
provide: DYNAMIC_ERROR_MESSAGES_MATCHER,
useValue: ValidateEmailErrorStateMatcher
useValue: ValidateEmailErrorStateMatcher,
},
]
],
})
/**
* This module handles all components related to the access control pages

View File

@@ -1,16 +1,22 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { of } from 'rxjs';
import { NgbAccordionModule, NgbNavModule } from '@ng-bootstrap/ng-bootstrap';
import {
ComponentFixture,
TestBed,
waitForAsync,
} from '@angular/core/testing';
import {
NgbAccordionModule,
NgbNavModule,
} from '@ng-bootstrap/ng-bootstrap';
import { TranslateModule } from '@ngx-translate/core';
import { of } from 'rxjs';
import { BulkAccessBrowseComponent } from './bulk-access-browse.component';
import { buildPaginatedList } from '../../../core/data/paginated-list.model';
import { PageInfo } from '../../../core/shared/page-info.model';
import { SelectableListService } from '../../../shared/object-list/selectable-list/selectable-list.service';
import { SelectableObject } from '../../../shared/object-list/selectable-list/selectable-list.service.spec';
import { PageInfo } from '../../../core/shared/page-info.model';
import { buildPaginatedList } from '../../../core/data/paginated-list.model';
import { createSuccessfulRemoteDataObject } from '../../../shared/remote-data.utils';
import { BulkAccessBrowseComponent } from './bulk-access-browse.component';
describe('BulkAccessBrowseComponent', () => {
let component: BulkAccessBrowseComponent;
@@ -31,13 +37,13 @@ describe('BulkAccessBrowseComponent', () => {
imports: [
NgbAccordionModule,
NgbNavModule,
TranslateModule.forRoot()
TranslateModule.forRoot(),
],
declarations: [BulkAccessBrowseComponent],
providers: [ { provide: SelectableListService, useValue: selectableListService }, ],
providers: [ { provide: SelectableListService, useValue: selectableListService } ],
schemas: [
NO_ERRORS_SCHEMA
]
NO_ERRORS_SCHEMA,
],
}).compileComponents();
}));
@@ -72,7 +78,7 @@ describe('BulkAccessBrowseComponent', () => {
'elementsPerPage': 5,
'totalElements': 2,
'totalPages': 1,
'currentPage': 1
'currentPage': 1,
}), [selected1, selected2]) ;
const rd = createSuccessfulRemoteDataObject(list);

View File

@@ -1,19 +1,32 @@
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import {
Component,
Input,
OnDestroy,
OnInit,
} from '@angular/core';
import {
BehaviorSubject,
Subscription,
} from 'rxjs';
import {
distinctUntilChanged,
map,
} from 'rxjs/operators';
import { BehaviorSubject, Subscription } from 'rxjs';
import { distinctUntilChanged, map } from 'rxjs/operators';
import { SEARCH_CONFIG_SERVICE } from '../../../my-dspace-page/my-dspace-page.component';
import { SearchConfigurationService } from '../../../core/shared/search/search-configuration.service';
import { SelectableListService } from '../../../shared/object-list/selectable-list/selectable-list.service';
import { SelectableListState } from '../../../shared/object-list/selectable-list/selectable-list.reducer';
import {
buildPaginatedList,
PaginatedList,
} from '../../../core/data/paginated-list.model';
import { RemoteData } from '../../../core/data/remote-data';
import { buildPaginatedList, PaginatedList } from '../../../core/data/paginated-list.model';
import { ListableObject } from '../../../shared/object-collection/shared/listable-object.model';
import { createSuccessfulRemoteDataObject } from '../../../shared/remote-data.utils';
import { PageInfo } from '../../../core/shared/page-info.model';
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
import { SearchConfigurationService } from '../../../core/shared/search/search-configuration.service';
import { SEARCH_CONFIG_SERVICE } from '../../../my-dspace-page/my-dspace-page.component';
import { hasValue } from '../../../shared/empty.util';
import { ListableObject } from '../../../shared/object-collection/shared/listable-object.model';
import { SelectableListState } from '../../../shared/object-list/selectable-list/selectable-list.reducer';
import { SelectableListService } from '../../../shared/object-list/selectable-list/selectable-list.service';
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
import { createSuccessfulRemoteDataObject } from '../../../shared/remote-data.utils';
@Component({
selector: 'ds-bulk-access-browse',
@@ -22,9 +35,9 @@ import { hasValue } from '../../../shared/empty.util';
providers: [
{
provide: SEARCH_CONFIG_SERVICE,
useClass: SearchConfigurationService
}
]
useClass: SearchConfigurationService,
},
],
})
export class BulkAccessBrowseComponent implements OnInit, OnDestroy {
@@ -49,7 +62,7 @@ export class BulkAccessBrowseComponent implements OnInit, OnDestroy {
paginationOptions$: BehaviorSubject<PaginationComponentOptions> = new BehaviorSubject<PaginationComponentOptions>(Object.assign(new PaginationComponentOptions(), {
id: 'bas',
pageSize: 5,
currentPage: 1
currentPage: 1,
}));
/**
@@ -67,20 +80,20 @@ export class BulkAccessBrowseComponent implements OnInit, OnDestroy {
this.subs.push(
this.selectableListService.getSelectableList(this.listId).pipe(
distinctUntilChanged(),
map((list: SelectableListState) => this.generatePaginatedListBySelectedElements(list))
).subscribe(this.objectsSelected$)
map((list: SelectableListState) => this.generatePaginatedListBySelectedElements(list)),
).subscribe(this.objectsSelected$),
);
}
pageNext() {
this.paginationOptions$.next(Object.assign(new PaginationComponentOptions(), this.paginationOptions$.value, {
currentPage: this.paginationOptions$.value.currentPage + 1
currentPage: this.paginationOptions$.value.currentPage + 1,
}));
}
pagePrev() {
this.paginationOptions$.next(Object.assign(new PaginationComponentOptions(), this.paginationOptions$.value, {
currentPage: this.paginationOptions$.value.currentPage - 1
currentPage: this.paginationOptions$.value.currentPage - 1,
}));
}
@@ -99,12 +112,12 @@ export class BulkAccessBrowseComponent implements OnInit, OnDestroy {
elementsPerPage: this.paginationOptions$.value.pageSize,
totalElements: list?.selection.length,
totalPages: this.calculatePageCount(this.paginationOptions$.value.pageSize, list?.selection.length),
currentPage: this.paginationOptions$.value.currentPage
currentPage: this.paginationOptions$.value.currentPage,
});
if (pageInfo.currentPage > pageInfo.totalPages) {
pageInfo.currentPage = pageInfo.totalPages;
this.paginationOptions$.next(Object.assign(new PaginationComponentOptions(), this.paginationOptions$.value, {
currentPage: pageInfo.currentPage
currentPage: pageInfo.currentPage,
}));
}
return createSuccessfulRemoteDataObject(buildPaginatedList(pageInfo, list?.selection || []));

View File

@@ -1,18 +1,20 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import {
ComponentFixture,
TestBed,
} from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { TranslateModule } from '@ngx-translate/core';
import { of } from 'rxjs';
import { BulkAccessComponent } from './bulk-access.component';
import { BulkAccessControlService } from '../../shared/access-control-form-container/bulk-access-control.service';
import { SelectableListService } from '../../shared/object-list/selectable-list/selectable-list.service';
import { SelectableListState } from '../../shared/object-list/selectable-list/selectable-list.reducer';
import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
import { Process } from '../../process-page/processes/process.model';
import { RouterTestingModule } from '@angular/router/testing';
import { BulkAccessControlService } from '../../shared/access-control-form-container/bulk-access-control.service';
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { SelectableListState } from '../../shared/object-list/selectable-list/selectable-list.reducer';
import { SelectableListService } from '../../shared/object-list/selectable-list/selectable-list.service';
import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
import { NotificationsServiceStub } from '../../shared/testing/notifications-service.stub';
import { BulkAccessComponent } from './bulk-access.component';
describe('BulkAccessComponent', () => {
let component: BulkAccessComponent;
@@ -31,35 +33,35 @@ describe('BulkAccessComponent', () => {
'startDate': {
'year': 2026,
'month': 5,
'day': 31
'day': 31,
},
'endDate': null,
},
'endDate': null
}
],
'state': {
'item': {
'toggleStatus': true,
'accessMode': 'replace'
'accessMode': 'replace',
},
'bitstream': {
'toggleStatus': false,
'accessMode': '',
'changesLimit': '',
'selectedBitstreams': []
}
}
'selectedBitstreams': [],
},
},
};
const mockFile = {
'uuids': [
'1234', '5678'
'1234', '5678',
],
'file': { }
'file': { },
};
const mockSettings: any = jasmine.createSpyObj('AccessControlFormContainerComponent', {
getValue: jasmine.createSpy('getValue'),
reset: jasmine.createSpy('reset')
reset: jasmine.createSpy('reset'),
});
const selection: any[] = [{ indexableObject: { uuid: '1234' } }, { indexableObject: { uuid: '5678' } }];
const selectableListState: SelectableListState = { id: 'test', selection };
@@ -71,15 +73,15 @@ describe('BulkAccessComponent', () => {
await TestBed.configureTestingModule({
imports: [
RouterTestingModule,
TranslateModule.forRoot()
TranslateModule.forRoot(),
],
declarations: [ BulkAccessComponent ],
providers: [
{ provide: BulkAccessControlService, useValue: bulkAccessControlServiceMock },
{ provide: NotificationsService, useValue: NotificationsServiceStub },
{ provide: SelectableListService, useValue: selectableListServiceMock }
{ provide: SelectableListService, useValue: selectableListServiceMock },
],
schemas: [NO_ERRORS_SCHEMA]
schemas: [NO_ERRORS_SCHEMA],
})
.compileComponents();
});

View File

@@ -1,17 +1,26 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import {
Component,
OnInit,
ViewChild,
} from '@angular/core';
import {
BehaviorSubject,
Subscription,
} from 'rxjs';
import {
distinctUntilChanged,
map,
} from 'rxjs/operators';
import { BehaviorSubject, Subscription } from 'rxjs';
import { distinctUntilChanged, map } from 'rxjs/operators';
import { BulkAccessSettingsComponent } from './settings/bulk-access-settings.component';
import { BulkAccessControlService } from '../../shared/access-control-form-container/bulk-access-control.service';
import { SelectableListState } from '../../shared/object-list/selectable-list/selectable-list.reducer';
import { SelectableListService } from '../../shared/object-list/selectable-list/selectable-list.service';
import { BulkAccessSettingsComponent } from './settings/bulk-access-settings.component';
@Component({
selector: 'ds-bulk-access',
templateUrl: './bulk-access.component.html',
styleUrls: ['./bulk-access.component.scss']
styleUrls: ['./bulk-access.component.scss'],
})
export class BulkAccessComponent implements OnInit {
@@ -37,7 +46,7 @@ export class BulkAccessComponent implements OnInit {
constructor(
private bulkAccessControlService: BulkAccessControlService,
private selectableListService: SelectableListService
private selectableListService: SelectableListService,
) {
}
@@ -45,8 +54,8 @@ export class BulkAccessComponent implements OnInit {
this.subs.push(
this.selectableListService.getSelectableList(this.listId).pipe(
distinctUntilChanged(),
map((list: SelectableListState) => this.generateIdListBySelectedElements(list))
).subscribe(this.objectsSelected$)
map((list: SelectableListState) => this.generateIdListBySelectedElements(list)),
).subscribe(this.objectsSelected$),
);
}
@@ -74,12 +83,12 @@ export class BulkAccessComponent implements OnInit {
const { file } = this.bulkAccessControlService.createPayloadFile({
bitstreamAccess,
itemAccess,
state: settings.state
state: settings.state,
});
this.bulkAccessControlService.executeScript(
this.objectsSelected$.value || [],
file
file,
).subscribe();
}

View File

@@ -1,8 +1,12 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import {
ComponentFixture,
TestBed,
} from '@angular/core/testing';
import { NgbAccordionModule } from '@ng-bootstrap/ng-bootstrap';
import { TranslateModule } from '@ngx-translate/core';
import { BulkAccessSettingsComponent } from './bulk-access-settings.component';
import { NO_ERRORS_SCHEMA } from '@angular/core';
describe('BulkAccessSettingsComponent', () => {
let component: BulkAccessSettingsComponent;
@@ -15,35 +19,35 @@ describe('BulkAccessSettingsComponent', () => {
'startDate': {
'year': 2026,
'month': 5,
'day': 31
'day': 31,
},
'endDate': null,
},
'endDate': null
}
],
'state': {
'item': {
'toggleStatus': true,
'accessMode': 'replace'
'accessMode': 'replace',
},
'bitstream': {
'toggleStatus': false,
'accessMode': '',
'changesLimit': '',
'selectedBitstreams': []
}
}
'selectedBitstreams': [],
},
},
};
const mockControl: any = jasmine.createSpyObj('AccessControlFormContainerComponent', {
getFormValue: jasmine.createSpy('getFormValue'),
reset: jasmine.createSpy('reset')
reset: jasmine.createSpy('reset'),
});
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [NgbAccordionModule, TranslateModule.forRoot()],
declarations: [BulkAccessSettingsComponent],
schemas: [NO_ERRORS_SCHEMA]
schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
});

View File

@@ -1,13 +1,15 @@
import { Component, ViewChild } from '@angular/core';
import {
AccessControlFormContainerComponent
} from '../../../shared/access-control-form-container/access-control-form-container.component';
Component,
ViewChild,
} from '@angular/core';
import { AccessControlFormContainerComponent } from '../../../shared/access-control-form-container/access-control-form-container.component';
@Component({
selector: 'ds-bulk-access-settings',
templateUrl: 'bulk-access-settings.component.html',
styleUrls: ['./bulk-access-settings.component.scss'],
exportAs: 'dsBulkSettings'
exportAs: 'dsBulkSettings',
})
export class BulkAccessSettingsComponent {

View File

@@ -1,5 +1,6 @@
/* eslint-disable max-classes-per-file */
import { Action } from '@ngrx/store';
import { EPerson } from '../../core/eperson/models/eperson.model';
import { type } from '../../shared/ngrx/type';

View File

@@ -43,7 +43,7 @@
<ds-themed-loading *ngIf="searching$ | async"></ds-themed-loading>
<ds-pagination
*ngIf="(pageInfoState$ | async)?.totalElements > 0 && !(searching$ | async)"
*ngIf="(pageInfoState$ | async)?.totalElements > 0 && (searching$ | async) !== true"
[paginationOptions]="config"
[pageInfoState]="pageInfoState$"
[collectionSize]="(pageInfoState$ | async)?.totalElements"
@@ -87,7 +87,7 @@
</ds-pagination>
<div *ngIf="(pageInfoState$ | async)?.totalElements == 0" class="alert alert-info w-100 mb-2" role="alert">
<div *ngIf="(pageInfoState$ | async)?.totalElements === 0" class="alert alert-info w-100 mb-2" role="alert">
{{labelPrefix + 'no-items' | translate}}
</div>
</div>

View File

@@ -1,30 +1,58 @@
import { Router } from '@angular/router';
import { Observable, of as observableOf } from 'rxjs';
import { CommonModule } from '@angular/common';
import { DebugElement, NO_ERRORS_SCHEMA } from '@angular/core';
import { ComponentFixture, fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { BrowserModule, By } from '@angular/platform-browser';
import { NgbModule, NgbModal } from '@ng-bootstrap/ng-bootstrap';
import {
DebugElement,
NO_ERRORS_SCHEMA,
} from '@angular/core';
import {
ComponentFixture,
fakeAsync,
TestBed,
tick,
waitForAsync,
} from '@angular/core/testing';
import {
FormsModule,
ReactiveFormsModule,
} from '@angular/forms';
import {
BrowserModule,
By,
} from '@angular/platform-browser';
import { Router } from '@angular/router';
import {
NgbModal,
NgbModule,
} from '@ng-bootstrap/ng-bootstrap';
import { TranslateModule } from '@ngx-translate/core';
import { buildPaginatedList, PaginatedList } from '../../core/data/paginated-list.model';
import {
Observable,
of as observableOf,
} from 'rxjs';
import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
import { FindListOptions } from '../../core/data/find-list-options.model';
import {
buildPaginatedList,
PaginatedList,
} from '../../core/data/paginated-list.model';
import { RemoteData } from '../../core/data/remote-data';
import { RequestService } from '../../core/data/request.service';
import { EPersonDataService } from '../../core/eperson/eperson-data.service';
import { EPerson } from '../../core/eperson/models/eperson.model';
import { PaginationService } from '../../core/pagination/pagination.service';
import { PageInfo } from '../../core/shared/page-info.model';
import { FormBuilderService } from '../../shared/form/builder/form-builder.service';
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { EPeopleRegistryComponent } from './epeople-registry.component';
import { EPersonMock, EPersonMock2 } from '../../shared/testing/eperson.mock';
import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
import { getMockFormBuilderService } from '../../shared/mocks/form-builder-service.mock';
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
import {
EPersonMock,
EPersonMock2,
} from '../../shared/testing/eperson.mock';
import { NotificationsServiceStub } from '../../shared/testing/notifications-service.stub';
import { RouterStub } from '../../shared/testing/router.stub';
import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
import { RequestService } from '../../core/data/request.service';
import { PaginationService } from '../../core/pagination/pagination.service';
import { PaginationServiceStub } from '../../shared/testing/pagination-service.stub';
import { FindListOptions } from '../../core/data/find-list-options.model';
import { RouterStub } from '../../shared/testing/router.stub';
import { EPeopleRegistryComponent } from './epeople-registry.component';
describe('EPeopleRegistryComponent', () => {
let component: EPeopleRegistryComponent;
@@ -48,7 +76,7 @@ describe('EPeopleRegistryComponent', () => {
elementsPerPage: this.allEpeople.length,
totalElements: this.allEpeople.length,
totalPages: 1,
currentPage: 1
currentPage: 1,
}), this.allEpeople));
},
getActiveEPerson(): Observable<EPerson> {
@@ -63,7 +91,7 @@ describe('EPeopleRegistryComponent', () => {
elementsPerPage: [result].length,
totalElements: [result].length,
totalPages: 1,
currentPage: 1
currentPage: 1,
}), [result]));
}
if (scope === 'metadata') {
@@ -72,7 +100,7 @@ describe('EPeopleRegistryComponent', () => {
elementsPerPage: this.allEpeople.length,
totalElements: this.allEpeople.length,
totalPages: 1,
currentPage: 1
currentPage: 1,
}), this.allEpeople));
}
const result = this.allEpeople.find((ePerson: EPerson) => {
@@ -82,14 +110,14 @@ describe('EPeopleRegistryComponent', () => {
elementsPerPage: [result].length,
totalElements: [result].length,
totalPages: 1,
currentPage: 1
currentPage: 1,
}), [result]));
}
return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo({
elementsPerPage: this.allEpeople.length,
totalElements: this.allEpeople.length,
totalPages: 1,
currentPage: 1
currentPage: 1,
}), this.allEpeople));
},
deleteEPerson(ePerson: EPerson): Observable<boolean> {
@@ -109,10 +137,10 @@ describe('EPeopleRegistryComponent', () => {
},
getEPeoplePageRouterLink(): string {
return '/access-control/epeople';
}
},
};
authorizationService = jasmine.createSpyObj('authorizationService', {
isAuthorized: observableOf(true)
isAuthorized: observableOf(true),
});
builderService = getMockFormBuilderService();
@@ -129,9 +157,9 @@ describe('EPeopleRegistryComponent', () => {
{ provide: FormBuilderService, useValue: builderService },
{ provide: Router, useValue: new RouterStub() },
{ provide: RequestService, useValue: jasmine.createSpyObj('requestService', ['removeByHrefSubstring']) },
{ provide: PaginationService, useValue: paginationService }
{ provide: PaginationService, useValue: paginationService },
],
schemas: [NO_ERRORS_SCHEMA]
schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
}));
@@ -202,7 +230,7 @@ describe('EPeopleRegistryComponent', () => {
const deleteButtons = fixture.debugElement.queryAll(By.css('.access-control-deleteEPersonButton'));
deleteButtons[0].triggerEventHandler('click', {
preventDefault: () => {/**/
}
},
});
tick();
fixture.detectChanges();

View File

@@ -1,28 +1,51 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import {
Component,
OnDestroy,
OnInit,
} from '@angular/core';
import { UntypedFormBuilder } from '@angular/forms';
import { Router } from '@angular/router';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { TranslateService } from '@ngx-translate/core';
import { BehaviorSubject, combineLatest, Observable, Subscription } from 'rxjs';
import { map, switchMap, take } from 'rxjs/operators';
import { buildPaginatedList, PaginatedList } from '../../core/data/paginated-list.model';
import {
BehaviorSubject,
combineLatest,
Observable,
Subscription,
} from 'rxjs';
import {
map,
switchMap,
take,
} from 'rxjs/operators';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
import { FeatureID } from '../../core/data/feature-authorization/feature-id';
import {
buildPaginatedList,
PaginatedList,
} from '../../core/data/paginated-list.model';
import { RemoteData } from '../../core/data/remote-data';
import { RequestService } from '../../core/data/request.service';
import { EPersonDataService } from '../../core/eperson/eperson-data.service';
import { EPerson } from '../../core/eperson/models/eperson.model';
import { EpersonDtoModel } from '../../core/eperson/models/eperson-dto.model';
import { PaginationService } from '../../core/pagination/pagination.service';
import { NoContent } from '../../core/shared/NoContent.model';
import {
getAllSucceededRemoteData,
getFirstCompletedRemoteData,
} from '../../core/shared/operators';
import { PageInfo } from '../../core/shared/page-info.model';
import { ConfirmationModalComponent } from '../../shared/confirmation-modal/confirmation-modal.component';
import { hasValue } from '../../shared/empty.util';
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
import { EpersonDtoModel } from '../../core/eperson/models/eperson-dto.model';
import { FeatureID } from '../../core/data/feature-authorization/feature-id';
import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
import { getAllSucceededRemoteData, getFirstCompletedRemoteData } from '../../core/shared/operators';
import { ConfirmationModalComponent } from '../../shared/confirmation-modal/confirmation-modal.component';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { RequestService } from '../../core/data/request.service';
import { PageInfo } from '../../core/shared/page-info.model';
import { NoContent } from '../../core/shared/NoContent.model';
import { PaginationService } from '../../core/pagination/pagination.service';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
import { getEPersonEditRoute, getEPersonsRoute } from '../access-control-routing-paths';
import {
getEPersonEditRoute,
getEPersonsRoute,
} from '../access-control-routing-paths';
@Component({
selector: 'ds-epeople-registry',
@@ -62,7 +85,7 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy {
config: PaginationComponentOptions = Object.assign(new PaginationComponentOptions(), {
id: 'elp',
pageSize: 5,
currentPage: 1
currentPage: 1,
});
// The search form
@@ -121,7 +144,7 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy {
epersonDtoModel.ableToDelete = authorized;
epersonDtoModel.eperson = eperson;
return epersonDtoModel;
})
}),
);
})).pipe(map((dtos: EpersonDtoModel[]) => {
return buildPaginatedList(epeople.pageInfo, dtos);
@@ -151,14 +174,14 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy {
const scope: string = data.scope;
if (query != null && this.currentSearchQuery !== query) {
void this.router.navigate([getEPersonsRoute()], {
queryParamsHandling: 'merge'
queryParamsHandling: 'merge',
});
this.currentSearchQuery = query;
this.paginationService.resetPage(this.config.id);
}
if (scope != null && this.currentSearchScope !== scope) {
void this.router.navigate([getEPersonsRoute()], {
queryParamsHandling: 'merge'
queryParamsHandling: 'merge',
});
this.currentSearchScope = scope;
this.paginationService.resetPage(this.config.id);
@@ -166,15 +189,15 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy {
}
return this.epersonService.searchByScope(this.currentSearchScope, this.currentSearchQuery, {
currentPage: findListOptions.currentPage,
elementsPerPage: findListOptions.pageSize
elementsPerPage: findListOptions.pageSize,
});
}
},
),
getAllSucceededRemoteData(),
).subscribe((peopleRD) => {
this.ePeople$.next(peopleRD.payload);
this.pageInfoState$.next(peopleRD.payload.pageInfo);
}
},
);
}
@@ -184,7 +207,7 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy {
*/
isActive(eperson: EPerson): Observable<boolean> {
return this.getActiveEPerson().pipe(
map((activeEPerson) => eperson === activeEPerson)
map((activeEPerson) => eperson === activeEPerson),
);
}

View File

@@ -1,6 +1,12 @@
import { EPeopleRegistryCancelEPersonAction, EPeopleRegistryEditEPersonAction } from './epeople-registry.actions';
import { ePeopleRegistryReducer, EPeopleRegistryState } from './epeople-registry.reducers';
import { EPersonMock } from '../../shared/testing/eperson.mock';
import {
EPeopleRegistryCancelEPersonAction,
EPeopleRegistryEditEPersonAction,
} from './epeople-registry.actions';
import {
ePeopleRegistryReducer,
EPeopleRegistryState,
} from './epeople-registry.reducers';
const initialState: EPeopleRegistryState = {
editEPerson: null,

View File

@@ -2,7 +2,7 @@ import { EPerson } from '../../core/eperson/models/eperson.model';
import {
EPeopleRegistryAction,
EPeopleRegistryActionTypes,
EPeopleRegistryEditEPersonAction
EPeopleRegistryEditEPersonAction,
} from './epeople-registry.actions';
/**
@@ -30,13 +30,13 @@ export function ePeopleRegistryReducer(state = initialState, action: EPeopleRegi
case EPeopleRegistryActionTypes.EDIT_EPERSON: {
return Object.assign({}, state, {
editEPerson: (action as EPeopleRegistryEditEPersonAction).eperson
editEPerson: (action as EPeopleRegistryEditEPersonAction).eperson,
});
}
case EPeopleRegistryActionTypes.CANCEL_EDIT_EPERSON: {
return Object.assign({}, state, {
editEPerson: null
editEPerson: null,
});
}

View File

@@ -25,7 +25,7 @@
</button>
</div>
<div *ngIf="displayResetPassword" between class="btn-group">
<button class="btn btn-primary" [disabled]="!(canReset$ | async)" type="button" (click)="resetPassword()">
<button class="btn btn-primary" [disabled]="(canReset$ | async) !== true" type="button" (click)="resetPassword()">
<i class="fa fa-key"></i> {{'admin.access-control.epeople.actions.reset' | translate}}
</button>
</div>
@@ -47,13 +47,13 @@
<div *ngIf="epersonService.getActiveEPerson() | async">
<h2>{{messagePrefix + '.groupsEPersonIsMemberOf' | translate}}</h2>
<ds-themed-loading [showMessage]="false" *ngIf="!(groups | async)"></ds-themed-loading>
<ds-themed-loading [showMessage]="false" *ngIf="groups$ | async | dsHasNoValue"></ds-themed-loading>
<ds-pagination
*ngIf="(groups | async)?.payload?.totalElements > 0"
*ngIf="(groups$ | async)?.payload?.totalElements > 0"
[paginationOptions]="config"
[pageInfoState]="(groups | async)?.payload"
[collectionSize]="(groups | async)?.payload?.totalElements"
[pageInfoState]="groupsPageInfoState$"
[collectionSize]="(groups$ | async)?.payload?.totalElements"
[hideGear]="true"
[hidePagerWhenSinglePage]="true"
(pageChange)="onPageChange($event)">
@@ -68,7 +68,7 @@
</tr>
</thead>
<tbody>
<tr *ngFor="let group of (groups | async)?.payload?.page">
<tr *ngFor="let group of (groups$ | async)?.payload?.page">
<td class="align-middle">{{group.id}}</td>
<td class="align-middle">
<a (click)="groupsDataService.startEditingNewGroup(group)"
@@ -84,7 +84,7 @@
</ds-pagination>
<div *ngIf="(groups | async)?.payload?.totalElements == 0" class="alert alert-info w-100 mb-2" role="alert">
<div *ngIf="(groups$ | async)?.payload?.totalElements === 0" class="alert alert-info w-100 mb-2" role="alert">
<div>{{messagePrefix + '.memberOfNoGroups' | translate}}</div>
<div>
<button [routerLink]="[groupsDataService.getGroupRegistryRouterLink()]"

View File

@@ -1,40 +1,70 @@
import { Observable, of as observableOf } from 'rxjs';
import { CommonModule } from '@angular/common';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { UntypedFormControl, UntypedFormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
import { BrowserModule, By } from '@angular/platform-browser';
import {
ComponentFixture,
TestBed,
waitForAsync,
} from '@angular/core/testing';
import {
FormsModule,
ReactiveFormsModule,
UntypedFormControl,
UntypedFormGroup,
Validators,
} from '@angular/forms';
import {
BrowserModule,
By,
} from '@angular/platform-browser';
import {
ActivatedRoute,
Router,
} from '@angular/router';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { buildPaginatedList, PaginatedList } from '../../../core/data/paginated-list.model';
import {
TranslateLoader,
TranslateModule,
} from '@ngx-translate/core';
import {
Observable,
of as observableOf,
} from 'rxjs';
import { AuthService } from '../../../core/auth/auth.service';
import { EpersonRegistrationService } from '../../../core/data/eperson-registration.service';
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
import { FindListOptions } from '../../../core/data/find-list-options.model';
import {
buildPaginatedList,
PaginatedList,
} from '../../../core/data/paginated-list.model';
import { RemoteData } from '../../../core/data/remote-data';
import { RequestService } from '../../../core/data/request.service';
import { EPersonDataService } from '../../../core/eperson/eperson-data.service';
import { GroupDataService } from '../../../core/eperson/group-data.service';
import { EPerson } from '../../../core/eperson/models/eperson.model';
import { PaginationService } from '../../../core/pagination/pagination.service';
import { PageInfo } from '../../../core/shared/page-info.model';
import { FormBuilderService } from '../../../shared/form/builder/form-builder.service';
import { getMockFormBuilderService } from '../../../shared/mocks/form-builder-service.mock';
import { TranslateLoaderMock } from '../../../shared/mocks/translate-loader.mock';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
import { ActivatedRouteStub } from '../../../shared/testing/active-router.stub';
import { AuthServiceStub } from '../../../shared/testing/auth-service.stub';
import {
EPersonMock,
EPersonMock2,
} from '../../../shared/testing/eperson.mock';
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub';
import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub';
import { RouterStub } from '../../../shared/testing/router.stub';
import { createPaginatedList } from '../../../shared/testing/utils.test';
import { FollowLinkConfig } from '../../../shared/utils/follow-link-config.model';
import { HasNoValuePipe } from '../../../shared/utils/has-no-value.pipe';
import { EPeopleRegistryComponent } from '../epeople-registry.component';
import { EPersonFormComponent } from './eperson-form.component';
import { EPersonMock, EPersonMock2 } from '../../../shared/testing/eperson.mock';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
import { getMockFormBuilderService } from '../../../shared/mocks/form-builder-service.mock';
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub';
import { TranslateLoaderMock } from '../../../shared/mocks/translate-loader.mock';
import { AuthService } from '../../../core/auth/auth.service';
import { AuthServiceStub } from '../../../shared/testing/auth-service.stub';
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
import { GroupDataService } from '../../../core/eperson/group-data.service';
import { createPaginatedList } from '../../../shared/testing/utils.test';
import { RequestService } from '../../../core/data/request.service';
import { PaginationService } from '../../../core/pagination/pagination.service';
import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub';
import { FindListOptions } from '../../../core/data/find-list-options.model';
import { ValidateEmailNotTaken } from './validators/email-taken.validator';
import { EpersonRegistrationService } from '../../../core/data/eperson-registration.service';
import { FollowLinkConfig } from '../../../shared/utils/follow-link-config.model';
import { ActivatedRoute, Router } from '@angular/router';
import { RouterStub } from '../../../shared/testing/router.stub';
import { ActivatedRouteStub } from '../../../shared/testing/active-router.stub';
describe('EPersonFormComponent', () => {
let component: EPersonFormComponent;
@@ -115,7 +145,7 @@ describe('EPersonFormComponent', () => {
},
findById(_id: string, _useCachedVersionIfAvailable = true, _reRequestOnStale = true, ..._linksToFollow: FollowLinkConfig<EPerson>[]): Observable<RemoteData<EPerson>> {
return createSuccessfulRemoteDataObject$(null);
}
},
};
builderService = Object.assign(getMockFormBuilderService(),{
createFormGroup(formModel, options = null) {
@@ -178,7 +208,7 @@ describe('EPersonFormComponent', () => {
},
isObject(value) {
return typeof value === 'object' && value !== null;
}
},
});
authService = new AuthServiceStub();
authorizationService = jasmine.createSpyObj('authorizationService', {
@@ -187,7 +217,7 @@ describe('EPersonFormComponent', () => {
});
groupsDataService = jasmine.createSpyObj('groupsDataService', {
findListByHref: createSuccessfulRemoteDataObject$(createPaginatedList([])),
getGroupRegistryRouterLink: ''
getGroupRegistryRouterLink: '',
});
paginationService = new PaginationServiceStub();
@@ -198,11 +228,14 @@ describe('EPersonFormComponent', () => {
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: TranslateLoaderMock
}
useClass: TranslateLoaderMock,
},
}),
],
declarations: [EPersonFormComponent],
declarations: [
EPersonFormComponent,
HasNoValuePipe,
],
providers: [
{ provide: EPersonDataService, useValue: ePersonDataServiceStub },
{ provide: GroupDataService, useValue: groupsDataService },
@@ -215,14 +248,14 @@ describe('EPersonFormComponent', () => {
{ provide: EpersonRegistrationService, useValue: epersonRegistrationService },
{ provide: ActivatedRoute, useValue: route },
{ provide: Router, useValue: router },
EPeopleRegistryComponent
EPeopleRegistryComponent,
],
schemas: [NO_ERRORS_SCHEMA]
schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
}));
epersonRegistrationService = jasmine.createSpyObj('epersonRegistrationService', {
registerEmail: createSuccessfulRemoteDataObject$(null)
registerEmail: createSuccessfulRemoteDataObject$(null),
});
beforeEach(() => {
@@ -254,12 +287,12 @@ describe('EPersonFormComponent', () => {
metadata: {
'eperson.firstname': [
{
value: firstName
}
value: firstName,
},
],
'eperson.lastname': [
{
value: lastName
value: lastName,
},
],
},
@@ -328,7 +361,7 @@ describe('EPersonFormComponent', () => {
const ePersonServiceWithEperson = Object.assign(ePersonDataServiceStub,{
getEPersonByEmail(): Observable<RemoteData<EPerson>> {
return createSuccessfulRemoteDataObject$(EPersonMock);
}
},
});
component.formGroup.controls.email.setValue('test@test.com');
component.formGroup.controls.email.setAsyncValidators(ValidateEmailNotTaken.createValidator(ePersonServiceWithEperson));
@@ -363,12 +396,12 @@ describe('EPersonFormComponent', () => {
metadata: {
'eperson.firstname': [
{
value: firstName
}
value: firstName,
},
],
'eperson.lastname': [
{
value: lastName
value: lastName,
},
],
},
@@ -404,19 +437,19 @@ describe('EPersonFormComponent', () => {
metadata: {
'eperson.firstname': [
{
value: firstName
}
value: firstName,
},
],
'eperson.lastname': [
{
value: lastName
value: lastName,
},
],
},
email: email,
canLogIn: canLogIn,
requireCertificate: requireCertificate,
_links: undefined
_links: undefined,
});
spyOn(ePersonDataServiceStub, 'getActiveEPerson').and.returnValue(observableOf(expectedWithId));
component.onSubmit();
@@ -436,7 +469,7 @@ describe('EPersonFormComponent', () => {
spyOn(authService, 'impersonate').and.callThrough();
ePersonId = 'testEPersonId';
component.epersonInitial = Object.assign(new EPerson(), {
id: ePersonId
id: ePersonId,
});
component.impersonate();
});
@@ -524,7 +557,7 @@ describe('EPersonFormComponent', () => {
ePersonEmail = 'person.email@4science.it';
component.epersonInitial = Object.assign(new EPerson(), {
id: ePersonId,
email: ePersonEmail
email: ePersonEmail,
});
component.resetPassword();
});

View File

@@ -1,45 +1,68 @@
import { ChangeDetectorRef, Component, EventEmitter, OnDestroy, OnInit, Output } from '@angular/core';
import {
ChangeDetectorRef,
Component,
EventEmitter,
OnDestroy,
OnInit,
Output,
} from '@angular/core';
import { UntypedFormGroup } from '@angular/forms';
import {
ActivatedRoute,
Router,
} from '@angular/router';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import {
DynamicCheckboxModel,
DynamicFormControlModel,
DynamicFormLayout,
DynamicInputModel
DynamicInputModel,
} from '@ng-dynamic-forms/core';
import { TranslateService } from '@ngx-translate/core';
import { combineLatest as observableCombineLatest, Observable, of as observableOf, Subscription } from 'rxjs';
import { debounceTime, finalize, map, switchMap, take } from 'rxjs/operators';
import {
combineLatest as observableCombineLatest,
Observable,
of as observableOf,
Subscription,
} from 'rxjs';
import {
debounceTime,
finalize,
map,
switchMap,
take,
} from 'rxjs/operators';
import { AuthService } from '../../../core/auth/auth.service';
import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
import { EpersonRegistrationService } from '../../../core/data/eperson-registration.service';
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
import { PaginatedList } from '../../../core/data/paginated-list.model';
import { RemoteData } from '../../../core/data/remote-data';
import { RequestService } from '../../../core/data/request.service';
import { EPersonDataService } from '../../../core/eperson/eperson-data.service';
import { GroupDataService } from '../../../core/eperson/group-data.service';
import { EPerson } from '../../../core/eperson/models/eperson.model';
import { Group } from '../../../core/eperson/models/group.model';
import { PaginationService } from '../../../core/pagination/pagination.service';
import { NoContent } from '../../../core/shared/NoContent.model';
import {
getFirstCompletedRemoteData,
getFirstSucceededRemoteData,
getRemoteDataPayload
getRemoteDataPayload,
} from '../../../core/shared/operators';
import { PageInfo } from '../../../core/shared/page-info.model';
import { Registration } from '../../../core/shared/registration.model';
import { TYPE_REQUEST_FORGOT } from '../../../register-email-form/register-email-form.component';
import { ConfirmationModalComponent } from '../../../shared/confirmation-modal/confirmation-modal.component';
import { hasValue } from '../../../shared/empty.util';
import { FormBuilderService } from '../../../shared/form/builder/form-builder.service';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
import { AuthService } from '../../../core/auth/auth.service';
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
import { ConfirmationModalComponent } from '../../../shared/confirmation-modal/confirmation-modal.component';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { RequestService } from '../../../core/data/request.service';
import { NoContent } from '../../../core/shared/NoContent.model';
import { PaginationService } from '../../../core/pagination/pagination.service';
import { followLink } from '../../../shared/utils/follow-link-config.model';
import { ValidateEmailNotTaken } from './validators/email-taken.validator';
import { Registration } from '../../../core/shared/registration.model';
import { EpersonRegistrationService } from '../../../core/data/eperson-registration.service';
import { TYPE_REQUEST_FORGOT } from '../../../register-email-form/register-email-form.component';
import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
import { ActivatedRoute, Router } from '@angular/router';
import { getEPersonsRoute } from '../../access-control-routing-paths';
import { ValidateEmailNotTaken } from './validators/email-taken.validator';
@Component({
selector: 'ds-eperson-form',
@@ -83,28 +106,28 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
formLayout: DynamicFormLayout = {
firstName: {
grid: {
host: 'row'
}
host: 'row',
},
},
lastName: {
grid: {
host: 'row'
}
host: 'row',
},
},
email: {
grid: {
host: 'row'
}
host: 'row',
},
},
canLogIn: {
grid: {
host: 'col col-sm-6 d-inline-block'
}
host: 'col col-sm-6 d-inline-block',
},
},
requireCertificate: {
grid: {
host: 'col col-sm-6 d-inline-block'
}
host: 'col col-sm-6 d-inline-block',
},
},
};
@@ -147,7 +170,12 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
/**
* A list of all the groups this EPerson is a member of
*/
groups: Observable<RemoteData<PaginatedList<Group>>>;
groups$: Observable<RemoteData<PaginatedList<Group>>>;
/**
* The pagination of the {@link groups$} list.
*/
groupsPageInfoState$: Observable<PageInfo>;
/**
* Pagination config used to display the list of groups
@@ -155,7 +183,7 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
config: PaginationComponentOptions = Object.assign(new PaginationComponentOptions(), {
id: 'gem',
pageSize: 5,
currentPage: 1
currentPage: 1,
});
/**
@@ -257,23 +285,23 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
required: true,
errorMessages: {
emailTaken: 'error.validation.emailTaken',
pattern: 'error.validation.NotValidEmail'
pattern: 'error.validation.NotValidEmail',
},
hint: emailHint
hint: emailHint,
});
this.canLogIn = new DynamicCheckboxModel(
{
id: 'canLogIn',
label: canLogIn,
name: 'canLogIn',
value: (this.epersonInitial != null ? this.epersonInitial.canLogIn : true)
value: (this.epersonInitial != null ? this.epersonInitial.canLogIn : true),
});
this.requireCertificate = new DynamicCheckboxModel(
{
id: 'requireCertificate',
label: requireCertificate,
name: 'requireCertificate',
value: (this.epersonInitial != null ? this.epersonInitial.requireCertificate : false)
value: (this.epersonInitial != null ? this.epersonInitial.requireCertificate : false),
});
this.formModel = [
this.firstName,
@@ -285,9 +313,9 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
this.formGroup = this.formBuilderService.createFormGroup(this.formModel);
this.subs.push(this.epersonService.getActiveEPerson().subscribe((eperson: EPerson) => {
if (eperson != null) {
this.groups = this.groupsDataService.findListByHref(eperson._links.groups.href, {
this.groups$ = this.groupsDataService.findListByHref(eperson._links.groups.href, {
currentPage: 1,
elementsPerPage: this.config.pageSize
elementsPerPage: this.config.pageSize,
});
}
this.formGroup.patchValue({
@@ -295,7 +323,7 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
lastName: eperson != null ? eperson.firstMetadataValue('eperson.lastname') : '',
email: eperson != null ? eperson.email : '',
canLogIn: eperson != null ? eperson.canLogIn : true,
requireCertificate: eperson != null ? eperson.requireCertificate : false
requireCertificate: eperson != null ? eperson.requireCertificate : false,
});
if (eperson === null && !!this.formGroup.controls.email) {
@@ -308,11 +336,11 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
const activeEPerson$ = this.epersonService.getActiveEPerson();
this.groups = activeEPerson$.pipe(
this.groups$ = activeEPerson$.pipe(
switchMap((eperson) => {
return observableCombineLatest([observableOf(eperson), this.paginationService.getFindListOptions(this.config.id, {
currentPage: 1,
elementsPerPage: this.config.pageSize
elementsPerPage: this.config.pageSize,
})]);
}),
switchMap(([eperson, findListOptions]) => {
@@ -320,7 +348,11 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
return this.groupsDataService.findListByHref(eperson._links.groups.href, findListOptions, true, true, followLink('object'));
}
return observableOf(undefined);
})
}),
);
this.groupsPageInfoState$ = this.groups$.pipe(
map(groupsRD => groupsRD.payload.pageInfo),
);
this.canImpersonate$ = activeEPerson$.pipe(
@@ -330,10 +362,10 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
} else {
return observableOf(false);
}
})
}),
);
this.canDelete$ = activeEPerson$.pipe(
switchMap((eperson) => this.authorizationService.isAuthorized(FeatureID.CanDelete, hasValue(eperson) ? eperson.self : undefined))
switchMap((eperson) => this.authorizationService.isAuthorized(FeatureID.CanDelete, hasValue(eperson) ? eperson.self : undefined)),
);
this.canReset$ = observableOf(true);
});
@@ -361,12 +393,12 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
metadata: {
'eperson.firstname': [
{
value: this.firstName.value
}
value: this.firstName.value,
},
],
'eperson.lastname': [
{
value: this.lastName.value
value: this.lastName.value,
},
],
},
@@ -379,7 +411,7 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
} else {
this.editEPerson(ePerson, values);
}
}
},
);
}
@@ -392,7 +424,7 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
const response = this.epersonService.create(ePersonToCreate);
response.pipe(
getFirstCompletedRemoteData()
getFirstCompletedRemoteData(),
).subscribe((rd: RemoteData<EPerson>) => {
if (rd.hasSucceeded) {
this.notificationsService.success(this.translateService.get(this.labelPrefix + 'notification.created.success', { name: this.dsoNameService.getName(ePersonToCreate) }));
@@ -418,12 +450,12 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
metadata: {
'eperson.firstname': [
{
value: (this.firstName.value ? this.firstName.value : ePerson.firstMetadataValue('eperson.firstname'))
}
value: (this.firstName.value ? this.firstName.value : ePerson.firstMetadataValue('eperson.firstname')),
},
],
'eperson.lastname': [
{
value: (this.lastName.value ? this.lastName.value : ePerson.firstMetadataValue('eperson.lastname'))
value: (this.lastName.value ? this.lastName.value : ePerson.firstMetadataValue('eperson.lastname')),
},
],
},
@@ -457,7 +489,7 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
onPageChange(event) {
this.updateGroups({
currentPage: event,
elementsPerPage: this.config.pageSize
elementsPerPage: this.config.pageSize,
});
}
@@ -493,15 +525,15 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
this.canDelete$ = observableOf(false);
return this.epersonService.deleteEPerson(eperson).pipe(
getFirstCompletedRemoteData(),
map((restResponse: RemoteData<NoContent>) => ({ restResponse, eperson }))
map((restResponse: RemoteData<NoContent>) => ({ restResponse, eperson })),
);
} else {
return observableOf(null);
}
}),
finalize(() => this.canDelete$ = observableOf(true))
finalize(() => this.canDelete$ = observableOf(true)),
);
})
}),
).subscribe(({ restResponse, eperson }: { restResponse: RemoteData<NoContent> | null, eperson: EPerson }) => {
if (restResponse?.hasSucceeded) {
this.notificationsService.success(this.translateService.get(this.labelPrefix + 'notification.deleted.success', { name: this.dsoNameService.getName(eperson) }));
@@ -536,7 +568,7 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
this.notificationsService.error(this.translateService.get('forgot-email.form.error.head'),
this.translateService.get('forgot-email.form.error.content', { email: this.epersonInitial.email }));
}
}
},
);
}
}
@@ -562,13 +594,13 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
// Relevant message for email in use
this.subs.push(this.epersonService.searchByScope('email', ePerson.email, {
currentPage: 1,
elementsPerPage: 0
elementsPerPage: 0,
}).pipe(getFirstSucceededRemoteData(), getRemoteDataPayload())
.subscribe((list: PaginatedList<EPerson>) => {
if (list.totalElements > 0) {
this.notificationsService.error(this.translateService.get(this.labelPrefix + 'notification.' + notificationSection + '.failure.emailInUse', {
name: this.dsoNameService.getName(ePerson),
email: ePerson.email
email: ePerson.email,
}));
}
}));
@@ -579,7 +611,7 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
*/
private updateGroups(options) {
this.subs.push(this.epersonService.getActiveEPerson().subscribe((eperson: EPerson) => {
this.groups = this.groupsDataService.findListByHref(eperson._links.groups.href, options);
this.groups$ = this.groupsDataService.findListByHref(eperson._links.groups.href, options);
}));
}
}

View File

@@ -1,9 +1,12 @@
import { AbstractControl, ValidationErrors } from '@angular/forms';
import {
AbstractControl,
ValidationErrors,
} from '@angular/forms';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { EPersonDataService } from '../../../../core/eperson/eperson-data.service';
import { getFirstSucceededRemoteData, } from '../../../../core/shared/operators';
import { getFirstSucceededRemoteData } from '../../../../core/shared/operators';
export class ValidateEmailNotTaken {
@@ -17,8 +20,8 @@ export class ValidateEmailNotTaken {
.pipe(
getFirstSucceededRemoteData(),
map(res => {
return !!res.payload ? { emailTaken: true } : null;
})
return res.payload ? { emailTaken: true } : null;
}),
);
};
}

View File

@@ -1,13 +1,21 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { EPerson } from '../../core/eperson/models/eperson.model';
import { RemoteData } from '../../core/data/remote-data';
import { getFirstCompletedRemoteData } from '../../core/shared/operators';
import { ResolvedAction } from '../../core/resolving/resolver.actions';
import { EPersonDataService } from '../../core/eperson/eperson-data.service';
import {
ActivatedRouteSnapshot,
Resolve,
RouterStateSnapshot,
} from '@angular/router';
import { Store } from '@ngrx/store';
import { followLink, FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
import { Observable } from 'rxjs';
import { RemoteData } from '../../core/data/remote-data';
import { EPersonDataService } from '../../core/eperson/eperson-data.service';
import { EPerson } from '../../core/eperson/models/eperson.model';
import { ResolvedAction } from '../../core/resolving/resolver.actions';
import { getFirstCompletedRemoteData } from '../../core/shared/operators';
import {
followLink,
FollowLinkConfig,
} from '../../shared/utils/follow-link-config.model';
export const EPERSON_EDIT_FOLLOW_LINKS: FollowLinkConfig<EPerson>[] = [
followLink('groups'),

View File

@@ -25,7 +25,7 @@
<ds-alert *ngIf="groupBeingEdited?.permanent" [type]="AlertTypeEnum.Warning"
[content]="messagePrefix + '.alert.permanent'"></ds-alert>
<ds-alert *ngIf="!(canEdit$ | async) && (groupDataService.getActiveGroup() | async)" [type]="AlertTypeEnum.Warning"
<ds-alert *ngIf="(canEdit$ | async) !== true && (groupDataService.getActiveGroup() | async)" [type]="AlertTypeEnum.Warning"
[content]="(messagePrefix + '.alert.workflowGroup' | translate:{ name: dsoNameService.getName((getLinkedDSO(groupBeingEdited) | async)?.payload), comcol: (getLinkedDSO(groupBeingEdited) | async)?.payload?.type, comcolEditRolesRoute: (getLinkedEditRolesRoute(groupBeingEdited) | async) })">
</ds-alert>
@@ -47,10 +47,10 @@
</ds-form>
<div class="mb-5">
<ds-members-list *ngIf="groupBeingEdited != null"
<ds-members-list *ngIf="groupBeingEdited !== undefined"
[messagePrefix]="messagePrefix + '.members-list'"></ds-members-list>
</div>
<ds-subgroups-list *ngIf="groupBeingEdited != null"
<ds-subgroups-list *ngIf="groupBeingEdited !== undefined"
[messagePrefix]="messagePrefix + '.subgroups-list'"></ds-subgroups-list>

View File

@@ -1,43 +1,73 @@
import { CommonModule } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { UntypedFormControl, UntypedFormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
import { BrowserModule, By } from '@angular/platform-browser';
import { ActivatedRoute, Router } from '@angular/router';
import {
ComponentFixture,
TestBed,
waitForAsync,
} from '@angular/core/testing';
import {
FormsModule,
ReactiveFormsModule,
UntypedFormControl,
UntypedFormGroup,
Validators,
} from '@angular/forms';
import {
BrowserModule,
By,
} from '@angular/platform-browser';
import {
ActivatedRoute,
Router,
} from '@angular/router';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { Store } from '@ngrx/store';
import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core';
import { Observable, of as observableOf } from 'rxjs';
import {
TranslateLoader,
TranslateModule,
TranslateService,
} from '@ngx-translate/core';
import { Operation } from 'fast-json-patch';
import {
Observable,
of as observableOf,
} from 'rxjs';
import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
import { RemoteDataBuildService } from '../../../core/cache/builders/remote-data-build.service';
import { ObjectCacheService } from '../../../core/cache/object-cache.service';
import { DSOChangeAnalyzer } from '../../../core/data/dso-change-analyzer.service';
import { DSpaceObjectDataService } from '../../../core/data/dspace-object-data.service';
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
import { buildPaginatedList, PaginatedList } from '../../../core/data/paginated-list.model';
import {
buildPaginatedList,
PaginatedList,
} from '../../../core/data/paginated-list.model';
import { RemoteData } from '../../../core/data/remote-data';
import { EPersonDataService } from '../../../core/eperson/eperson-data.service';
import { GroupDataService } from '../../../core/eperson/group-data.service';
import { Group } from '../../../core/eperson/models/group.model';
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
import { HALEndpointService } from '../../../core/shared/hal-endpoint.service';
import { NoContent } from '../../../core/shared/NoContent.model';
import { PageInfo } from '../../../core/shared/page-info.model';
import { UUIDService } from '../../../core/shared/uuid.service';
import { FormBuilderService } from '../../../shared/form/builder/form-builder.service';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { GroupMock, GroupMock2 } from '../../../shared/testing/group-mock';
import { GroupFormComponent } from './group-form.component';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
import { getMockFormBuilderService } from '../../../shared/mocks/form-builder-service.mock';
import { getMockTranslateService } from '../../../shared/mocks/translate.service.mock';
import { TranslateLoaderMock } from '../../../shared/testing/translate-loader.mock';
import { RouterMock } from '../../../shared/mocks/router.mock';
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub';
import { Operation } from 'fast-json-patch';
import { ValidateGroupExists } from './validators/group-exists.validator';
import { NoContent } from '../../../core/shared/NoContent.model';
import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
import { DSONameServiceMock } from '../../../shared/mocks/dso-name.service.mock';
import { getMockFormBuilderService } from '../../../shared/mocks/form-builder-service.mock';
import { RouterMock } from '../../../shared/mocks/router.mock';
import { getMockTranslateService } from '../../../shared/mocks/translate.service.mock';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
import {
GroupMock,
GroupMock2,
} from '../../../shared/testing/group-mock';
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub';
import { TranslateLoaderMock } from '../../../shared/testing/translate-loader.mock';
import { GroupFormComponent } from './group-form.component';
import { ValidateGroupExists } from './validators/group-exists.validator';
describe('GroupFormComponent', () => {
let component: GroupFormComponent;
@@ -65,8 +95,8 @@ describe('GroupFormComponent', () => {
metadata: {
'dc.description': [
{
value: groupDescription
}
value: groupDescription,
},
],
},
});
@@ -105,7 +135,7 @@ describe('GroupFormComponent', () => {
create(group: Group): Observable<RemoteData<Group>> {
this.allGroups = [...this.allGroups, group];
this.createdGroup = Object.assign({}, group, {
_links: { self: { href: 'group-selflink' } }
_links: { self: { href: 'group-selflink' } },
});
return createSuccessfulRemoteDataObject$(this.createdGroup);
},
@@ -114,15 +144,15 @@ describe('GroupFormComponent', () => {
},
getGroupEditPageRouterLinkWithID(id: string) {
return `group-edit-page-for-${id}`;
}
},
};
authorizationService = jasmine.createSpyObj('authorizationService', {
isAuthorized: observableOf(true)
isAuthorized: observableOf(true),
});
dsoDataServiceStub = {
findByHref(href: string): Observable<RemoteData<DSpaceObject>> {
return null;
}
},
};
builderService = Object.assign(getMockFormBuilderService(),{
createFormGroup(formModel, options = null) {
@@ -185,7 +215,7 @@ describe('GroupFormComponent', () => {
},
isObject(value) {
return typeof value === 'object' && value !== null;
}
},
});
translateService = getMockTranslateService();
router = new RouterMock();
@@ -195,8 +225,8 @@ describe('GroupFormComponent', () => {
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: TranslateLoaderMock
}
useClass: TranslateLoaderMock,
},
}),
],
declarations: [GroupFormComponent],
@@ -216,12 +246,12 @@ describe('GroupFormComponent', () => {
{ provide: HALEndpointService, useValue: {} },
{
provide: ActivatedRoute,
useValue: { data: observableOf({ dso: { payload: {} } }), params: observableOf({}) }
useValue: { data: observableOf({ dso: { payload: {} } }), params: observableOf({}) },
},
{ provide: Router, useValue: router },
{ provide: AuthorizationDataService, useValue: authorizationService },
],
schemas: [NO_ERRORS_SCHEMA]
schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
}));
@@ -257,8 +287,8 @@ describe('GroupFormComponent', () => {
metadata: {
'dc.description': [
{
value: groupDescription
}
value: groupDescription,
},
],
},
});
@@ -273,11 +303,11 @@ describe('GroupFormComponent', () => {
const operations = [{
op: 'add',
path: '/metadata/dc.description',
value: 'testDescription'
value: 'testDescription',
}, {
op: 'replace',
path: '/name',
value: 'newGroupName'
value: 'newGroupName',
}];
expect(groupsDataServiceStub.patch).toHaveBeenCalledWith(expected, operations);
});
@@ -289,7 +319,7 @@ describe('GroupFormComponent', () => {
const operations = [{
op: 'add',
path: '/metadata/dc.description',
value: 'testDescription'
value: 'testDescription',
}];
expect(groupsDataServiceStub.patch).toHaveBeenCalledWith(expected, operations);
});
@@ -301,7 +331,7 @@ describe('GroupFormComponent', () => {
const operations = [{
op: 'replace',
path: '/name',
value: 'newGroupName'
value: 'newGroupName',
}];
expect(groupsDataServiceStub.patch).toHaveBeenCalledWith(expected, operations);
});
@@ -338,8 +368,8 @@ describe('GroupFormComponent', () => {
metadata: {
'dc.description': [
{
value: groupDescription
}
value: groupDescription,
},
],
},
});
@@ -376,7 +406,7 @@ describe('GroupFormComponent', () => {
const groupsDataServiceStubWithGroup = Object.assign(groupsDataServiceStub,{
searchGroups(query: string): Observable<RemoteData<PaginatedList<Group>>> {
return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), [expected]));
}
},
});
component.formGroup.controls.groupName.setValue('testName');
component.formGroup.controls.groupName.setAsyncValidators(ValidateGroupExists.createValidator(groupsDataServiceStubWithGroup));
@@ -400,7 +430,7 @@ describe('GroupFormComponent', () => {
component.canEdit$ = observableOf(true);
component.groupBeingEdited = {
permanent: false
permanent: false,
} as Group;
fixture.detectChanges();

View File

@@ -1,23 +1,45 @@
import { Component, EventEmitter, HostListener, OnDestroy, OnInit, Output, ChangeDetectorRef } from '@angular/core';
import {
ChangeDetectorRef,
Component,
EventEmitter,
HostListener,
OnDestroy,
OnInit,
Output,
} from '@angular/core';
import { UntypedFormGroup } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import {
ActivatedRoute,
Router,
} from '@angular/router';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import {
DynamicFormControlModel,
DynamicFormLayout,
DynamicInputModel,
DynamicTextAreaModel
DynamicTextAreaModel,
} from '@ng-dynamic-forms/core';
import { TranslateService } from '@ngx-translate/core';
import { Operation } from 'fast-json-patch';
import {
combineLatest as observableCombineLatest,
Observable,
of as observableOf,
Subscription,
} from 'rxjs';
import { catchError, map, switchMap, take, filter, debounceTime } from 'rxjs/operators';
import {
catchError,
debounceTime,
filter,
map,
switchMap,
take,
} from 'rxjs/operators';
import { environment } from '../../../../environments/environment';
import { getCollectionEditRolesRoute } from '../../../collection-page/collection-page-routing-paths';
import { getCommunityEditRolesRoute } from '../../../community-page/community-page-routing-paths';
import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
import { DSpaceObjectDataService } from '../../../core/data/dspace-object-data.service';
import { AuthorizationDataService } from '../../../core/data/feature-authorization/authorization-data.service';
import { FeatureID } from '../../../core/data/feature-authorization/feature-id';
@@ -30,28 +52,32 @@ import { Group } from '../../../core/eperson/models/group.model';
import { Collection } from '../../../core/shared/collection.model';
import { Community } from '../../../core/shared/community.model';
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
import { NoContent } from '../../../core/shared/NoContent.model';
import {
getRemoteDataPayload,
getFirstSucceededRemoteData,
getFirstCompletedRemoteData,
getFirstSucceededRemoteDataPayload
getFirstSucceededRemoteData,
getFirstSucceededRemoteDataPayload,
getRemoteDataPayload,
} from '../../../core/shared/operators';
import { AlertType } from '../../../shared/alert/alert-type';
import { ConfirmationModalComponent } from '../../../shared/confirmation-modal/confirmation-modal.component';
import { hasValue, isNotEmpty, hasValueOperator } from '../../../shared/empty.util';
import {
hasValue,
hasValueOperator,
isNotEmpty,
} from '../../../shared/empty.util';
import { FormBuilderService } from '../../../shared/form/builder/form-builder.service';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { followLink } from '../../../shared/utils/follow-link-config.model';
import { NoContent } from '../../../core/shared/NoContent.model';
import { Operation } from 'fast-json-patch';
import {
getGroupEditRoute,
getGroupsRoute,
} from '../../access-control-routing-paths';
import { ValidateGroupExists } from './validators/group-exists.validator';
import { DSONameService } from '../../../core/breadcrumbs/dso-name.service';
import { environment } from '../../../../environments/environment';
import { getGroupEditRoute, getGroupsRoute } from '../../access-control-routing-paths';
@Component({
selector: 'ds-group-form',
templateUrl: './group-form.component.html'
templateUrl: './group-form.component.html',
})
/**
* A form used for creating and editing groups
@@ -83,13 +109,13 @@ export class GroupFormComponent implements OnInit, OnDestroy {
formLayout: DynamicFormLayout = {
groupName: {
grid: {
host: 'row'
}
host: 'row',
},
},
groupDescription: {
grid: {
host: 'row'
}
host: 'row',
},
},
};
@@ -176,7 +202,7 @@ export class GroupFormComponent implements OnInit, OnDestroy {
observableCombineLatest([
this.translateService.get(`${this.messagePrefix}.groupName`),
this.translateService.get(`${this.messagePrefix}.groupCommunity`),
this.translateService.get(`${this.messagePrefix}.groupDescription`)
this.translateService.get(`${this.messagePrefix}.groupDescription`),
]).subscribe(([groupName, groupCommunity, groupDescription]) => {
this.groupName = new DynamicInputModel({
id: 'groupName',
@@ -207,7 +233,7 @@ export class GroupFormComponent implements OnInit, OnDestroy {
];
this.formGroup = this.formBuilderService.createFormGroup(this.formModel);
if (!!this.formGroup.controls.groupName) {
if (this.formGroup.controls.groupName) {
this.formGroup.controls.groupName.setAsyncValidators(ValidateGroupExists.createValidator(this.groupDataService));
this.groupNameValueChangeSubscribe = this.groupName.valueChanges.pipe(debounceTime(300)).subscribe(() => {
this.changeDetectorRef.detectChanges();
@@ -219,7 +245,7 @@ export class GroupFormComponent implements OnInit, OnDestroy {
this.groupDataService.getActiveGroup(),
this.canEdit$,
this.groupDataService.getActiveGroup()
.pipe(filter((activeGroup) => hasValue(activeGroup)),switchMap((activeGroup) => this.getLinkedDSO(activeGroup).pipe(getFirstSucceededRemoteDataPayload())))
.pipe(filter((activeGroup) => hasValue(activeGroup)),switchMap((activeGroup) => this.getLinkedDSO(activeGroup).pipe(getFirstSucceededRemoteDataPayload()))),
]).subscribe(([activeGroup, canEdit, linkedObject]) => {
if (activeGroup != null) {
@@ -254,7 +280,7 @@ export class GroupFormComponent implements OnInit, OnDestroy {
}
}, 200);
}
})
}),
);
});
}
@@ -282,9 +308,9 @@ export class GroupFormComponent implements OnInit, OnDestroy {
metadata: {
'dc.description': [
{
value: this.groupDescription.value
}
]
value: this.groupDescription.value,
},
],
},
};
if (group === null) {
@@ -292,7 +318,7 @@ export class GroupFormComponent implements OnInit, OnDestroy {
} else {
this.editGroup(group);
}
}
},
);
}
@@ -303,7 +329,7 @@ export class GroupFormComponent implements OnInit, OnDestroy {
createNewGroup(values) {
const groupToCreate = Object.assign(new Group(), values);
this.groupDataService.create(groupToCreate).pipe(
getFirstCompletedRemoteData()
getFirstCompletedRemoteData(),
).subscribe((rd: RemoteData<Group>) => {
if (rd.hasSucceeded) {
this.notificationsService.success(this.translateService.get(this.messagePrefix + '.notification.created.success', { name: groupToCreate.name }));
@@ -332,7 +358,7 @@ export class GroupFormComponent implements OnInit, OnDestroy {
// Relevant message for group name in use
this.subs.push(this.groupDataService.searchGroups(group.name, {
currentPage: 1,
elementsPerPage: 0
elementsPerPage: 0,
}).pipe(getFirstSucceededRemoteData(), getRemoteDataPayload())
.subscribe((list: PaginatedList<Group>) => {
if (list.totalElements > 0) {
@@ -354,7 +380,7 @@ export class GroupFormComponent implements OnInit, OnDestroy {
operations = [...operations, {
op: 'add',
path: '/metadata/dc.description',
value: this.groupDescription.value
value: this.groupDescription.value,
}];
}
@@ -362,12 +388,12 @@ export class GroupFormComponent implements OnInit, OnDestroy {
operations = [...operations, {
op: 'replace',
path: '/name',
value: this.groupName.value
value: this.groupName.value,
}];
}
this.groupDataService.patch(group, operations).pipe(
getFirstCompletedRemoteData()
getFirstCompletedRemoteData(),
).subscribe((rd: RemoteData<Group>) => {
if (rd.hasSucceeded) {
this.notificationsService.success(this.translateService.get(this.messagePrefix + '.notification.edited.success', { name: this.dsoNameService.getName(rd.payload) }));
@@ -506,7 +532,7 @@ export class GroupFormComponent implements OnInit, OnDestroy {
return getCollectionEditRolesRoute(rd.payload.id);
}
}
})
}),
);
}
}

View File

@@ -49,7 +49,7 @@
</ds-pagination>
<div *ngIf="(ePeopleMembersOfGroup | async) == undefined || (ePeopleMembersOfGroup | async)?.totalElements == 0" class="alert alert-info w-100 mb-2"
<div *ngIf="(ePeopleMembersOfGroup | async) === undefined || (ePeopleMembersOfGroup | async)?.totalElements === 0" class="alert alert-info w-100 mb-2"
role="alert">
{{messagePrefix + '.no-members-yet' | translate}}
</div>
@@ -130,7 +130,7 @@
</ds-pagination>
<div *ngIf="(ePeopleSearch | async)?.totalElements == 0 && searchDone"
<div *ngIf="(ePeopleSearch | async)?.totalElements === 0 && searchDone"
class="alert alert-info w-100 mb-2"
role="alert">
{{messagePrefix + '.no-items' | translate}}

View File

@@ -1,35 +1,68 @@
import { CommonModule } from '@angular/common';
import { DebugElement, NO_ERRORS_SCHEMA } from '@angular/core';
import { ComponentFixture, fakeAsync, flush, inject, TestBed, tick, waitForAsync } from '@angular/core/testing';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { BrowserModule, By } from '@angular/platform-browser';
import {
DebugElement,
NO_ERRORS_SCHEMA,
} from '@angular/core';
import {
ComponentFixture,
fakeAsync,
flush,
inject,
TestBed,
tick,
waitForAsync,
} from '@angular/core/testing';
import {
FormsModule,
ReactiveFormsModule,
} from '@angular/forms';
import {
BrowserModule,
By,
} from '@angular/platform-browser';
import { Router } from '@angular/router';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core';
import { Observable, of as observableOf } from 'rxjs';
import {
TranslateLoader,
TranslateModule,
TranslateService,
} from '@ngx-translate/core';
import {
Observable,
of as observableOf,
} from 'rxjs';
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
import { RestResponse } from '../../../../core/cache/response.models';
import { buildPaginatedList, PaginatedList } from '../../../../core/data/paginated-list.model';
import {
buildPaginatedList,
PaginatedList,
} from '../../../../core/data/paginated-list.model';
import { RemoteData } from '../../../../core/data/remote-data';
import { EPersonDataService } from '../../../../core/eperson/eperson-data.service';
import { GroupDataService } from '../../../../core/eperson/group-data.service';
import { EPerson } from '../../../../core/eperson/models/eperson.model';
import { Group } from '../../../../core/eperson/models/group.model';
import { PaginationService } from '../../../../core/pagination/pagination.service';
import { PageInfo } from '../../../../core/shared/page-info.model';
import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service';
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
import { GroupMock } from '../../../../shared/testing/group-mock';
import { MembersListComponent } from './members-list.component';
import { EPersonMock, EPersonMock2 } from '../../../../shared/testing/eperson.mock';
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/remote-data.utils';
import { getMockTranslateService } from '../../../../shared/mocks/translate.service.mock';
import { getMockFormBuilderService } from '../../../../shared/mocks/form-builder-service.mock';
import { TranslateLoaderMock } from '../../../../shared/testing/translate-loader.mock';
import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service.stub';
import { RouterMock } from '../../../../shared/mocks/router.mock';
import { PaginationService } from '../../../../core/pagination/pagination.service';
import { PaginationServiceStub } from '../../../../shared/testing/pagination-service.stub';
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
import { DSONameServiceMock } from '../../../../shared/mocks/dso-name.service.mock';
import { getMockFormBuilderService } from '../../../../shared/mocks/form-builder-service.mock';
import { RouterMock } from '../../../../shared/mocks/router.mock';
import { getMockTranslateService } from '../../../../shared/mocks/translate.service.mock';
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/remote-data.utils';
import {
EPersonMock,
EPersonMock2,
} from '../../../../shared/testing/eperson.mock';
import { GroupMock } from '../../../../shared/testing/group-mock';
import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service.stub';
import { PaginationServiceStub } from '../../../../shared/testing/pagination-service.stub';
import { TranslateLoaderMock } from '../../../../shared/testing/translate-loader.mock';
import { MembersListComponent } from './members-list.component';
// todo: optimize imports
describe('MembersListComponent', () => {
let component: MembersListComponent;
@@ -109,7 +142,7 @@ describe('MembersListComponent', () => {
// Add eperson to list of non-members
this.epersonNonMembers = [...this.epersonNonMembers, epersonToDelete];
return observableOf(new RestResponse(true, 200, 'Success'));
}
},
};
builderService = getMockFormBuilderService();
translateService = getMockTranslateService();
@@ -120,8 +153,8 @@ describe('MembersListComponent', () => {
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: TranslateLoaderMock
}
useClass: TranslateLoaderMock,
},
}),
],
declarations: [MembersListComponent],
@@ -134,7 +167,7 @@ describe('MembersListComponent', () => {
{ provide: PaginationService, useValue: paginationService },
{ provide: DSONameService, useValue: new DSONameServiceMock() },
],
schemas: [NO_ERRORS_SCHEMA]
schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
}));

View File

@@ -1,30 +1,42 @@
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import {
Component,
Input,
OnDestroy,
OnInit,
} from '@angular/core';
import { UntypedFormBuilder } from '@angular/forms';
import { Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import {
BehaviorSubject,
Observable,
Subscription,
BehaviorSubject
} from 'rxjs';
import { map, switchMap, take } from 'rxjs/operators';
import {
map,
switchMap,
take,
} from 'rxjs/operators';
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
import { PaginatedList } from '../../../../core/data/paginated-list.model';
import { RemoteData } from '../../../../core/data/remote-data';
import { EPersonDataService } from '../../../../core/eperson/eperson-data.service';
import { GroupDataService } from '../../../../core/eperson/group-data.service';
import { EPerson } from '../../../../core/eperson/models/eperson.model';
import { Group } from '../../../../core/eperson/models/group.model';
import { PaginationService } from '../../../../core/pagination/pagination.service';
import {
getFirstCompletedRemoteData,
getAllCompletedRemoteData,
getRemoteDataPayload
getFirstCompletedRemoteData,
getRemoteDataPayload,
} from '../../../../core/shared/operators';
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
import { PaginationComponentOptions } from '../../../../shared/pagination/pagination-component-options.model';
import { PaginationService } from '../../../../core/pagination/pagination.service';
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
import { getEPersonEditRoute } from '../../../access-control-routing-paths';
// todo: optimize imports
/**
* Keys to keep track of specific subscriptions
*/
@@ -65,7 +77,7 @@ export interface EPersonListActionConfig {
@Component({
selector: 'ds-members-list',
templateUrl: './members-list.component.html'
templateUrl: './members-list.component.html',
})
/**
* The list of members in the edit group page
@@ -85,7 +97,7 @@ export class MembersListComponent implements OnInit, OnDestroy {
remove: {
css: 'btn-outline-danger',
disabled: false,
icon: 'fas fa-trash-alt fa-fw'
icon: 'fas fa-trash-alt fa-fw',
},
};
@@ -104,7 +116,7 @@ export class MembersListComponent implements OnInit, OnDestroy {
configSearch: PaginationComponentOptions = Object.assign(new PaginationComponentOptions(), {
id: 'sml',
pageSize: 5,
currentPage: 1
currentPage: 1,
});
/**
* Pagination config used to display the list of EPerson Membes of active group being edited
@@ -112,7 +124,7 @@ export class MembersListComponent implements OnInit, OnDestroy {
config: PaginationComponentOptions = Object.assign(new PaginationComponentOptions(), {
id: 'ml',
pageSize: 5,
currentPage: 1
currentPage: 1,
});
/**
@@ -173,8 +185,8 @@ export class MembersListComponent implements OnInit, OnDestroy {
switchMap((currentPagination) => {
return this.ePersonDataService.findListByHref(this.groupBeingEdited._links.epersons.href, {
currentPage: currentPagination.currentPage,
elementsPerPage: currentPagination.pageSize
}
elementsPerPage: currentPagination.pageSize,
},
);
}),
getAllCompletedRemoteData(),
@@ -263,7 +275,7 @@ export class MembersListComponent implements OnInit, OnDestroy {
return this.ePersonDataService.searchNonMembers(this.currentSearchQuery, this.groupBeingEdited.id, {
currentPage: paginationOptions.currentPage,
elementsPerPage: paginationOptions.pageSize
elementsPerPage: paginationOptions.pageSize,
}, false, true);
}),
getAllCompletedRemoteData(),

View File

@@ -45,7 +45,7 @@
</div>
</ds-pagination>
<div *ngIf="(subGroups$ | async)?.payload?.totalElements == 0" class="alert alert-info w-100 mb-2"
<div *ngIf="(subGroups$ | async)?.payload?.totalElements === 0" class="alert alert-info w-100 mb-2"
role="alert">
{{messagePrefix + '.no-subgroups-yet' | translate}}
</div>
@@ -124,7 +124,7 @@
</div>
</ds-pagination>
<div *ngIf="(searchResults$ | async)?.payload?.totalElements == 0 && searchDone" class="alert alert-info w-100 mb-2"
<div *ngIf="(searchResults$ | async)?.payload?.totalElements === 0 && searchDone" class="alert alert-info w-100 mb-2"
role="alert">
{{messagePrefix + '.no-items' | translate}}
</div>

View File

@@ -1,35 +1,63 @@
import { CommonModule } from '@angular/common';
import { NO_ERRORS_SCHEMA, DebugElement } from '@angular/core';
import { ComponentFixture, fakeAsync, flush, inject, TestBed, waitForAsync } from '@angular/core/testing';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { BrowserModule, By } from '@angular/platform-browser';
import {
DebugElement,
NO_ERRORS_SCHEMA,
} from '@angular/core';
import {
ComponentFixture,
fakeAsync,
flush,
inject,
TestBed,
waitForAsync,
} from '@angular/core/testing';
import {
FormsModule,
ReactiveFormsModule,
} from '@angular/forms';
import {
BrowserModule,
By,
} from '@angular/platform-browser';
import { Router } from '@angular/router';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core';
import { Observable, of as observableOf } from 'rxjs';
import {
TranslateLoader,
TranslateModule,
TranslateService,
} from '@ngx-translate/core';
import {
Observable,
of as observableOf,
} from 'rxjs';
import { EPersonMock2 } from 'src/app/shared/testing/eperson.mock';
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
import { RestResponse } from '../../../../core/cache/response.models';
import { buildPaginatedList, PaginatedList } from '../../../../core/data/paginated-list.model';
import {
buildPaginatedList,
PaginatedList,
} from '../../../../core/data/paginated-list.model';
import { RemoteData } from '../../../../core/data/remote-data';
import { GroupDataService } from '../../../../core/eperson/group-data.service';
import { Group } from '../../../../core/eperson/models/group.model';
import { PaginationService } from '../../../../core/pagination/pagination.service';
import { PageInfo } from '../../../../core/shared/page-info.model';
import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service';
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
import { GroupMock, GroupMock2 } from '../../../../shared/testing/group-mock';
import { SubgroupsListComponent } from './subgroups-list.component';
import {
createSuccessfulRemoteDataObject$
} from '../../../../shared/remote-data.utils';
import { RouterMock } from '../../../../shared/mocks/router.mock';
import { getMockFormBuilderService } from '../../../../shared/mocks/form-builder-service.mock';
import { getMockTranslateService } from '../../../../shared/mocks/translate.service.mock';
import { TranslateLoaderMock } from '../../../../shared/testing/translate-loader.mock';
import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service.stub';
import { PaginationService } from '../../../../core/pagination/pagination.service';
import { PaginationServiceStub } from '../../../../shared/testing/pagination-service.stub';
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
import { DSONameServiceMock } from '../../../../shared/mocks/dso-name.service.mock';
import { EPersonMock2 } from 'src/app/shared/testing/eperson.mock';
import { getMockFormBuilderService } from '../../../../shared/mocks/form-builder-service.mock';
import { RouterMock } from '../../../../shared/mocks/router.mock';
import { getMockTranslateService } from '../../../../shared/mocks/translate.service.mock';
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/remote-data.utils';
import {
GroupMock,
GroupMock2,
} from '../../../../shared/testing/group-mock';
import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service.stub';
import { PaginationServiceStub } from '../../../../shared/testing/pagination-service.stub';
import { TranslateLoaderMock } from '../../../../shared/testing/translate-loader.mock';
import { SubgroupsListComponent } from './subgroups-list.component';
describe('SubgroupsListComponent', () => {
let component: SubgroupsListComponent;
@@ -56,7 +84,7 @@ describe('SubgroupsListComponent', () => {
},
subgroups: { href: 'https://rest.api/server/api/eperson/groups/activegroupid/subgroups' },
object: { href: 'https://rest.api/server/api/eperson/groups/activegroupid/object' },
epersons: { href: 'https://rest.api/server/api/eperson/groups/activegroupid/epersons' }
epersons: { href: 'https://rest.api/server/api/eperson/groups/activegroupid/epersons' },
},
_name: 'activegroupname',
id: 'activegroupid',
@@ -120,7 +148,7 @@ describe('SubgroupsListComponent', () => {
// Add group to list of non-members
this.groupNonMembers = [...this.groupNonMembers, subgroupToDelete];
return observableOf(new RestResponse(true, 200, 'Success'));
}
},
};
routerStub = new RouterMock();
builderService = getMockFormBuilderService();
@@ -132,8 +160,8 @@ describe('SubgroupsListComponent', () => {
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: TranslateLoaderMock
}
useClass: TranslateLoaderMock,
},
}),
],
declarations: [SubgroupsListComponent],
@@ -145,7 +173,7 @@ describe('SubgroupsListComponent', () => {
{ provide: Router, useValue: routerStub },
{ provide: PaginationService, useValue: paginationService },
],
schemas: [NO_ERRORS_SCHEMA]
schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
}));

View File

@@ -1,23 +1,38 @@
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import {
Component,
Input,
OnDestroy,
OnInit,
} from '@angular/core';
import { UntypedFormBuilder } from '@angular/forms';
import { Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { BehaviorSubject, Observable, Subscription } from 'rxjs';
import { map, switchMap, take } from 'rxjs/operators';
import {
BehaviorSubject,
Observable,
Subscription,
} from 'rxjs';
import {
map,
switchMap,
take,
} from 'rxjs/operators';
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
import { PaginatedList } from '../../../../core/data/paginated-list.model';
import { RemoteData } from '../../../../core/data/remote-data';
import { GroupDataService } from '../../../../core/eperson/group-data.service';
import { Group } from '../../../../core/eperson/models/group.model';
import { PaginationService } from '../../../../core/pagination/pagination.service';
import { NoContent } from '../../../../core/shared/NoContent.model';
import {
getAllCompletedRemoteData,
getFirstCompletedRemoteData
getFirstCompletedRemoteData,
} from '../../../../core/shared/operators';
import { PageInfo } from '../../../../core/shared/page-info.model';
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
import { PaginationComponentOptions } from '../../../../shared/pagination/pagination-component-options.model';
import { NoContent } from '../../../../core/shared/NoContent.model';
import { PaginationService } from '../../../../core/pagination/pagination.service';
import { followLink } from '../../../../shared/utils/follow-link-config.model';
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
/**
* Keys to keep track of specific subscriptions
@@ -30,7 +45,7 @@ enum SubKey {
@Component({
selector: 'ds-subgroups-list',
templateUrl: './subgroups-list.component.html'
templateUrl: './subgroups-list.component.html',
})
/**
* The list of subgroups in the edit group page
@@ -49,6 +64,8 @@ export class SubgroupsListComponent implements OnInit, OnDestroy {
*/
subGroups$: BehaviorSubject<RemoteData<PaginatedList<Group>>> = new BehaviorSubject(undefined);
subGroupsPageInfoState$: Observable<PageInfo>;
/**
* Map of active subscriptions
*/
@@ -60,7 +77,7 @@ export class SubgroupsListComponent implements OnInit, OnDestroy {
configSearch: PaginationComponentOptions = Object.assign(new PaginationComponentOptions(), {
id: 'ssgl',
pageSize: 5,
currentPage: 1
currentPage: 1,
});
/**
* Pagination config used to display the list of subgroups of currently active group being edited
@@ -68,7 +85,7 @@ export class SubgroupsListComponent implements OnInit, OnDestroy {
config: PaginationComponentOptions = Object.assign(new PaginationComponentOptions(), {
id: 'sgl',
pageSize: 5,
currentPage: 1
currentPage: 1,
});
// The search form
@@ -105,6 +122,9 @@ export class SubgroupsListComponent implements OnInit, OnDestroy {
this.search({ query: '' });
}
}));
this.subGroupsPageInfoState$ = this.subGroups$.pipe(
map(subGroupsRD => subGroupsRD?.payload?.pageInfo),
);
}
/**
@@ -120,12 +140,12 @@ export class SubgroupsListComponent implements OnInit, OnDestroy {
this.paginationService.getCurrentPagination(this.config.id, this.config).pipe(
switchMap((config) => this.groupDataService.findListByHref(this.groupBeingEdited._links.subgroups.href, {
currentPage: config.currentPage,
elementsPerPage: config.pageSize
elementsPerPage: config.pageSize,
},
true,
true,
followLink('object')
))
followLink('object'),
)),
).subscribe((rd: RemoteData<PaginatedList<Group>>) => {
this.subGroups$.next(rd);
}));
@@ -194,7 +214,7 @@ export class SubgroupsListComponent implements OnInit, OnDestroy {
return this.groupDataService.searchNonMemberGroups(this.currentSearchQuery, this.groupBeingEdited.id, {
currentPage: paginationOptions.currentPage,
elementsPerPage: paginationOptions.pageSize
elementsPerPage: paginationOptions.pageSize,
}, false, true, followLink('object'));
}),
getAllCompletedRemoteData(),

View File

@@ -1,10 +1,13 @@
import { AbstractControl, ValidationErrors } from '@angular/forms';
import {
AbstractControl,
ValidationErrors,
} from '@angular/forms';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { GroupDataService } from '../../../../core/eperson/group-data.service';
import { getFirstSucceededRemoteListPayload } from '../../../../core/shared/operators';
import { Group } from '../../../../core/eperson/models/group.model';
import { getFirstSucceededRemoteListPayload } from '../../../../core/shared/operators';
export class ValidateGroupExists {
@@ -17,7 +20,7 @@ export class ValidateGroupExists {
return (control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> => {
return groupDataService.searchGroups(control.value, {
currentPage: 1,
elementsPerPage: 100
elementsPerPage: 100,
})
.pipe(
getFirstSucceededRemoteListPayload(),

View File

@@ -1,10 +1,14 @@
import { GroupPageGuard } from './group-page.guard';
import { HALEndpointService } from '../../core/shared/hal-endpoint.service';
import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
import { ActivatedRouteSnapshot, Router } from '@angular/router';
import {
ActivatedRouteSnapshot,
Router,
} from '@angular/router';
import { of as observableOf } from 'rxjs';
import { AuthService } from '../../core/auth/auth.service';
import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
import { FeatureID } from '../../core/data/feature-authorization/feature-id';
import { HALEndpointService } from '../../core/shared/hal-endpoint.service';
import { GroupPageGuard } from './group-page.guard';
describe('GroupPageGuard', () => {
const groupsEndpointUrl = 'https://test.org/api/eperson/groups';
@@ -13,7 +17,7 @@ describe('GroupPageGuard', () => {
const routeSnapshotWithGroupId = {
params: {
groupId: groupUuid,
}
},
} as unknown as ActivatedRouteSnapshot;
let guard: GroupPageGuard;
@@ -50,10 +54,10 @@ describe('GroupPageGuard', () => {
it('should return true', (done) => {
guard.canActivate(
routeSnapshotWithGroupId, { url: 'current-url'} as any
routeSnapshotWithGroupId, { url: 'current-url' } as any,
).subscribe((result) => {
expect(authorizationService.isAuthorized).toHaveBeenCalledWith(
FeatureID.CanManageGroup, groupEndpointUrl, undefined
FeatureID.CanManageGroup, groupEndpointUrl, undefined,
);
expect(result).toBeTrue();
done();
@@ -68,10 +72,10 @@ describe('GroupPageGuard', () => {
it('should not return true', (done) => {
guard.canActivate(
routeSnapshotWithGroupId, { url: 'current-url'} as any
routeSnapshotWithGroupId, { url: 'current-url' } as any,
).subscribe((result) => {
expect(authorizationService.isAuthorized).toHaveBeenCalledWith(
FeatureID.CanManageGroup, groupEndpointUrl, undefined
FeatureID.CanManageGroup, groupEndpointUrl, undefined,
);
expect(result).not.toBeTrue();
done();

View File

@@ -1,15 +1,23 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router';
import { Observable, of as observableOf } from 'rxjs';
import { FeatureID } from '../../core/data/feature-authorization/feature-id';
import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
import { AuthService } from '../../core/auth/auth.service';
import { SomeFeatureAuthorizationGuard } from '../../core/data/feature-authorization/feature-authorization-guard/some-feature-authorization.guard';
import { HALEndpointService } from '../../core/shared/hal-endpoint.service';
import {
ActivatedRouteSnapshot,
Router,
RouterStateSnapshot,
} from '@angular/router';
import {
Observable,
of as observableOf,
} from 'rxjs';
import { map } from 'rxjs/operators';
import { AuthService } from '../../core/auth/auth.service';
import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
import { SomeFeatureAuthorizationGuard } from '../../core/data/feature-authorization/feature-authorization-guard/some-feature-authorization.guard';
import { FeatureID } from '../../core/data/feature-authorization/feature-id';
import { HALEndpointService } from '../../core/shared/hal-endpoint.service';
@Injectable({
providedIn: 'root'
providedIn: 'root',
})
export class GroupPageGuard extends SomeFeatureAuthorizationGuard {
@@ -28,7 +36,7 @@ export class GroupPageGuard extends SomeFeatureAuthorizationGuard {
getObjectUrl(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<string> {
return this.halEndpointService.getEndpoint(this.groupsEndpoint).pipe(
map(groupsUrl => `${groupsUrl}/${route?.params?.groupId}`)
map(groupsUrl => `${groupsUrl}/${route?.params?.groupId}`),
);
}

View File

@@ -1,5 +1,6 @@
/* eslint-disable max-classes-per-file */
import { Action } from '@ngrx/store';
import { Group } from '../../core/eperson/models/group.model';
import { type } from '../../shared/ngrx/type';

View File

@@ -1,6 +1,12 @@
import { GroupMock } from '../../shared/testing/group-mock';
import { GroupRegistryCancelGroupAction, GroupRegistryEditGroupAction } from './group-registry.actions';
import { groupRegistryReducer, GroupRegistryState } from './group-registry.reducers';
import {
GroupRegistryCancelGroupAction,
GroupRegistryEditGroupAction,
} from './group-registry.actions';
import {
groupRegistryReducer,
GroupRegistryState,
} from './group-registry.reducers';
const initialState: GroupRegistryState = {
editGroup: null,

View File

@@ -1,5 +1,9 @@
import { Group } from '../../core/eperson/models/group.model';
import { GroupRegistryAction, GroupRegistryActionTypes, GroupRegistryEditGroupAction } from './group-registry.actions';
import {
GroupRegistryAction,
GroupRegistryActionTypes,
GroupRegistryEditGroupAction,
} from './group-registry.actions';
/**
* The metadata registry state.
@@ -27,13 +31,13 @@ export function groupRegistryReducer(state = initialState, action: GroupRegistry
case GroupRegistryActionTypes.EDIT_GROUP: {
return Object.assign({}, state, {
editGroup: (action as GroupRegistryEditGroupAction).group
editGroup: (action as GroupRegistryEditGroupAction).group,
});
}
case GroupRegistryActionTypes.CANCEL_EDIT_GROUP: {
return Object.assign({}, state, {
editGroup: null
editGroup: null,
});
}

View File

@@ -35,7 +35,7 @@
<ds-themed-loading *ngIf="loading$ | async"></ds-themed-loading>
<ds-pagination
*ngIf="(pageInfoState$ | async)?.totalElements > 0 && !(loading$ | async)"
*ngIf="(pageInfoState$ | async)?.totalElements > 0 && (loading$ | async) !== true"
[paginationOptions]="config"
[pageInfoState]="pageInfoState$"
[collectionSize]="(pageInfoState$ | async)?.totalElements"
@@ -91,7 +91,7 @@
</div>
</ds-pagination>
<div *ngIf="(pageInfoState$ | async)?.totalElements == 0" class="alert alert-info w-100 mb-2" role="alert">
<div *ngIf="(pageInfoState$ | async)?.totalElements === 0" class="alert alert-info w-100 mb-2" role="alert">
{{messagePrefix + 'no-items' | translate}}
</div>

View File

@@ -1,39 +1,71 @@
import { CommonModule } from '@angular/common';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { ComponentFixture, fakeAsync, inject, TestBed, tick, waitForAsync } from '@angular/core/testing';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { BrowserModule, By } from '@angular/platform-browser';
import {
ComponentFixture,
fakeAsync,
inject,
TestBed,
tick,
waitForAsync,
} from '@angular/core/testing';
import {
FormsModule,
ReactiveFormsModule,
} from '@angular/forms';
import {
BrowserModule,
By,
} from '@angular/platform-browser';
import { Router } from '@angular/router';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { Observable, of as observableOf } from 'rxjs';
import {
TranslateLoader,
TranslateModule,
} from '@ngx-translate/core';
import {
Observable,
of as observableOf,
} from 'rxjs';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
import { buildPaginatedList, PaginatedList } from '../../core/data/paginated-list.model';
import { FeatureID } from '../../core/data/feature-authorization/feature-id';
import {
buildPaginatedList,
PaginatedList,
} from '../../core/data/paginated-list.model';
import { RemoteData } from '../../core/data/remote-data';
import { RequestService } from '../../core/data/request.service';
import { EPersonDataService } from '../../core/eperson/eperson-data.service';
import { GroupDataService } from '../../core/eperson/group-data.service';
import { EPerson } from '../../core/eperson/models/eperson.model';
import { Group } from '../../core/eperson/models/group.model';
import { PaginationService } from '../../core/pagination/pagination.service';
import { RouteService } from '../../core/services/route.service';
import { DSpaceObject } from '../../core/shared/dspace-object.model';
import { PageInfo } from '../../core/shared/page-info.model';
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { GroupMock, GroupMock2 } from '../../shared/testing/group-mock';
import { GroupsRegistryComponent } from './groups-registry.component';
import { EPersonMock, EPersonMock2 } from '../../shared/testing/eperson.mock';
import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
import { TranslateLoaderMock } from '../../shared/testing/translate-loader.mock';
import { NotificationsServiceStub } from '../../shared/testing/notifications-service.stub';
import { routeServiceStub } from '../../shared/testing/route-service.stub';
import { RouterMock } from '../../shared/mocks/router.mock';
import { PaginationService } from '../../core/pagination/pagination.service';
import { PaginationServiceStub } from '../../shared/testing/pagination-service.stub';
import { FeatureID } from '../../core/data/feature-authorization/feature-id';
import { NoContent } from '../../core/shared/NoContent.model';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
import { DSONameServiceMock, UNDEFINED_NAME } from '../../shared/mocks/dso-name.service.mock';
import { PageInfo } from '../../core/shared/page-info.model';
import {
DSONameServiceMock,
UNDEFINED_NAME,
} from '../../shared/mocks/dso-name.service.mock';
import { RouterMock } from '../../shared/mocks/router.mock';
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
import {
EPersonMock,
EPersonMock2,
} from '../../shared/testing/eperson.mock';
import {
GroupMock,
GroupMock2,
} from '../../shared/testing/group-mock';
import { NotificationsServiceStub } from '../../shared/testing/notifications-service.stub';
import { PaginationServiceStub } from '../../shared/testing/pagination-service.stub';
import { routeServiceStub } from '../../shared/testing/route-service.stub';
import { TranslateLoaderMock } from '../../shared/testing/translate-loader.mock';
import { GroupsRegistryComponent } from './groups-registry.component';
describe('GroupsRegistryComponent', () => {
let component: GroupsRegistryComponent;
@@ -78,24 +110,24 @@ describe('GroupsRegistryComponent', () => {
elementsPerPage: 1,
totalElements: 0,
totalPages: 0,
currentPage: 1
currentPage: 1,
}), []));
case 'https://dspace.4science.it/dspace-spring-rest/api/eperson/groups/testgroupid/epersons':
return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo({
elementsPerPage: 1,
totalElements: 1,
totalPages: 1,
currentPage: 1
currentPage: 1,
}), [EPersonMock]));
default:
return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo({
elementsPerPage: 1,
totalElements: 0,
totalPages: 0,
currentPage: 1
currentPage: 1,
}), []));
}
}
},
};
groupsDataServiceStub = {
allGroups: mockGroups,
@@ -106,21 +138,21 @@ describe('GroupsRegistryComponent', () => {
elementsPerPage: 1,
totalElements: 0,
totalPages: 0,
currentPage: 1
currentPage: 1,
}), []));
case 'https://dspace.4science.it/dspace-spring-rest/api/eperson/groups/testgroupid/groups':
return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo({
elementsPerPage: 1,
totalElements: 1,
totalPages: 1,
currentPage: 1
currentPage: 1,
}), [GroupMock2]));
default:
return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo({
elementsPerPage: 1,
totalElements: 0,
totalPages: 0,
currentPage: 1
currentPage: 1,
}), []));
}
},
@@ -136,7 +168,7 @@ describe('GroupsRegistryComponent', () => {
elementsPerPage: this.allGroups.length,
totalElements: this.allGroups.length,
totalPages: 1,
currentPage: 1
currentPage: 1,
}), this.allGroups));
}
const result = this.allGroups.find((group: Group) => {
@@ -146,7 +178,7 @@ describe('GroupsRegistryComponent', () => {
elementsPerPage: [result].length,
totalElements: [result].length,
totalPages: 1,
currentPage: 1
currentPage: 1,
}), [result]));
},
delete(objectId: string, copyVirtualMetadata?: string[]): Observable<RemoteData<NoContent>> {
@@ -156,7 +188,7 @@ describe('GroupsRegistryComponent', () => {
dsoDataServiceStub = {
findByHref(href: string): Observable<RemoteData<DSpaceObject>> {
return createSuccessfulRemoteDataObject$(undefined);
}
},
};
authorizationService = jasmine.createSpyObj('authorizationService', ['isAuthorized']);
@@ -167,8 +199,8 @@ describe('GroupsRegistryComponent', () => {
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: TranslateLoaderMock
}
useClass: TranslateLoaderMock,
},
}),
],
declarations: [GroupsRegistryComponent],
@@ -182,9 +214,9 @@ describe('GroupsRegistryComponent', () => {
{ provide: Router, useValue: new RouterMock() },
{ provide: AuthorizationDataService, useValue: authorizationService },
{ provide: PaginationService, useValue: paginationService },
{ provide: RequestService, useValue: jasmine.createSpyObj('requestService', ['removeByHrefSubstring']) }
{ provide: RequestService, useValue: jasmine.createSpyObj('requestService', ['removeByHrefSubstring']) },
],
schemas: [NO_ERRORS_SCHEMA]
schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
}));
@@ -237,16 +269,16 @@ describe('GroupsRegistryComponent', () => {
it('should not check the canManageGroup permissions', () => {
expect(authorizationService.isAuthorized).not.toHaveBeenCalledWith(
FeatureID.CanManageGroup, mockGroups[0].self
FeatureID.CanManageGroup, mockGroups[0].self,
);
expect(authorizationService.isAuthorized).not.toHaveBeenCalledWith(
FeatureID.CanManageGroup, mockGroups[0].self, undefined // treated differently
FeatureID.CanManageGroup, mockGroups[0].self, undefined, // treated differently
);
expect(authorizationService.isAuthorized).not.toHaveBeenCalledWith(
FeatureID.CanManageGroup, mockGroups[1].self
FeatureID.CanManageGroup, mockGroups[1].self,
);
expect(authorizationService.isAuthorized).not.toHaveBeenCalledWith(
FeatureID.CanManageGroup, mockGroups[1].self, undefined // treated differently
FeatureID.CanManageGroup, mockGroups[1].self, undefined, // treated differently
);
});
});

View File

@@ -1,4 +1,8 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import {
Component,
OnDestroy,
OnInit,
} from '@angular/core';
import { UntypedFormBuilder } from '@angular/forms';
import { Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
@@ -8,36 +12,46 @@ import {
EMPTY,
Observable,
of as observableOf,
Subscription
Subscription,
} from 'rxjs';
import { catchError, defaultIfEmpty, map, switchMap, tap } from 'rxjs/operators';
import {
catchError,
defaultIfEmpty,
map,
switchMap,
tap,
} from 'rxjs/operators';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
import { FeatureID } from '../../core/data/feature-authorization/feature-id';
import { buildPaginatedList, PaginatedList } from '../../core/data/paginated-list.model';
import {
buildPaginatedList,
PaginatedList,
} from '../../core/data/paginated-list.model';
import { RemoteData } from '../../core/data/remote-data';
import { RequestService } from '../../core/data/request.service';
import { EPersonDataService } from '../../core/eperson/eperson-data.service';
import { GroupDataService } from '../../core/eperson/group-data.service';
import { EPerson } from '../../core/eperson/models/eperson.model';
import { GroupDtoModel } from '../../core/eperson/models/group-dto.model';
import { Group } from '../../core/eperson/models/group.model';
import { GroupDtoModel } from '../../core/eperson/models/group-dto.model';
import { PaginationService } from '../../core/pagination/pagination.service';
import { RouteService } from '../../core/services/route.service';
import { DSpaceObject } from '../../core/shared/dspace-object.model';
import { NoContent } from '../../core/shared/NoContent.model';
import {
getAllSucceededRemoteData,
getFirstCompletedRemoteData,
getFirstSucceededRemoteData,
getRemoteDataPayload
getRemoteDataPayload,
} from '../../core/shared/operators';
import { PageInfo } from '../../core/shared/page-info.model';
import { hasValue } from '../../shared/empty.util';
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
import { NoContent } from '../../core/shared/NoContent.model';
import { PaginationService } from '../../core/pagination/pagination.service';
import { followLink } from '../../shared/utils/follow-link-config.model';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
@Component({
selector: 'ds-groups-registry',
@@ -57,7 +71,7 @@ export class GroupsRegistryComponent implements OnInit, OnDestroy {
config: PaginationComponentOptions = Object.assign(new PaginationComponentOptions(), {
id: 'gl',
pageSize: 5,
currentPage: 1
currentPage: 1,
});
/**
@@ -155,7 +169,7 @@ export class GroupsRegistryComponent implements OnInit, OnDestroy {
this.canManageGroup$(isSiteAdmin, group),
this.hasLinkedDSO(group),
this.getSubgroups(group),
this.getMembers(group)
this.getMembers(group),
]).pipe(
map(([canDelete, canManageGroup, hasLinkedDSO, subgroups, members]:
[boolean, boolean, boolean, RemoteData<PaginatedList<Group>>, RemoteData<PaginatedList<EPerson>>]) => {
@@ -166,8 +180,8 @@ export class GroupsRegistryComponent implements OnInit, OnDestroy {
groupDtoModel.subgroups = subgroups.payload;
groupDtoModel.epersons = members.payload;
return groupDtoModel;
}
)
},
),
);
} else {
return EMPTY;
@@ -175,9 +189,9 @@ export class GroupsRegistryComponent implements OnInit, OnDestroy {
})]).pipe(defaultIfEmpty([]), map((dtos: GroupDtoModel[]) => {
return buildPaginatedList(groups.pageInfo, dtos);
}));
})
}),
);
})
}),
).subscribe((value: PaginatedList<GroupDtoModel>) => {
this.groupsDto$.next(value);
this.pageInfoState$.next(value.pageInfo);

View File

@@ -1,7 +1,12 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { AdminCurationTasksComponent } from './admin-curation-tasks.component';
import { TranslateModule } from '@ngx-translate/core';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import {
ComponentFixture,
TestBed,
waitForAsync,
} from '@angular/core/testing';
import { TranslateModule } from '@ngx-translate/core';
import { AdminCurationTasksComponent } from './admin-curation-tasks.component';
describe('AdminCurationTasksComponent', () => {
let comp: AdminCurationTasksComponent;
@@ -11,7 +16,7 @@ describe('AdminCurationTasksComponent', () => {
TestBed.configureTestingModule({
imports: [TranslateModule.forRoot()],
declarations: [AdminCurationTasksComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
schemas: [CUSTOM_ELEMENTS_SCHEMA],
}).compileComponents();
}));

View File

@@ -1,22 +1,31 @@
import { ComponentFixture, fakeAsync, TestBed, waitForAsync } from '@angular/core/testing';
import { BatchImportPageComponent } from './batch-import-page.component';
import { NotificationsServiceStub } from '../../shared/testing/notifications-service.stub';
import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
import { FormsModule } from '@angular/forms';
import { TranslateModule } from '@ngx-translate/core';
import { RouterTestingModule } from '@angular/router/testing';
import { FileValueAccessorDirective } from '../../shared/utils/file-value-accessor.directive';
import { FileValidator } from '../../shared/utils/require-file.validator';
import { NotificationsService } from '../../shared/notifications/notifications.service';
import {
BATCH_IMPORT_SCRIPT_NAME,
ScriptDataService
} from '../../core/data/processes/script-data.service';
import { Router } from '@angular/router';
import { Location } from '@angular/common';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import {
ComponentFixture,
fakeAsync,
TestBed,
waitForAsync,
} from '@angular/core/testing';
import { FormsModule } from '@angular/forms';
import { By } from '@angular/platform-browser';
import { Router } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { TranslateModule } from '@ngx-translate/core';
import {
BATCH_IMPORT_SCRIPT_NAME,
ScriptDataService,
} from '../../core/data/processes/script-data.service';
import { ProcessParameter } from '../../process-page/processes/process-parameter.model';
import { NotificationsService } from '../../shared/notifications/notifications.service';
import {
createFailedRemoteDataObject$,
createSuccessfulRemoteDataObject$,
} from '../../shared/remote-data.utils';
import { NotificationsServiceStub } from '../../shared/testing/notifications-service.stub';
import { FileValueAccessorDirective } from '../../shared/utils/file-value-accessor.directive';
import { FileValidator } from '../../shared/utils/require-file.validator';
import { BatchImportPageComponent } from './batch-import-page.component';
describe('BatchImportPageComponent', () => {
let component: BatchImportPageComponent;
@@ -31,14 +40,14 @@ describe('BatchImportPageComponent', () => {
notificationService = new NotificationsServiceStub();
scriptService = jasmine.createSpyObj('scriptService',
{
invoke: createSuccessfulRemoteDataObject$({ processId: '46' })
}
invoke: createSuccessfulRemoteDataObject$({ processId: '46' }),
},
);
router = jasmine.createSpyObj('router', {
navigateByUrl: jasmine.createSpy('navigateByUrl')
navigateByUrl: jasmine.createSpy('navigateByUrl'),
});
locationStub = jasmine.createSpyObj('location', {
back: jasmine.createSpy('back')
back: jasmine.createSpy('back'),
});
}
@@ -48,7 +57,7 @@ describe('BatchImportPageComponent', () => {
imports: [
FormsModule,
TranslateModule.forRoot(),
RouterTestingModule.withRoutes([])
RouterTestingModule.withRoutes([]),
],
declarations: [BatchImportPageComponent, FileValueAccessorDirective, FileValidator],
providers: [
@@ -57,7 +66,7 @@ describe('BatchImportPageComponent', () => {
{ provide: Router, useValue: router },
{ provide: Location, useValue: locationStub },
],
schemas: [NO_ERRORS_SCHEMA]
schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
}));
@@ -108,7 +117,7 @@ describe('BatchImportPageComponent', () => {
it('metadata-import script is invoked with --zip fileName and the mockFile', () => {
const parameterValues: ProcessParameter[] = [
Object.assign(new ProcessParameter(), { name: '--add' }),
Object.assign(new ProcessParameter(), { name: '--zip', value: 'filename.zip' })
Object.assign(new ProcessParameter(), { name: '--zip', value: 'filename.zip' }),
];
expect(scriptService.invoke).toHaveBeenCalledWith(BATCH_IMPORT_SCRIPT_NAME, parameterValues, [fileMock]);
});
@@ -181,7 +190,7 @@ describe('BatchImportPageComponent', () => {
it('metadata-import script is invoked with --url and the file url', () => {
const parameterValues: ProcessParameter[] = [
Object.assign(new ProcessParameter(), { name: '--add' }),
Object.assign(new ProcessParameter(), { name: '--url', value: 'example.fileURL.com' })
Object.assign(new ProcessParameter(), { name: '--url', value: 'example.fileURL.com' }),
];
expect(scriptService.invoke).toHaveBeenCalledWith(BATCH_IMPORT_SCRIPT_NAME, parameterValues, [null]);
});

View File

@@ -1,26 +1,31 @@
import { Component } from '@angular/core';
import { Location } from '@angular/common';
import { TranslateService } from '@ngx-translate/core';
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { BATCH_IMPORT_SCRIPT_NAME, ScriptDataService } from '../../core/data/processes/script-data.service';
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { ProcessParameter } from '../../process-page/processes/process-parameter.model';
import { getFirstCompletedRemoteData } from '../../core/shared/operators';
import { RemoteData } from '../../core/data/remote-data';
import { Process } from '../../process-page/processes/process.model';
import { isEmpty, isNotEmpty } from '../../shared/empty.util';
import { getProcessDetailRoute } from '../../process-page/process-page-routing.paths';
import {
ImportBatchSelectorComponent
} from '../../shared/dso-selector/modal-wrappers/import-batch-selector/import-batch-selector.component';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { TranslateService } from '@ngx-translate/core';
import { take } from 'rxjs/operators';
import { DSpaceObject } from '../../core/shared/dspace-object.model';
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
import {
BATCH_IMPORT_SCRIPT_NAME,
ScriptDataService,
} from '../../core/data/processes/script-data.service';
import { RemoteData } from '../../core/data/remote-data';
import { DSpaceObject } from '../../core/shared/dspace-object.model';
import { getFirstCompletedRemoteData } from '../../core/shared/operators';
import { getProcessDetailRoute } from '../../process-page/process-page-routing.paths';
import { Process } from '../../process-page/processes/process.model';
import { ProcessParameter } from '../../process-page/processes/process-parameter.model';
import { ImportBatchSelectorComponent } from '../../shared/dso-selector/modal-wrappers/import-batch-selector/import-batch-selector.component';
import {
isEmpty,
isNotEmpty,
} from '../../shared/empty.util';
import { NotificationsService } from '../../shared/notifications/notifications.service';
@Component({
selector: 'ds-batch-import-page',
templateUrl: './batch-import-page.component.html'
templateUrl: './batch-import-page.component.html',
})
export class BatchImportPageComponent {
/**
@@ -91,7 +96,7 @@ export class BatchImportPageComponent {
}
} else {
const parameterValues: ProcessParameter[] = [
Object.assign(new ProcessParameter(), { name: '--add' })
Object.assign(new ProcessParameter(), { name: '--add' }),
];
if (this.isUpload) {
parameterValues.push(Object.assign(new ProcessParameter(), { name: '--zip', value: this.fileObject.name }));

View File

@@ -1,19 +1,31 @@
import { Location } from '@angular/common';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { ComponentFixture, fakeAsync, TestBed, waitForAsync } from '@angular/core/testing';
import {
ComponentFixture,
fakeAsync,
TestBed,
waitForAsync,
} from '@angular/core/testing';
import { FormsModule } from '@angular/forms';
import { By } from '@angular/platform-browser';
import { Router } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { TranslateModule } from '@ngx-translate/core';
import { METADATA_IMPORT_SCRIPT_NAME, ScriptDataService } from '../../core/data/processes/script-data.service';
import {
METADATA_IMPORT_SCRIPT_NAME,
ScriptDataService,
} from '../../core/data/processes/script-data.service';
import { ProcessParameter } from '../../process-page/processes/process-parameter.model';
import { NotificationsService } from '../../shared/notifications/notifications.service';
import {
createFailedRemoteDataObject$,
createSuccessfulRemoteDataObject$,
} from '../../shared/remote-data.utils';
import { NotificationsServiceStub } from '../../shared/testing/notifications-service.stub';
import { FileValueAccessorDirective } from '../../shared/utils/file-value-accessor.directive';
import { FileValidator } from '../../shared/utils/require-file.validator';
import { MetadataImportPageComponent } from './metadata-import-page.component';
import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
describe('MetadataImportPageComponent', () => {
let comp: MetadataImportPageComponent;
@@ -28,14 +40,14 @@ describe('MetadataImportPageComponent', () => {
notificationService = new NotificationsServiceStub();
scriptService = jasmine.createSpyObj('scriptService',
{
invoke: createSuccessfulRemoteDataObject$({ processId: '45' })
}
invoke: createSuccessfulRemoteDataObject$({ processId: '45' }),
},
);
router = jasmine.createSpyObj('router', {
navigateByUrl: jasmine.createSpy('navigateByUrl')
navigateByUrl: jasmine.createSpy('navigateByUrl'),
});
locationStub = jasmine.createSpyObj('location', {
back: jasmine.createSpy('back')
back: jasmine.createSpy('back'),
});
}
@@ -45,7 +57,7 @@ describe('MetadataImportPageComponent', () => {
imports: [
FormsModule,
TranslateModule.forRoot(),
RouterTestingModule.withRoutes([])
RouterTestingModule.withRoutes([]),
],
declarations: [MetadataImportPageComponent, FileValueAccessorDirective, FileValidator],
providers: [
@@ -54,7 +66,7 @@ describe('MetadataImportPageComponent', () => {
{ provide: Router, useValue: router },
{ provide: Location, useValue: locationStub },
],
schemas: [NO_ERRORS_SCHEMA]
schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
}));

View File

@@ -2,18 +2,22 @@ import { Location } from '@angular/common';
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { METADATA_IMPORT_SCRIPT_NAME, ScriptDataService } from '../../core/data/processes/script-data.service';
import {
METADATA_IMPORT_SCRIPT_NAME,
ScriptDataService,
} from '../../core/data/processes/script-data.service';
import { RemoteData } from '../../core/data/remote-data';
import { getFirstCompletedRemoteData } from '../../core/shared/operators';
import { getProcessDetailRoute } from '../../process-page/process-page-routing.paths';
import { Process } from '../../process-page/processes/process.model';
import { ProcessParameter } from '../../process-page/processes/process-parameter.model';
import { isNotEmpty } from '../../shared/empty.util';
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { RemoteData } from '../../core/data/remote-data';
import { Process } from '../../process-page/processes/process.model';
import { getFirstCompletedRemoteData } from '../../core/shared/operators';
import { getProcessDetailRoute } from '../../process-page/process-page-routing.paths';
@Component({
selector: 'ds-metadata-import-page',
templateUrl: './metadata-import-page.component.html'
templateUrl: './metadata-import-page.component.html',
})
/**

View File

@@ -1,10 +1,13 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { LdnServicesOverviewComponent } from './ldn-services-directory/ldn-services-directory.component';
import { NavigationBreadcrumbResolver } from '../../core/breadcrumbs/navigation-breadcrumb.resolver';
import { I18nBreadcrumbResolver } from '../../core/breadcrumbs/i18n-breadcrumb.resolver';
import { LdnServiceFormComponent } from './ldn-service-form/ldn-service-form.component';
import {
RouterModule,
Routes,
} from '@angular/router';
import { I18nBreadcrumbResolver } from '../../core/breadcrumbs/i18n-breadcrumb.resolver';
import { NavigationBreadcrumbResolver } from '../../core/breadcrumbs/navigation-breadcrumb.resolver';
import { LdnServiceFormComponent } from './ldn-service-form/ldn-service-form.component';
import { LdnServicesOverviewComponent } from './ldn-services-directory/ldn-services-directory.component';
const moduleRoutes: Routes = [
{
@@ -18,13 +21,13 @@ const moduleRoutes: Routes = [
path: 'new',
resolve: { breadcrumb: NavigationBreadcrumbResolver },
component: LdnServiceFormComponent,
data: {title: 'ldn-register-new-service.title', breadcrumbKey: 'ldn-register-new-service'}
data: { title: 'ldn-register-new-service.title', breadcrumbKey: 'ldn-register-new-service' },
},
{
path: 'edit/:serviceId',
resolve: { breadcrumb: NavigationBreadcrumbResolver },
component: LdnServiceFormComponent,
data: {title: 'ldn-edit-service.title', breadcrumbKey: 'ldn-edit-service'}
data: { title: 'ldn-edit-service.title', breadcrumbKey: 'ldn-edit-service' },
},
];
@@ -37,10 +40,10 @@ const moduleRoutes: Routes = [
relatedRoutes: moduleRoutes.filter(relatedRoute => relatedRoute.path !== route.path)
.map((relatedRoute) => {
return { path: relatedRoute.path, data: relatedRoute.data };
})
}),
} };
}))
]
})),
],
})
export class AdminLdnServicesRoutingModule {

View File

@@ -1,25 +1,25 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { AdminLdnServicesRoutingModule } from './admin-ldn-services-routing.module';
import { LdnServicesOverviewComponent } from './ldn-services-directory/ldn-services-directory.component';
import { SharedModule } from '../../shared/shared.module';
import { LdnServiceFormComponent } from './ldn-service-form/ldn-service-form.component';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { LdnItemfiltersService } from './ldn-services-data/ldn-itemfilters-data.service';
import { SharedModule } from '../../shared/shared.module';
import { AdminLdnServicesRoutingModule } from './admin-ldn-services-routing.module';
import { LdnServiceFormComponent } from './ldn-service-form/ldn-service-form.component';
import { LdnItemfiltersService } from './ldn-services-data/ldn-itemfilters-data.service';
import { LdnServicesOverviewComponent } from './ldn-services-directory/ldn-services-directory.component';
@NgModule({
imports: [
CommonModule,
SharedModule,
AdminLdnServicesRoutingModule,
FormsModule
FormsModule,
],
declarations: [
LdnServicesOverviewComponent,
LdnServiceFormComponent,
],
providers: [LdnItemfiltersService]
providers: [LdnItemfiltersService],
})
export class AdminLdnServicesModule {
}

View File

@@ -1,23 +1,49 @@
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import {NgbDropdownModule, NgbModal} from '@ng-bootstrap/ng-bootstrap';
import {LdnServiceFormComponent} from './ldn-service-form.component';
import {ChangeDetectorRef, EventEmitter} from '@angular/core';
import { FormArray, FormBuilder, FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
import {ActivatedRoute, Router} from '@angular/router';
import {TranslateModule, TranslateService} from '@ngx-translate/core';
import {
ChangeDetectorRef,
EventEmitter,
} from '@angular/core';
import {
ComponentFixture,
fakeAsync,
TestBed,
tick,
} from '@angular/core/testing';
import {
FormArray,
FormBuilder,
FormControl,
FormGroup,
ReactiveFormsModule,
} from '@angular/forms';
import { By } from '@angular/platform-browser';
import {
ActivatedRoute,
Router,
} from '@angular/router';
import {
NgbDropdownModule,
NgbModal,
} from '@ng-bootstrap/ng-bootstrap';
import { provideMockStore } from '@ngrx/store/testing';
import {
TranslateModule,
TranslateService,
} from '@ngx-translate/core';
import { PaginationService } from 'ngx-pagination';
import {
of as observableOf,
of,
} from 'rxjs';
import { RouteService } from '../../../core/services/route.service';
import { MockActivatedRoute } from '../../../shared/mocks/active-router.mock';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub';
import { RouterStub } from '../../../shared/testing/router.stub';
import { LdnItemfiltersService } from '../ldn-services-data/ldn-itemfilters-data.service';
import { LdnServicesService } from '../ldn-services-data/ldn-services-data.service';
import {RouterStub} from '../../../shared/testing/router.stub';
import {MockActivatedRoute} from '../../../shared/mocks/active-router.mock';
import {NotificationsServiceStub} from '../../../shared/testing/notifications-service.stub';
import { of as observableOf, of } from 'rxjs';
import {RouteService} from '../../../core/services/route.service';
import {provideMockStore} from '@ngrx/store/testing';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
import { By } from '@angular/platform-browser';
import { LdnServiceFormComponent } from './ldn-service-form.component';
describe('LdnServiceFormEditComponent', () => {
let component: LdnServiceFormComponent;
@@ -52,9 +78,9 @@ describe('LdnServiceFormEditComponent', () => {
'pattern': '',
'patternLabel': 'Select a pattern',
'constraint': '',
'automatic': false
}
]
'automatic': false,
},
],
};
@@ -63,7 +89,7 @@ describe('LdnServiceFormEditComponent', () => {
instant: () => 'translated-text',
onLangChange: new EventEmitter(),
onTranslationChange: new EventEmitter(),
onDefaultLangChange: new EventEmitter()
onDefaultLangChange: new EventEmitter(),
};
beforeEach(async () => {
@@ -77,11 +103,11 @@ describe('LdnServiceFormEditComponent', () => {
findAll: () => of(['item1', 'item2']),
};
cdRefStub = Object.assign({
detectChanges: () => fixture.detectChanges()
detectChanges: () => fixture.detectChanges(),
});
modalService = {
open: () => {/*comment*/
}
},
};
@@ -103,7 +129,7 @@ describe('LdnServiceFormEditComponent', () => {
FormBuilder,
RouteService,
provideMockStore({}),
]
],
})
.compileComponents();
@@ -196,13 +222,13 @@ describe('LdnServiceFormEditComponent', () => {
it('should check patterns', () => {
const arrValid = new FormArray([
new FormGroup({
pattern: new FormControl('pattern')
pattern: new FormControl('pattern'),
}),
]);
const arrInvalid = new FormArray([
new FormGroup({
pattern: new FormControl('')
pattern: new FormControl(''),
}),
]);

View File

@@ -1,38 +1,51 @@
import {
animate,
state,
style,
transition,
trigger,
} from '@angular/animations';
import {
ChangeDetectorRef,
Component,
OnDestroy,
OnInit,
TemplateRef,
ViewChild
ViewChild,
} from '@angular/core';
import {
FormArray,
FormBuilder,
FormGroup,
Validators
Validators,
} from '@angular/forms';
import {LDN_SERVICE} from '../ldn-services-model/ldn-service.resource-type';
import {ActivatedRoute, Router} from '@angular/router';
import {LdnServicesService} from '../ldn-services-data/ldn-services-data.service';
import {notifyPatterns} from '../ldn-services-patterns/ldn-service-coar-patterns';
import {animate, state, style, transition, trigger} from '@angular/animations';
import {
ActivatedRoute,
Router,
} from '@angular/router';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import {NotificationsService} from '../../../shared/notifications/notifications.service';
import { TranslateService } from '@ngx-translate/core';
import {LdnService} from '../ldn-services-model/ldn-services.model';
import {RemoteData} from 'src/app/core/data/remote-data';
import { Operation } from 'fast-json-patch';
import {getFirstCompletedRemoteData} from '../../../core/shared/operators';
import {LdnItemfiltersService} from '../ldn-services-data/ldn-itemfilters-data.service';
import {Itemfilter} from '../ldn-services-model/ldn-service-itemfilters';
import {PaginatedList} from '../../../core/data/paginated-list.model';
import {combineLatestWith, Observable, Subscription} from 'rxjs';
import {PaginationService} from '../../../core/pagination/pagination.service';
import {FindListOptions} from '../../../core/data/find-list-options.model';
import {NotifyServicePattern} from '../ldn-services-model/ldn-service-patterns.model';
import { IpV4Validator } from '../../../shared/utils/ipV4.validator';
import {
combineLatestWith,
Observable,
Subscription,
} from 'rxjs';
import { RemoteData } from 'src/app/core/data/remote-data';
import { FindListOptions } from '../../../core/data/find-list-options.model';
import { PaginatedList } from '../../../core/data/paginated-list.model';
import { PaginationService } from '../../../core/pagination/pagination.service';
import { getFirstCompletedRemoteData } from '../../../core/shared/operators';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { IpV4Validator } from '../../../shared/utils/ipV4.validator';
import { LdnItemfiltersService } from '../ldn-services-data/ldn-itemfilters-data.service';
import { LdnServicesService } from '../ldn-services-data/ldn-services-data.service';
import { LDN_SERVICE } from '../ldn-services-model/ldn-service.resource-type';
import { Itemfilter } from '../ldn-services-model/ldn-service-itemfilters';
import { NotifyServicePattern } from '../ldn-services-model/ldn-service-patterns.model';
import { LdnService } from '../ldn-services-model/ldn-services.model';
import { notifyPatterns } from '../ldn-services-patterns/ldn-service-coar-patterns';
/**
* Component for editing LDN service through a form that allows to create or edit the properties of a service
@@ -60,7 +73,7 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy {
public areControlsInitialized: boolean;
public itemfiltersRD$: Observable<RemoteData<PaginatedList<Itemfilter>>>;
public config: FindListOptions = Object.assign(new FindListOptions(), {
elementsPerPage: 20
elementsPerPage: 20,
});
public markedForDeletionInboundPattern: number[] = [];
public selectedInboundPatterns: string[];
@@ -83,7 +96,7 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy {
protected modalService: NgbModal,
private notificationService: NotificationsService,
private translateService: TranslateService,
protected paginationService: PaginationService
protected paginationService: PaginationService,
) {
this.formModel = this.formBuilder.group({
@@ -103,7 +116,7 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy {
ngOnInit(): void {
this.routeSubscription = this.route.params.pipe(
combineLatestWith(this.route.url)
combineLatestWith(this.route.url),
).subscribe(([params, segment]) => {
this.serviceId = params.serviceId;
this.isNewService = segment[0].path === 'new';
@@ -164,7 +177,7 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy {
const ldnServiceData = this.ldnServicesService.create(values);
ldnServiceData.pipe(
getFirstCompletedRemoteData()
getFirstCompletedRemoteData(),
).subscribe((rd: RemoteData<LdnService>) => {
if (rd.hasSucceeded) {
this.notificationService.success(this.translateService.get('ldn-service-notification.created.success.title'),
@@ -204,7 +217,7 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy {
*/
fetchServiceData(serviceId: string): void {
this.ldnServicesService.findById(serviceId).pipe(
getFirstCompletedRemoteData()
getFirstCompletedRemoteData(),
).subscribe(
(data: RemoteData<LdnService>) => {
if (data.hasSucceeded) {
@@ -219,18 +232,18 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy {
type: this.ldnService.type,
enabled: this.ldnService.enabled,
lowerIp: this.ldnService.lowerIp,
upperIp: this.ldnService.upperIp
upperIp: this.ldnService.upperIp,
});
this.filterPatternObjectsAndAssignLabel('notifyServiceInboundPatterns');
let notifyServiceInboundPatternsFormArray = this.formModel.get('notifyServiceInboundPatterns') as FormArray;
const notifyServiceInboundPatternsFormArray = this.formModel.get('notifyServiceInboundPatterns') as FormArray;
notifyServiceInboundPatternsFormArray.controls.forEach(
control => {
const controlFormGroup = control as FormGroup;
const controlConstraint = controlFormGroup.get('constraint').value;
controlFormGroup.patchValue({
constraintFormatted: controlConstraint ? this.translateService.instant((controlConstraint as string) + '.label') : ''
constraintFormatted: controlConstraint ? this.translateService.instant((controlConstraint as string) + '.label') : '',
});
}
},
);
}
},
@@ -245,14 +258,13 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy {
const PatternsArray = this.formModel.get(formArrayName) as FormArray;
PatternsArray.clear();
let servicesToUse = this.ldnService.notifyServiceInboundPatterns;
const servicesToUse = this.ldnService.notifyServiceInboundPatterns;
servicesToUse.forEach((patternObj: NotifyServicePattern) => {
let patternFormGroup;
patternFormGroup = this.initializeInboundPatternFormGroup();
const patternFormGroup = this.initializeInboundPatternFormGroup();
const newPatternObjWithLabel = Object.assign(new NotifyServicePattern(), {
...patternObj,
patternLabel: this.translateService.instant('ldn-service.form.pattern.' + patternObj?.pattern + '.label')
patternLabel: this.translateService.instant('ldn-service.form.pattern.' + patternObj?.pattern + '.label'),
});
patternFormGroup.patchValue(newPatternObjWithLabel);
@@ -280,7 +292,7 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy {
this.deletedInboundPatterns.forEach(index => {
const removeOperation: Operation = {
op: 'remove',
path: `notifyServiceInboundPatterns[${index}]`
path: `notifyServiceInboundPatterns[${index}]`,
};
patchOperations.push(removeOperation);
});
@@ -323,7 +335,7 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy {
const filterArray = (this.formModel.get('notifyServiceInboundPatterns') as FormArray);
filterArray.controls[index].patchValue({
constraint: filterValue,
constraintFormatted: this.translateService.instant((filterValue !== '' ? filterValue : 'ldn.no-filter') + '.label')
constraintFormatted: this.translateService.instant((filterValue !== '' ? filterValue : 'ldn.no-filter') + '.label'),
});
filterArray.markAllAsTouched();
}
@@ -353,12 +365,12 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy {
};
this.ldnServicesService.patch(this.ldnService, [patchOperation]).pipe(
getFirstCompletedRemoteData()
getFirstCompletedRemoteData(),
).subscribe(
() => {
this.formModel.get('enabled').setValue(newStatus);
this.cdRef.detectChanges();
}
},
);
}
@@ -404,7 +416,7 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy {
}
this.ldnServicesService.patch(this.ldnService, patchOperations).pipe(
getFirstCompletedRemoteData()
getFirstCompletedRemoteData(),
).subscribe(
(rd: RemoteData<LdnService>) => {
if (rd.hasSucceeded) {
@@ -542,7 +554,7 @@ export class LdnServiceFormComponent implements OnInit, OnDestroy {
constraint: '',
constraintFormatted: '',
automatic: false,
isNew: true
isNew: true,
};
if (this.isNewService) {

View File

@@ -1,9 +1,13 @@
import {LdnService} from '../ldn-services-model/ldn-services.model';
import {LDN_SERVICE} from '../ldn-services-model/ldn-service.resource-type';
import {RemoteData} from '../../../core/data/remote-data';
import {
Observable,
of,
} from 'rxjs';
import { PaginatedList } from '../../../core/data/paginated-list.model';
import {Observable, of} from 'rxjs';
import { RemoteData } from '../../../core/data/remote-data';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
import { LDN_SERVICE } from '../ldn-services-model/ldn-service.resource-type';
import { LdnService } from '../ldn-services-model/ldn-services.model';
export const mockLdnService: LdnService = {
uuid: '1',
@@ -31,7 +35,7 @@ export const mockLdnService: LdnService = {
type: LDN_SERVICE,
_links: {
self: {
href: 'http://localhost/api/ldn/ldnservices/1'
href: 'http://localhost/api/ldn/ldnservices/1',
},
},
get self(): string {
@@ -68,7 +72,7 @@ export const mockLdnServices: LdnService[] = [{
type: LDN_SERVICE,
_links: {
self: {
href: 'http://localhost/api/ldn/ldnservices/1'
href: 'http://localhost/api/ldn/ldnservices/1',
},
},
get self(): string {
@@ -100,12 +104,12 @@ export const mockLdnServices: LdnService[] = [{
type: LDN_SERVICE,
_links: {
self: {
href: 'http://localhost/api/ldn/ldnservices/1'
href: 'http://localhost/api/ldn/ldnservices/1',
},
},
get self(): string {
return '';
},
}
},
];
export const mockLdnServicesRD$: Observable<RemoteData<PaginatedList<LdnService>>> = of((mockLdnServices as unknown) as RemoteData<PaginatedList<LdnService>>);

View File

@@ -1,19 +1,23 @@
import {
cold,
getTestScheduler,
} from 'jasmine-marbles';
import { of } from 'rxjs';
import { TestScheduler } from 'rxjs/testing';
import { LdnItemfiltersService } from './ldn-itemfilters-data.service';
import { RequestService } from '../../../core/data/request.service';
import { RemoteDataBuildService } from '../../../core/cache/builders/remote-data-build.service';
import { ObjectCacheService } from '../../../core/cache/object-cache.service';
import { HALEndpointService } from '../../../core/shared/hal-endpoint.service';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { RequestEntry } from '../../../core/data/request-entry.model';
import { RemoteData } from '../../../core/data/remote-data';
import { RequestEntryState } from '../../../core/data/request-entry-state.model';
import { cold, getTestScheduler } from 'jasmine-marbles';
import { RestResponse } from '../../../core/cache/response.models';
import { of } from 'rxjs';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
import { FindAllData } from '../../../core/data/base/find-all-data';
import { testFindAllDataImplementation } from '../../../core/data/base/find-all-data.spec';
import { RemoteData } from '../../../core/data/remote-data';
import { RequestService } from '../../../core/data/request.service';
import { RequestEntry } from '../../../core/data/request-entry.model';
import { RequestEntryState } from '../../../core/data/request-entry-state.model';
import { HALEndpointService } from '../../../core/shared/hal-endpoint.service';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
import { LdnItemfiltersService } from './ldn-itemfilters-data.service';
describe('LdnItemfiltersService test', () => {
let scheduler: TestScheduler;
@@ -60,12 +64,12 @@ describe('LdnItemfiltersService test', () => {
});
halService = jasmine.createSpyObj('halService', {
getEndpoint: of(endpointURL)
getEndpoint: of(endpointURL),
});
rdbService = jasmine.createSpyObj('rdbService', {
buildSingle: createSuccessfulRemoteDataObject$({}, 500),
buildList: cold('a', { a: remoteDataMocks.Success })
buildList: cold('a', { a: remoteDataMocks.Success }),
});

View File

@@ -1,21 +1,23 @@
import { Injectable } from '@angular/core';
import {dataService} from '../../../core/data/base/data-service.decorator';
import {LDN_SERVICE_CONSTRAINT_FILTERS} from '../ldn-services-model/ldn-service.resource-type';
import {IdentifiableDataService} from '../../../core/data/base/identifiable-data.service';
import {FindAllData, FindAllDataImpl} from '../../../core/data/base/find-all-data';
import { Observable } from 'rxjs';
import {RequestService} from '../../../core/data/request.service';
import { RemoteDataBuildService } from '../../../core/cache/builders/remote-data-build.service';
import { ObjectCacheService } from '../../../core/cache/object-cache.service';
import { dataService } from '../../../core/data/base/data-service.decorator';
import {
FindAllData,
FindAllDataImpl,
} from '../../../core/data/base/find-all-data';
import { IdentifiableDataService } from '../../../core/data/base/identifiable-data.service';
import { FindListOptions } from '../../../core/data/find-list-options.model';
import { PaginatedList } from '../../../core/data/paginated-list.model';
import { RemoteData } from '../../../core/data/remote-data';
import { RequestService } from '../../../core/data/request.service';
import { HALEndpointService } from '../../../core/shared/hal-endpoint.service';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import {FindListOptions} from '../../../core/data/find-list-options.model';
import { FollowLinkConfig } from '../../../shared/utils/follow-link-config.model';
import {Observable} from 'rxjs';
import {RemoteData} from '../../../core/data/remote-data';
import { LDN_SERVICE_CONSTRAINT_FILTERS } from '../ldn-services-model/ldn-service.resource-type';
import { Itemfilter } from '../ldn-services-model/ldn-service-itemfilters';
import {PaginatedList} from '../../../core/data/paginated-list.model';
/**
* A service responsible for fetching/sending data from/to the REST API on the itemfilters endpoint

View File

@@ -1,32 +1,35 @@
import { TestScheduler } from 'rxjs/testing';
import { RequestService } from '../../../core/data/request.service';
import { RemoteDataBuildService } from '../../../core/cache/builders/remote-data-build.service';
import { ObjectCacheService } from '../../../core/cache/object-cache.service';
import { HALEndpointService } from '../../../core/shared/hal-endpoint.service';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { RequestEntry } from '../../../core/data/request-entry.model';
import { RemoteData } from '../../../core/data/remote-data';
import { RequestEntryState } from '../../../core/data/request-entry-state.model';
import { cold, getTestScheduler } from 'jasmine-marbles';
import { RestResponse } from '../../../core/cache/response.models';
import {
cold,
getTestScheduler,
} from 'jasmine-marbles';
import { of as observableOf } from 'rxjs';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
import { FindAllData } from '../../../core/data/base/find-all-data';
import { testFindAllDataImplementation } from '../../../core/data/base/find-all-data.spec';
import { LdnServicesService } from './ldn-services-data.service';
import { testDeleteDataImplementation } from '../../../core/data/base/delete-data.spec';
import { DeleteData } from '../../../core/data/base/delete-data';
import { testSearchDataImplementation } from '../../../core/data/base/search-data.spec';
import { SearchData } from '../../../core/data/base/search-data';
import { testPatchDataImplementation } from '../../../core/data/base/patch-data.spec';
import { PatchData } from '../../../core/data/base/patch-data';
import { TestScheduler } from 'rxjs/testing';
import { RemoteDataBuildService } from '../../../core/cache/builders/remote-data-build.service';
import { RequestParam } from '../../../core/cache/models/request-param.model';
import { ObjectCacheService } from '../../../core/cache/object-cache.service';
import { RestResponse } from '../../../core/cache/response.models';
import { CreateData } from '../../../core/data/base/create-data';
import { testCreateDataImplementation } from '../../../core/data/base/create-data.spec';
import { DeleteData } from '../../../core/data/base/delete-data';
import { testDeleteDataImplementation } from '../../../core/data/base/delete-data.spec';
import { FindAllData } from '../../../core/data/base/find-all-data';
import { testFindAllDataImplementation } from '../../../core/data/base/find-all-data.spec';
import { PatchData } from '../../../core/data/base/patch-data';
import { testPatchDataImplementation } from '../../../core/data/base/patch-data.spec';
import { SearchData } from '../../../core/data/base/search-data';
import { testSearchDataImplementation } from '../../../core/data/base/search-data.spec';
import { FindListOptions } from '../../../core/data/find-list-options.model';
import { RequestParam } from '../../../core/cache/models/request-param.model';
import { mockLdnService } from '../ldn-service-serviceMock/ldnServicesRD$-mock';
import { RemoteData } from '../../../core/data/remote-data';
import { RequestService } from '../../../core/data/request.service';
import { RequestEntry } from '../../../core/data/request-entry.model';
import { RequestEntryState } from '../../../core/data/request-entry-state.model';
import { HALEndpointService } from '../../../core/shared/hal-endpoint.service';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
import { createPaginatedList } from '../../../shared/testing/utils.test';
import { mockLdnService } from '../ldn-service-serviceMock/ldnServicesRD$-mock';
import { LdnServicesService } from './ldn-services-data.service';
describe('LdnServicesService test', () => {
let scheduler: TestScheduler;
@@ -73,13 +76,13 @@ describe('LdnServicesService test', () => {
});
halService = jasmine.createSpyObj('halService', {
getEndpoint: observableOf(endpointURL)
getEndpoint: observableOf(endpointURL),
});
rdbService = jasmine.createSpyObj('rdbService', {
buildSingle: createSuccessfulRemoteDataObject$({}, 500),
buildFromRequestUUID: createSuccessfulRemoteDataObject$({}, 500),
buildList: cold('a', { a: remoteDataMocks.Success })
buildList: cold('a', { a: remoteDataMocks.Success }),
});

View File

@@ -1,36 +1,49 @@
import { Injectable } from '@angular/core';
import {dataService} from '../../../core/data/base/data-service.decorator';
import {LDN_SERVICE} from '../ldn-services-model/ldn-service.resource-type';
import {IdentifiableDataService} from '../../../core/data/base/identifiable-data.service';
import {FindAllData, FindAllDataImpl} from '../../../core/data/base/find-all-data';
import {DeleteData, DeleteDataImpl} from '../../../core/data/base/delete-data';
import {RequestService} from '../../../core/data/request.service';
import {RemoteDataBuildService} from '../../../core/cache/builders/remote-data-build.service';
import {ObjectCacheService} from '../../../core/cache/object-cache.service';
import {HALEndpointService} from '../../../core/shared/hal-endpoint.service';
import {NotificationsService} from '../../../shared/notifications/notifications.service';
import {FindListOptions} from '../../../core/data/find-list-options.model';
import {FollowLinkConfig} from '../../../shared/utils/follow-link-config.model';
import {Observable} from 'rxjs';
import {RemoteData} from '../../../core/data/remote-data';
import {PaginatedList} from '../../../core/data/paginated-list.model';
import {NoContent} from '../../../core/shared/NoContent.model';
import {map, take} from 'rxjs/operators';
import {URLCombiner} from '../../../core/url-combiner/url-combiner';
import {MultipartPostRequest} from '../../../core/data/request.models';
import {RestRequest} from '../../../core/data/rest-request.model';
import {LdnService} from '../ldn-services-model/ldn-services.model';
import {PatchData, PatchDataImpl} from '../../../core/data/base/patch-data';
import {ChangeAnalyzer} from '../../../core/data/change-analyzer';
import { Operation } from 'fast-json-patch';
import {RestRequestMethod} from '../../../core/data/rest-request-method';
import {CreateData, CreateDataImpl} from '../../../core/data/base/create-data';
import {LdnServiceConstrain} from '../ldn-services-model/ldn-service.constrain.model';
import {SearchDataImpl} from '../../../core/data/base/search-data';
import { Observable } from 'rxjs';
import {
map,
take,
} from 'rxjs/operators';
import { RemoteDataBuildService } from '../../../core/cache/builders/remote-data-build.service';
import { RequestParam } from '../../../core/cache/models/request-param.model';
import { ObjectCacheService } from '../../../core/cache/object-cache.service';
import {
CreateData,
CreateDataImpl,
} from '../../../core/data/base/create-data';
import { dataService } from '../../../core/data/base/data-service.decorator';
import {
DeleteData,
DeleteDataImpl,
} from '../../../core/data/base/delete-data';
import {
FindAllData,
FindAllDataImpl,
} from '../../../core/data/base/find-all-data';
import { IdentifiableDataService } from '../../../core/data/base/identifiable-data.service';
import {
PatchData,
PatchDataImpl,
} from '../../../core/data/base/patch-data';
import { SearchDataImpl } from '../../../core/data/base/search-data';
import { ChangeAnalyzer } from '../../../core/data/change-analyzer';
import { FindListOptions } from '../../../core/data/find-list-options.model';
import { PaginatedList } from '../../../core/data/paginated-list.model';
import { RemoteData } from '../../../core/data/remote-data';
import { MultipartPostRequest } from '../../../core/data/request.models';
import { RequestService } from '../../../core/data/request.service';
import { RestRequest } from '../../../core/data/rest-request.model';
import { RestRequestMethod } from '../../../core/data/rest-request-method';
import { HALEndpointService } from '../../../core/shared/hal-endpoint.service';
import { NoContent } from '../../../core/shared/NoContent.model';
import { URLCombiner } from '../../../core/url-combiner/url-combiner';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { FollowLinkConfig } from '../../../shared/utils/follow-link-config.model';
import { LdnServiceConstrain } from '../ldn-services-model/ldn-service.constrain.model';
import { LDN_SERVICE } from '../ldn-services-model/ldn-service.resource-type';
import { LdnService } from '../ldn-services-model/ldn-services.model';
/**
* Injectable service responsible for fetching/sending data from/to the REST API on the ldnservices endpoint.
@@ -200,7 +213,7 @@ export class LdnServicesService extends IdentifiableDataService<LdnService> impl
map((endpoint: string) => {
const body = this.getInvocationFormData(parameters, files);
return new MultipartPostRequest(requestId, endpoint, body);
})
}),
).subscribe((request: RestRequest) => this.requestService.send(request));
return this.rdbService.buildFromRequestUUID<LdnService>(requestId);

View File

@@ -1,19 +1,32 @@
import {ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing';
import { ChangeDetectorRef, EventEmitter, NO_ERRORS_SCHEMA } from '@angular/core';
import {NotificationsService} from '../../../shared/notifications/notifications.service';
import {NotificationsServiceStub} from '../../../shared/testing/notifications-service.stub';
import {TranslateModule, TranslateService} from '@ngx-translate/core';
import {
ChangeDetectorRef,
EventEmitter,
NO_ERRORS_SCHEMA,
} from '@angular/core';
import {
ComponentFixture,
fakeAsync,
TestBed,
tick,
} from '@angular/core/testing';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import {LdnServicesService} from '../ldn-services-data/ldn-services-data.service';
import {PaginationService} from '../../../core/pagination/pagination.service';
import {PaginationServiceStub} from '../../../shared/testing/pagination-service.stub';
import {
TranslateModule,
TranslateService,
} from '@ngx-translate/core';
import { of } from 'rxjs';
import {LdnService} from '../ldn-services-model/ldn-services.model';
import { PaginatedList } from '../../../core/data/paginated-list.model';
import { RemoteData } from '../../../core/data/remote-data';
import {LdnServicesOverviewComponent} from './ldn-services-directory.component';
import { PaginationService } from '../../../core/pagination/pagination.service';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub';
import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub';
import { createPaginatedList } from '../../../shared/testing/utils.test';
import { LdnServicesService } from '../ldn-services-data/ldn-services-data.service';
import { LdnService } from '../ldn-services-model/ldn-services.model';
import { LdnServicesOverviewComponent } from './ldn-services-directory.component';
describe('LdnServicesOverviewComponent', () => {
let component: LdnServicesOverviewComponent;
@@ -26,7 +39,7 @@ describe('LdnServicesOverviewComponent', () => {
get: () => of('translated-text'),
onLangChange: new EventEmitter(),
onTranslationChange: new EventEmitter(),
onDefaultLangChange: new EventEmitter()
onDefaultLangChange: new EventEmitter(),
};
beforeEach(async () => {
@@ -42,20 +55,20 @@ describe('LdnServicesOverviewComponent', () => {
providers: [
{
provide: LdnServicesService,
useValue: ldnServicesService
useValue: ldnServicesService,
},
{ provide: PaginationService, useValue: paginationService },
{
provide: NgbModal, useValue: {
open: () => { /*comment*/
}
}
},
},
},
{ provide: ChangeDetectorRef, useValue: {} },
{ provide: NotificationsService, useValue: new NotificationsServiceStub() },
{ provide: TranslateService, useValue: translateServiceStub },
],
schemas: [NO_ERRORS_SCHEMA]
schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
});

View File

@@ -5,24 +5,30 @@ import {
OnDestroy,
OnInit,
TemplateRef,
ViewChild
ViewChild,
} from '@angular/core';
import {Observable, Subscription} from 'rxjs';
import {RemoteData} from '../../../core/data/remote-data';
import {PaginatedList} from '../../../core/data/paginated-list.model';
import {FindListOptions} from '../../../core/data/find-list-options.model';
import {LdnService} from '../ldn-services-model/ldn-services.model';
import {PaginationComponentOptions} from '../../../shared/pagination/pagination-component-options.model';
import {map, switchMap} from 'rxjs/operators';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { TranslateService } from '@ngx-translate/core';
import { Operation } from 'fast-json-patch';
import {
Observable,
Subscription,
} from 'rxjs';
import {
map,
switchMap,
} from 'rxjs/operators';
import { LdnServicesService } from 'src/app/admin/admin-ldn-services/ldn-services-data/ldn-services-data.service';
import { PaginationService } from 'src/app/core/pagination/pagination.service';
import {NgbModal} from '@ng-bootstrap/ng-bootstrap';
import {hasValue} from '../../../shared/empty.util';
import {Operation} from 'fast-json-patch';
import {getFirstCompletedRemoteData} from '../../../core/shared/operators';
import {NotificationsService} from '../../../shared/notifications/notifications.service';
import {TranslateService} from '@ngx-translate/core';
import { FindListOptions } from '../../../core/data/find-list-options.model';
import { PaginatedList } from '../../../core/data/paginated-list.model';
import { RemoteData } from '../../../core/data/remote-data';
import { getFirstCompletedRemoteData } from '../../../core/shared/operators';
import { hasValue } from '../../../shared/empty.util';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
import { LdnService } from '../ldn-services-model/ldn-services.model';
/**
* The `LdnServicesOverviewComponent` is a component that provides an overview of LDN (Linked Data Notifications) services.
@@ -33,7 +39,7 @@ import {TranslateService} from '@ngx-translate/core';
selector: 'ds-ldn-services-directory',
templateUrl: './ldn-services-directory.component.html',
styleUrls: ['./ldn-services-directory.component.scss'],
changeDetection: ChangeDetectionStrategy.Default
changeDetection: ChangeDetectionStrategy.Default,
})
export class LdnServicesOverviewComponent implements OnInit, OnDestroy {
@@ -42,11 +48,11 @@ export class LdnServicesOverviewComponent implements OnInit, OnDestroy {
@ViewChild('deleteModal', { static: true }) deleteModal: TemplateRef<any>;
ldnServicesRD$: Observable<RemoteData<PaginatedList<LdnService>>>;
config: FindListOptions = Object.assign(new FindListOptions(), {
elementsPerPage: 10
elementsPerPage: 10,
});
pageConfig: PaginationComponentOptions = Object.assign(new PaginationComponentOptions(), {
id: 'po',
pageSize: 10
pageSize: 10,
});
isProcessingSub: Subscription;
modalRef: any;
@@ -72,8 +78,8 @@ export class LdnServicesOverviewComponent implements OnInit, OnDestroy {
setLdnServices() {
this.ldnServicesRD$ = this.paginationService.getFindListOptions(this.pageConfig.id, this.config).pipe(
switchMap((config) => this.ldnServicesService.findAll(config, false, false).pipe(
getFirstCompletedRemoteData()
))
getFirstCompletedRemoteData(),
)),
);
}
@@ -128,7 +134,7 @@ export class LdnServicesOverviewComponent implements OnInit, OnDestroy {
remoteData.payload.page = remoteData.payload.page.filter(service => service.id.toString() !== serviceId);
}
return remoteData;
})
}),
);
this.cdRef.detectChanges();
this.closeModal();
@@ -170,7 +176,7 @@ export class LdnServicesOverviewComponent implements OnInit, OnDestroy {
this.notificationService.error(this.translateService.get('ldn-enable-service.notification.error.title'),
this.translateService.get('ldn-enable-service.notification.error.content'));
}
}
},
);
}
}

View File

@@ -1,9 +1,14 @@
import {autoserialize, deserialize, inheritSerialization} from 'cerialize';
import {LDN_SERVICE_CONSTRAINT_FILTER} from './ldn-service.resource-type';
import {CacheableObject} from '../../../core/cache/cacheable-object.model';
import {
autoserialize,
deserialize,
inheritSerialization,
} from 'cerialize';
import { typedObject } from '../../../core/cache/builders/build-decorators';
import {excludeFromEquals} from '../../../core/utilities/equals.decorators';
import { CacheableObject } from '../../../core/cache/cacheable-object.model';
import { ResourceType } from '../../../core/shared/resource-type';
import { excludeFromEquals } from '../../../core/utilities/equals.decorators';
import { LDN_SERVICE_CONSTRAINT_FILTER } from './ldn-service.resource-type';
/** A single filter value and its properties. */
@typedObject

View File

@@ -1,11 +1,16 @@
import {ResourceType} from '../../../core/shared/resource-type';
import {CacheableObject} from '../../../core/cache/cacheable-object.model';
import {autoserialize, deserialize, deserializeAs, inheritSerialization} from 'cerialize';
import {LDN_SERVICE} from './ldn-service.resource-type';
import {excludeFromEquals} from '../../../core/utilities/equals.decorators';
import {typedObject} from '../../../core/cache/builders/build-decorators';
import {NotifyServicePattern} from './ldn-service-patterns.model';
import {
autoserialize,
deserialize,
deserializeAs,
inheritSerialization,
} from 'cerialize';
import { typedObject } from '../../../core/cache/builders/build-decorators';
import { CacheableObject } from '../../../core/cache/cacheable-object.model';
import { ResourceType } from '../../../core/shared/resource-type';
import { excludeFromEquals } from '../../../core/utilities/equals.decorators';
import { LDN_SERVICE } from './ldn-service.resource-type';
import { NotifyServicePattern } from './ldn-service-patterns.model';
/**
* LDN Services bounded to each selected pattern, relation set in service creation

View File

@@ -1,5 +1,9 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
import {
ActivatedRouteSnapshot,
Resolve,
RouterStateSnapshot,
} from '@angular/router';
/**
* Interface for the route parameters.
@@ -26,7 +30,7 @@ export class NotificationsSuggestionTargetsPageResolver implements Resolve<Notif
return {
pageId: route.queryParams.pageId,
pageSize: parseInt(route.queryParams.pageSize, 10),
currentPage: parseInt(route.queryParams.page, 10)
currentPage: parseInt(route.queryParams.page, 10),
};
}
}

View File

@@ -1,11 +1,13 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { CommonModule } from '@angular/common';
import { TranslateModule } from '@ngx-translate/core';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import {
NotificationsSuggestionTargetsPageComponent
} from '../../../quality-assurance-notifications-pages/notifications-suggestion-targets-page/notifications-suggestion-targets-page.component';
async,
ComponentFixture,
TestBed,
} from '@angular/core/testing';
import { TranslateModule } from '@ngx-translate/core';
import { NotificationsSuggestionTargetsPageComponent } from '../../../quality-assurance-notifications-pages/notifications-suggestion-targets-page/notifications-suggestion-targets-page.component';
describe('NotificationsSuggestionTargetsPageComponent', () => {
let component: NotificationsSuggestionTargetsPageComponent;
@@ -15,15 +17,15 @@ describe('NotificationsSuggestionTargetsPageComponent', () => {
TestBed.configureTestingModule({
imports: [
CommonModule,
TranslateModule.forRoot()
TranslateModule.forRoot(),
],
declarations: [
NotificationsSuggestionTargetsPageComponent
NotificationsSuggestionTargetsPageComponent,
],
providers: [
NotificationsSuggestionTargetsPageComponent
NotificationsSuggestionTargetsPageComponent,
],
schemas: [NO_ERRORS_SCHEMA]
schemas: [NO_ERRORS_SCHEMA],
})
.compileComponents();
}));

View File

@@ -3,7 +3,7 @@ import { Component } from '@angular/core';
@Component({
selector: 'ds-admin-notifications-publication-claim-page',
templateUrl: './admin-notifications-publication-claim-page.component.html',
styleUrls: ['./admin-notifications-publication-claim-page.component.scss']
styleUrls: ['./admin-notifications-publication-claim-page.component.scss'],
})
export class AdminNotificationsPublicationClaimPageComponent {

View File

@@ -4,39 +4,22 @@ import { RouterModule } from '@angular/router';
import { AuthenticatedGuard } from '../../core/auth/authenticated.guard';
import { I18nBreadcrumbResolver } from '../../core/breadcrumbs/i18n-breadcrumb.resolver';
import { I18nBreadcrumbsService } from '../../core/breadcrumbs/i18n-breadcrumbs.service';
import { PUBLICATION_CLAIMS_PATH } from './admin-notifications-routing-paths';
import { AdminNotificationsPublicationClaimPageComponent } from './admin-notifications-publication-claim-page/admin-notifications-publication-claim-page.component';
import { QUALITY_ASSURANCE_EDIT_PATH } from './admin-notifications-routing-paths';
import {
SiteAdministratorGuard
} from '../../core/data/feature-authorization/feature-authorization-guard/site-administrator.guard';
import { QualityAssuranceBreadcrumbResolver } from '../../core/breadcrumbs/quality-assurance-breadcrumb.resolver';
import { QualityAssuranceBreadcrumbService } from '../../core/breadcrumbs/quality-assurance-breadcrumb.service';
import { SiteAdministratorGuard } from '../../core/data/feature-authorization/feature-authorization-guard/site-administrator.guard';
import { AdminNotificationsPublicationClaimPageResolver } from '../../quality-assurance-notifications-pages/notifications-suggestion-targets-page/notifications-suggestion-targets-page-resolver.service';
import { QualityAssuranceEventsPageComponent } from '../../quality-assurance-notifications-pages/quality-assurance-events-page/quality-assurance-events-page.component';
import { QualityAssuranceEventsPageResolver } from '../../quality-assurance-notifications-pages/quality-assurance-events-page/quality-assurance-events-page.resolver';
import { SourceDataResolver } from '../../quality-assurance-notifications-pages/quality-assurance-source-page-component/quality-assurance-source-data.resolver';
import { QualityAssuranceSourcePageComponent } from '../../quality-assurance-notifications-pages/quality-assurance-source-page-component/quality-assurance-source-page.component';
import { QualityAssuranceSourcePageResolver } from '../../quality-assurance-notifications-pages/quality-assurance-source-page-component/quality-assurance-source-page-resolver.service';
import { QualityAssuranceTopicsPageComponent } from '../../quality-assurance-notifications-pages/quality-assurance-topics-page/quality-assurance-topics-page.component';
import { QualityAssuranceTopicsPageResolver } from '../../quality-assurance-notifications-pages/quality-assurance-topics-page/quality-assurance-topics-page-resolver.service';
import { AdminNotificationsPublicationClaimPageComponent } from './admin-notifications-publication-claim-page/admin-notifications-publication-claim-page.component';
import {
QualityAssuranceEventsPageResolver
} from '../../quality-assurance-notifications-pages/quality-assurance-events-page/quality-assurance-events-page.resolver';
import {
AdminNotificationsPublicationClaimPageResolver
} from '../../quality-assurance-notifications-pages/notifications-suggestion-targets-page/notifications-suggestion-targets-page-resolver.service';
import {
QualityAssuranceTopicsPageComponent
} from '../../quality-assurance-notifications-pages/quality-assurance-topics-page/quality-assurance-topics-page.component';
import {
QualityAssuranceTopicsPageResolver
} from '../../quality-assurance-notifications-pages/quality-assurance-topics-page/quality-assurance-topics-page-resolver.service';
import {
QualityAssuranceSourcePageComponent
} from '../../quality-assurance-notifications-pages/quality-assurance-source-page-component/quality-assurance-source-page.component';
import {
QualityAssuranceSourcePageResolver
} from '../../quality-assurance-notifications-pages/quality-assurance-source-page-component/quality-assurance-source-page-resolver.service';
import {
SourceDataResolver
} from '../../quality-assurance-notifications-pages/quality-assurance-source-page-component/quality-assurance-source-data.resolver';
import {
QualityAssuranceEventsPageComponent
} from '../../quality-assurance-notifications-pages/quality-assurance-events-page/quality-assurance-events-page.component';
PUBLICATION_CLAIMS_PATH,
QUALITY_ASSURANCE_EDIT_PATH,
} from './admin-notifications-routing-paths';
@NgModule({
imports: [
@@ -48,13 +31,13 @@ import {
pathMatch: 'full',
resolve: {
breadcrumb: I18nBreadcrumbResolver,
suggestionTargetParams: AdminNotificationsPublicationClaimPageResolver
suggestionTargetParams: AdminNotificationsPublicationClaimPageResolver,
},
data: {
title: 'admin.notifications.publicationclaim.page.title',
breadcrumbKey: 'admin.notifications.publicationclaim',
showBreadcrumbsFluid: false
}
showBreadcrumbsFluid: false,
},
},
{
canActivate: [ AuthenticatedGuard ],
@@ -63,13 +46,13 @@ import {
pathMatch: 'full',
resolve: {
breadcrumb: QualityAssuranceBreadcrumbResolver,
openaireQualityAssuranceTopicsParams: QualityAssuranceTopicsPageResolver
openaireQualityAssuranceTopicsParams: QualityAssuranceTopicsPageResolver,
},
data: {
title: 'admin.quality-assurance.page.title',
breadcrumbKey: 'admin.quality-assurance',
showBreadcrumbsFluid: false
}
showBreadcrumbsFluid: false,
},
},
{
canActivate: [ AuthenticatedGuard ],
@@ -78,13 +61,13 @@ import {
pathMatch: 'full',
resolve: {
breadcrumb: I18nBreadcrumbResolver,
openaireQualityAssuranceTopicsParams: QualityAssuranceTopicsPageResolver
openaireQualityAssuranceTopicsParams: QualityAssuranceTopicsPageResolver,
},
data: {
title: 'admin.quality-assurance.page.title',
breadcrumbKey: 'admin.quality-assurance',
showBreadcrumbsFluid: false
}
showBreadcrumbsFluid: false,
},
},
{
canActivate: [ SiteAdministratorGuard ],
@@ -94,13 +77,13 @@ import {
resolve: {
breadcrumb: I18nBreadcrumbResolver,
openaireQualityAssuranceSourceParams: QualityAssuranceSourcePageResolver,
sourceData: SourceDataResolver
sourceData: SourceDataResolver,
},
data: {
title: 'admin.notifications.source.breadcrumbs',
breadcrumbKey: 'admin.notifications.source',
showBreadcrumbsFluid: false
}
showBreadcrumbsFluid: false,
},
},
{
canActivate: [ AuthenticatedGuard ],
@@ -109,15 +92,15 @@ import {
pathMatch: 'full',
resolve: {
breadcrumb: QualityAssuranceBreadcrumbResolver,
openaireQualityAssuranceEventsParams: QualityAssuranceEventsPageResolver
openaireQualityAssuranceEventsParams: QualityAssuranceEventsPageResolver,
},
data: {
title: 'admin.notifications.event.page.title',
breadcrumbKey: 'admin.notifications.event',
showBreadcrumbsFluid: false
}
}
])
showBreadcrumbsFluid: false,
},
},
]),
],
providers: [
I18nBreadcrumbResolver,
@@ -129,8 +112,8 @@ import {
QualityAssuranceEventsPageResolver,
QualityAssuranceSourcePageResolver,
QualityAssuranceBreadcrumbResolver,
QualityAssuranceBreadcrumbService
]
QualityAssuranceBreadcrumbService,
],
})
/**
* Routing module for the Notifications section of the admin sidebar

View File

@@ -1,16 +1,11 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { CoreModule } from '../../core/core.module';
import { SharedModule } from '../../shared/shared.module';
import { AdminNotificationsRoutingModule } from './admin-notifications-routing.module';
import { AdminNotificationsPublicationClaimPageComponent } from './admin-notifications-publication-claim-page/admin-notifications-publication-claim-page.component';
import { NotificationsModule } from '../../notifications/notifications.module';
import { SharedModule } from '../../shared/shared.module';
import { AdminNotificationsPublicationClaimPageComponent } from './admin-notifications-publication-claim-page/admin-notifications-publication-claim-page.component';
import { AdminNotificationsRoutingModule } from './admin-notifications-routing.module';
@NgModule({
imports: [
@@ -18,12 +13,12 @@ import { NotificationsModule } from '../../notifications/notifications.module';
SharedModule,
CoreModule.forRoot(),
AdminNotificationsRoutingModule,
NotificationsModule
NotificationsModule,
],
declarations: [
AdminNotificationsPublicationClaimPageComponent,
],
entryComponents: []
entryComponents: [],
})
/**
* This module handles all components related to the notifications pages

View File

@@ -1,17 +1,12 @@
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { I18nBreadcrumbResolver } from '../../core/breadcrumbs/i18n-breadcrumb.resolver';
import { AdminNotifyDashboardComponent } from './admin-notify-dashboard.component';
import {
SiteAdministratorGuard
} from '../../core/data/feature-authorization/feature-authorization-guard/site-administrator.guard';
import {
AdminNotifyIncomingComponent
} from './admin-notify-logs/admin-notify-incoming/admin-notify-incoming.component';
import {
AdminNotifyOutgoingComponent
} from './admin-notify-logs/admin-notify-outgoing/admin-notify-outgoing.component';
import { NotifyInfoGuard } from '../../core/coar-notify/notify-info/notify-info.guard';
import { SiteAdministratorGuard } from '../../core/data/feature-authorization/feature-authorization-guard/site-administrator.guard';
import { AdminNotifyDashboardComponent } from './admin-notify-dashboard.component';
import { AdminNotifyIncomingComponent } from './admin-notify-logs/admin-notify-incoming/admin-notify-incoming.component';
import { AdminNotifyOutgoingComponent } from './admin-notify-logs/admin-notify-outgoing/admin-notify-outgoing.component';
@NgModule({
imports: [
@@ -52,8 +47,8 @@ import { NotifyInfoGuard } from '../../core/coar-notify/notify-info/notify-info.
title: 'admin.notify.dashboard.page.title',
breadcrumbKey: 'admin.notify.dashboard',
},
}
])
},
]),
],
})
/**

View File

@@ -1,13 +1,16 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AdminNotifyDashboardComponent } from './admin-notify-dashboard.component';
import { TranslateModule } from '@ngx-translate/core';
import {
ComponentFixture,
TestBed,
} from '@angular/core/testing';
import { NgbNavModule } from '@ng-bootstrap/ng-bootstrap';
import { TranslateModule } from '@ngx-translate/core';
import { buildPaginatedList } from '../../core/data/paginated-list.model';
import { SearchService } from '../../core/shared/search/search.service';
import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
import { buildPaginatedList } from '../../core/data/paginated-list.model';
import { AdminNotifySearchResult } from './models/admin-notify-message-search-result.model';
import { AdminNotifyDashboardComponent } from './admin-notify-dashboard.component';
import { AdminNotifyMessage } from './models/admin-notify-message.model';
import { AdminNotifySearchResult } from './models/admin-notify-message-search-result.model';
describe('AdminNotifyDashboardComponent', () => {
let component: AdminNotifyDashboardComponent;
@@ -23,7 +26,7 @@ describe('AdminNotifyDashboardComponent', () => {
const mockBoxes = [
{ title: 'admin-notify-dashboard.received-ldn', boxes: [ undefined, undefined, undefined, undefined, undefined ] },
{ title: 'admin-notify-dashboard.generated-ldn', boxes: [ undefined, undefined, undefined, undefined, undefined ] }
{ title: 'admin-notify-dashboard.generated-ldn', boxes: [ undefined, undefined, undefined, undefined, undefined ] },
];
beforeEach(async () => {
@@ -38,7 +41,7 @@ describe('AdminNotifyDashboardComponent', () => {
await TestBed.configureTestingModule({
imports: [TranslateModule.forRoot(), NgbNavModule],
declarations: [ AdminNotifyDashboardComponent ],
providers: [{ provide: SearchService, useValue: { search: () => createSuccessfulRemoteDataObject$(results)}}]
providers: [{ provide: SearchService, useValue: { search: () => createSuccessfulRemoteDataObject$(results) } }],
})
.compileComponents();

View File

@@ -1,17 +1,26 @@
import { Component, OnInit } from '@angular/core';
import { SearchService } from '../../core/shared/search/search.service';
import { environment } from '../../../environments/environment';
import { PaginatedSearchOptions } from '../../shared/search/models/paginated-search-options.model';
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
import { forkJoin, Observable } from 'rxjs';
import { getFirstCompletedRemoteData } from '../../core/shared/operators';
import {
Component,
OnInit,
} from '@angular/core';
import {
forkJoin,
Observable,
} from 'rxjs';
import { map } from 'rxjs/operators';
import { SearchObjects } from '../../shared/search/models/search-objects.model';
import { AdminNotifyMetricsBox, AdminNotifyMetricsRow } from './admin-notify-metrics/admin-notify-metrics.model';
import { DSpaceObject } from '../../core/shared/dspace-object.model';
import { SEARCH_CONFIG_SERVICE } from '../../my-dspace-page/my-dspace-page.component';
import { SearchConfigurationService } from '../../core/shared/search/search-configuration.service';
import { environment } from '../../../environments/environment';
import { DSpaceObject } from '../../core/shared/dspace-object.model';
import { getFirstCompletedRemoteData } from '../../core/shared/operators';
import { SearchService } from '../../core/shared/search/search.service';
import { SearchConfigurationService } from '../../core/shared/search/search-configuration.service';
import { SEARCH_CONFIG_SERVICE } from '../../my-dspace-page/my-dspace-page.component';
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
import { PaginatedSearchOptions } from '../../shared/search/models/paginated-search-options.model';
import { SearchObjects } from '../../shared/search/models/search-objects.model';
import {
AdminNotifyMetricsBox,
AdminNotifyMetricsRow,
} from './admin-notify-metrics/admin-notify-metrics.model';
@Component({
selector: 'ds-admin-notify-dashboard',
@@ -19,9 +28,9 @@ import { SearchConfigurationService } from '../../core/shared/search/search-conf
providers: [
{
provide: SEARCH_CONFIG_SERVICE,
useClass: SearchConfigurationService
}
]
useClass: SearchConfigurationService,
},
],
})
/**
@@ -34,7 +43,7 @@ export class AdminNotifyDashboardComponent implements OnInit{
private metricsConfig = environment.notifyMetrics;
private singleResultOptions = Object.assign(new PaginationComponentOptions(), {
id: 'single-result-options',
pageSize: 1
pageSize: 1,
});
constructor(private searchService: SearchService) {
@@ -47,17 +56,17 @@ export class AdminNotifyDashboardComponent implements OnInit{
const flatConfigurations = [].concat(...mertricsRowsConfigurations.map((config) => config));
const searchConfigurations = flatConfigurations
.map(config => Object.assign(new PaginatedSearchOptions({}),
{ configuration: config, pagination: this.singleResultOptions }
{ configuration: config, pagination: this.singleResultOptions },
));
this.notifyMetricsRows$ = forkJoin(searchConfigurations.map(config => this.searchService.search(config)
.pipe(
getFirstCompletedRemoteData(),
map(response => this.mapSearchObjectsToMetricsBox(response.payload)),
)
)
),
),
).pipe(
map(metricBoxes => this.mapUpdatedBoxesToMetricsRows(metricBoxes))
map(metricBoxes => this.mapUpdatedBoxesToMetricsRows(metricBoxes)),
);
}
@@ -74,7 +83,7 @@ export class AdminNotifyDashboardComponent implements OnInit{
return {
...metricsBoxes.find(box => box.config === objectConfig),
count
count,
};
}
@@ -88,7 +97,7 @@ export class AdminNotifyDashboardComponent implements OnInit{
return this.metricsConfig.map(row => {
return {
...row,
boxes: row.boxes.map(rowBox => boxesWithCount.find(boxWithCount => boxWithCount.config === rowBox.config))
boxes: row.boxes.map(rowBox => boxesWithCount.find(boxWithCount => boxWithCount.config === rowBox.config)),
};
});
}

View File

@@ -1,26 +1,25 @@
import {
CommonModule,
DatePipe,
} from '@angular/common';
import { NgModule } from '@angular/core';
import { CommonModule, DatePipe } from '@angular/common';
import { RouterModule } from '@angular/router';
import { SearchPageModule } from '../../search-page/search-page.module';
import { SearchModule } from '../../shared/search/search.module';
import { SharedModule } from '../../shared/shared.module';
import { AdminNotifyDashboardComponent } from './admin-notify-dashboard.component';
import { AdminNotifyDashboardRoutingModule } from './admin-notify-dashboard-routing.module';
import { AdminNotifyMetricsComponent } from './admin-notify-metrics/admin-notify-metrics.component';
import { AdminNotifyIncomingComponent } from './admin-notify-logs/admin-notify-incoming/admin-notify-incoming.component';
import { SharedModule } from '../../shared/shared.module';
import { SearchModule } from '../../shared/search/search.module';
import { SearchPageModule } from '../../search-page/search-page.module';
import {
AdminNotifyOutgoingComponent
} from './admin-notify-logs/admin-notify-outgoing/admin-notify-outgoing.component';
import { AdminNotifyDetailModalComponent } from './admin-notify-detail-modal/admin-notify-detail-modal.component';
import {
AdminNotifySearchResultComponent
} from './admin-notify-search-result/admin-notify-search-result.component';
import { AdminNotifyMessagesService } from './services/admin-notify-messages.service';
import { AdminNotifyIncomingComponent } from './admin-notify-logs/admin-notify-incoming/admin-notify-incoming.component';
import { AdminNotifyLogsResultComponent } from './admin-notify-logs/admin-notify-logs-result/admin-notify-logs-result.component';
import { AdminNotifyOutgoingComponent } from './admin-notify-logs/admin-notify-outgoing/admin-notify-outgoing.component';
import { AdminNotifyMetricsComponent } from './admin-notify-metrics/admin-notify-metrics.component';
import { AdminNotifySearchResultComponent } from './admin-notify-search-result/admin-notify-search-result.component';
import { AdminNotifyMessagesService } from './services/admin-notify-messages.service';
const ENTRY_COMPONENTS = [
AdminNotifySearchResultComponent
AdminNotifySearchResultComponent,
];
@NgModule({
imports: [
@@ -29,11 +28,11 @@ const ENTRY_COMPONENTS = [
SharedModule,
AdminNotifyDashboardRoutingModule,
SearchModule,
SearchPageModule
SearchPageModule,
],
providers: [
AdminNotifyMessagesService,
DatePipe
DatePipe,
],
declarations: [
...ENTRY_COMPONENTS,
@@ -43,14 +42,14 @@ const ENTRY_COMPONENTS = [
AdminNotifyOutgoingComponent,
AdminNotifyDetailModalComponent,
AdminNotifySearchResultComponent,
AdminNotifyLogsResultComponent
]
AdminNotifyLogsResultComponent,
],
})
export class AdminNotifyDashboardModule {
static withEntryComponents() {
return {
ngModule: AdminNotifyDashboardModule,
providers: ENTRY_COMPONENTS.map((component) => ({provide: component}))
providers: ENTRY_COMPONENTS.map((component) => ({ provide: component })),
};
}
}

View File

@@ -1,9 +1,12 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AdminNotifyDetailModalComponent } from './admin-notify-detail-modal.component';
import {
ComponentFixture,
TestBed,
} from '@angular/core/testing';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { TranslateModule } from '@ngx-translate/core';
import { AdminNotifyDetailModalComponent } from './admin-notify-detail-modal.component';
describe('AdminNotifyDetailModalComponent', () => {
let component: AdminNotifyDetailModalComponent;
let fixture: ComponentFixture<AdminNotifyDetailModalComponent>;
@@ -14,7 +17,7 @@ describe('AdminNotifyDetailModalComponent', () => {
await TestBed.configureTestingModule({
imports: [TranslateModule.forRoot()],
declarations: [ AdminNotifyDetailModalComponent ],
providers: [{ provide: NgbActiveModal, useValue: modalStub }]
providers: [{ provide: NgbActiveModal, useValue: modalStub }],
})
.compileComponents();

View File

@@ -1,16 +1,22 @@
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { AdminNotifyMessage } from '../models/admin-notify-message.model';
import {
Component,
EventEmitter,
Input,
Output,
} from '@angular/core';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { TranslateService } from '@ngx-translate/core';
import { MissingTranslationHelper } from '../../../shared/translate/missing-translation.helper';
import { fadeIn } from '../../../shared/animations/fade';
import { MissingTranslationHelper } from '../../../shared/translate/missing-translation.helper';
import { AdminNotifyMessage } from '../models/admin-notify-message.model';
@Component({
selector: 'ds-admin-notify-detail-modal',
templateUrl: './admin-notify-detail-modal.component.html',
animations: [
fadeIn
]
fadeIn,
],
})
/**
* Component for detailed view of LDN messages displayed in search result in AdminNotifyDashboardComponent

View File

@@ -1,18 +1,21 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AdminNotifyIncomingComponent } from './admin-notify-incoming.component';
import { TranslateModule } from '@ngx-translate/core';
import {
ComponentFixture,
TestBed,
} from '@angular/core/testing';
import { ActivatedRoute } from '@angular/router';
import { MockActivatedRoute } from '../../../../shared/mocks/active-router.mock';
import { provideMockStore } from '@ngrx/store/testing';
import { HALEndpointService } from '../../../../core/shared/hal-endpoint.service';
import { SEARCH_CONFIG_SERVICE } from '../../../../my-dspace-page/my-dspace-page.component';
import { RouteService } from '../../../../core/services/route.service';
import { routeServiceStub } from '../../../../shared/testing/route-service.stub';
import { RequestService } from '../../../../core/data/request.service';
import { TranslateModule } from '@ngx-translate/core';
import { RemoteDataBuildService } from '../../../../core/cache/builders/remote-data-build.service';
import { getMockRemoteDataBuildService } from '../../../../shared/mocks/remote-data-build.service.mock';
import { RequestService } from '../../../../core/data/request.service';
import { RouteService } from '../../../../core/services/route.service';
import { HALEndpointService } from '../../../../core/shared/hal-endpoint.service';
import { SearchConfigurationService } from '../../../../core/shared/search/search-configuration.service';
import { SEARCH_CONFIG_SERVICE } from '../../../../my-dspace-page/my-dspace-page.component';
import { MockActivatedRoute } from '../../../../shared/mocks/active-router.mock';
import { getMockRemoteDataBuildService } from '../../../../shared/mocks/remote-data-build.service.mock';
import { routeServiceStub } from '../../../../shared/testing/route-service.stub';
import { AdminNotifyIncomingComponent } from './admin-notify-incoming.component';
describe('AdminNotifyIncomingComponent', () => {
let component: AdminNotifyIncomingComponent;
@@ -26,7 +29,7 @@ describe('AdminNotifyIncomingComponent', () => {
beforeEach(async () => {
rdbService = getMockRemoteDataBuildService();
halService = jasmine.createSpyObj('halService', {
'getRootHref': '/api'
'getRootHref': '/api',
});
requestService = jasmine.createSpyObj('requestService', {
'generateRequestId': 'client/1234',
@@ -43,7 +46,7 @@ describe('AdminNotifyIncomingComponent', () => {
{ provide: RequestService, useValue: requestService },
{ provide: RemoteDataBuildService, useValue: rdbService },
provideMockStore({}),
]
],
})
.compileComponents();

View File

@@ -1,7 +1,10 @@
import { Component, Inject } from '@angular/core';
import { SEARCH_CONFIG_SERVICE } from '../../../../my-dspace-page/my-dspace-page.component';
import { SearchConfigurationService } from '../../../../core/shared/search/search-configuration.service';
import {
Component,
Inject,
} from '@angular/core';
import { SearchConfigurationService } from '../../../../core/shared/search/search-configuration.service';
import { SEARCH_CONFIG_SERVICE } from '../../../../my-dspace-page/my-dspace-page.component';
@Component({
selector: 'ds-admin-notify-incoming',
@@ -9,9 +12,9 @@ import { SearchConfigurationService } from '../../../../core/shared/search/searc
providers: [
{
provide: SEARCH_CONFIG_SERVICE,
useClass: SearchConfigurationService
}
]
useClass: SearchConfigurationService,
},
],
})
export class AdminNotifyIncomingComponent {
constructor(@Inject(SEARCH_CONFIG_SERVICE) public searchConfigService: SearchConfigurationService) {

View File

@@ -1,17 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AdminNotifyLogsResultComponent } from './admin-notify-logs-result.component';
import { ActivatedRoute, Router } from '@angular/router';
import { MockActivatedRoute } from '../../../../shared/mocks/active-router.mock';
import {
ComponentFixture,
TestBed,
} from '@angular/core/testing';
import {
ActivatedRoute,
Router,
} from '@angular/router';
import { provideMockStore } from '@ngrx/store/testing';
import { HALEndpointService } from '../../../../core/shared/hal-endpoint.service';
import { TranslateModule } from '@ngx-translate/core';
import { RemoteDataBuildService } from '../../../../core/cache/builders/remote-data-build.service';
import { ObjectCacheService } from '../../../../core/cache/object-cache.service';
import { RequestService } from '../../../../core/data/request.service';
import { RemoteDataBuildService } from '../../../../core/cache/builders/remote-data-build.service';
import { TranslateModule } from '@ngx-translate/core';
import { RouterStub } from '../../../../shared/testing/router.stub';
import { RouteService } from '../../../../core/services/route.service';
import { HALEndpointService } from '../../../../core/shared/hal-endpoint.service';
import { MockActivatedRoute } from '../../../../shared/mocks/active-router.mock';
import { routeServiceStub } from '../../../../shared/testing/route-service.stub';
import { RouterStub } from '../../../../shared/testing/router.stub';
import { AdminNotifyLogsResultComponent } from './admin-notify-logs-result.component';
describe('AdminNotifyLogsResultComponent', () => {
let component: AdminNotifyLogsResultComponent;
@@ -34,7 +40,7 @@ describe('AdminNotifyLogsResultComponent', () => {
{ provide: RequestService, useValue: requestService },
{ provide: RemoteDataBuildService, useValue: rdbService },
provideMockStore({}),
]
],
})
.compileComponents();

View File

@@ -3,15 +3,20 @@ import {
Component,
Inject,
Input,
OnInit
OnInit,
} from '@angular/core';
import { SEARCH_CONFIG_SERVICE } from '../../../../my-dspace-page/my-dspace-page.component';
import {
ActivatedRoute,
ActivatedRouteSnapshot,
Router,
} from '@angular/router';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Context } from '../../../../core/shared/context.model';
import { SearchConfigurationService } from '../../../../core/shared/search/search-configuration.service';
import { Observable } from 'rxjs';
import { ActivatedRoute, ActivatedRouteSnapshot, Router } from '@angular/router';
import { ViewMode } from '../../../../core/shared/view-mode.model';
import { map } from 'rxjs/operators';
import { SEARCH_CONFIG_SERVICE } from '../../../../my-dspace-page/my-dspace-page.component';
@Component({
selector: 'ds-admin-notify-logs-result',
@@ -19,9 +24,9 @@ import { map } from 'rxjs/operators';
providers: [
{
provide: SEARCH_CONFIG_SERVICE,
useClass: SearchConfigurationService
}
]
useClass: SearchConfigurationService,
},
],
})
/**
@@ -48,7 +53,7 @@ export class AdminNotifyLogsResultComponent implements OnInit {
ngOnInit() {
this.selectedSearchConfig$ = this.searchConfigService.getCurrentConfiguration(this.defaultConfiguration);
this.isInbound$ = this.selectedSearchConfig$.pipe(
map(config => config.startsWith('NOTIFY.incoming'))
map(config => config.startsWith('NOTIFY.incoming')),
);
}

View File

@@ -1,18 +1,21 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AdminNotifyOutgoingComponent } from './admin-notify-outgoing.component';
import { TranslateModule } from '@ngx-translate/core';
import {
ComponentFixture,
TestBed,
} from '@angular/core/testing';
import { ActivatedRoute } from '@angular/router';
import { MockActivatedRoute } from '../../../../shared/mocks/active-router.mock';
import { provideMockStore } from '@ngrx/store/testing';
import { HALEndpointService } from '../../../../core/shared/hal-endpoint.service';
import { SEARCH_CONFIG_SERVICE } from '../../../../my-dspace-page/my-dspace-page.component';
import { RouteService } from '../../../../core/services/route.service';
import { routeServiceStub } from '../../../../shared/testing/route-service.stub';
import { RequestService } from '../../../../core/data/request.service';
import { getMockRemoteDataBuildService } from '../../../../shared/mocks/remote-data-build.service.mock';
import { TranslateModule } from '@ngx-translate/core';
import { RemoteDataBuildService } from '../../../../core/cache/builders/remote-data-build.service';
import { RequestService } from '../../../../core/data/request.service';
import { RouteService } from '../../../../core/services/route.service';
import { HALEndpointService } from '../../../../core/shared/hal-endpoint.service';
import { SearchConfigurationService } from '../../../../core/shared/search/search-configuration.service';
import { SEARCH_CONFIG_SERVICE } from '../../../../my-dspace-page/my-dspace-page.component';
import { MockActivatedRoute } from '../../../../shared/mocks/active-router.mock';
import { getMockRemoteDataBuildService } from '../../../../shared/mocks/remote-data-build.service.mock';
import { routeServiceStub } from '../../../../shared/testing/route-service.stub';
import { AdminNotifyOutgoingComponent } from './admin-notify-outgoing.component';
describe('AdminNotifyOutgoingComponent', () => {
let component: AdminNotifyOutgoingComponent;
@@ -29,7 +32,7 @@ describe('AdminNotifyOutgoingComponent', () => {
'send': '',
});
halService = jasmine.createSpyObj('halService', {
'getRootHref': '/api'
'getRootHref': '/api',
});
await TestBed.configureTestingModule({
imports: [TranslateModule.forRoot()],
@@ -42,7 +45,7 @@ describe('AdminNotifyOutgoingComponent', () => {
{ provide: RequestService, useValue: requestService },
{ provide: RemoteDataBuildService, useValue: rdbService },
provideMockStore({}),
]
],
})
.compileComponents();

View File

@@ -1,7 +1,10 @@
import { Component, Inject } from '@angular/core';
import { SEARCH_CONFIG_SERVICE } from '../../../../my-dspace-page/my-dspace-page.component';
import { SearchConfigurationService } from '../../../../core/shared/search/search-configuration.service';
import {
Component,
Inject,
} from '@angular/core';
import { SearchConfigurationService } from '../../../../core/shared/search/search-configuration.service';
import { SEARCH_CONFIG_SERVICE } from '../../../../my-dspace-page/my-dspace-page.component';
@Component({
selector: 'ds-admin-notify-outgoing',
@@ -9,9 +12,9 @@ import { SearchConfigurationService } from '../../../../core/shared/search/searc
providers: [
{
provide: SEARCH_CONFIG_SERVICE,
useClass: SearchConfigurationService
}
]
useClass: SearchConfigurationService,
},
],
})
export class AdminNotifyOutgoingComponent {
constructor(@Inject(SEARCH_CONFIG_SERVICE) public searchConfigService: SearchConfigurationService) {

View File

@@ -1,10 +1,13 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AdminNotifyMetricsComponent } from './admin-notify-metrics.component';
import { TranslateModule } from '@ngx-translate/core';
import {
ComponentFixture,
TestBed,
} from '@angular/core/testing';
import { Router } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core';
import { ViewMode } from '../../../core/shared/view-mode.model';
import { RouterStub } from '../../../shared/testing/router.stub';
import { AdminNotifyMetricsComponent } from './admin-notify-metrics.component';
describe('AdminNotifyMetricsComponent', () => {
let component: AdminNotifyMetricsComponent;
@@ -13,14 +16,14 @@ describe('AdminNotifyMetricsComponent', () => {
beforeEach(async () => {
router = Object.assign(new RouterStub(),
{url : '/notify-dashboard'}
{ url : '/notify-dashboard' },
);
await TestBed.configureTestingModule({
imports: [TranslateModule.forRoot()],
declarations: [ AdminNotifyMetricsComponent ],
providers: [{provide: Router, useValue: router}]
providers: [{ provide: Router, useValue: router }],
})
.compileComponents();
@@ -42,21 +45,21 @@ describe('AdminNotifyMetricsComponent', () => {
const routeExtras = {
queryParams: {
configuration: searchConfig,
view: ViewMode.ListElement
view: ViewMode.ListElement,
},
};
const routeExtrasTable = {
queryParams: {
configuration: incomingConfig,
view: ViewMode.Table
view: ViewMode.Table,
},
};
const routeExtrasTableOutgoing = {
queryParams: {
configuration: outgoingConfig,
view: ViewMode.Table
view: ViewMode.Table,
},
};
component.navigateToSelectedSearchConfig(searchConfig);

View File

@@ -1,7 +1,11 @@
import { Component, Input } from '@angular/core';
import { AdminNotifyMetricsRow } from './admin-notify-metrics.model';
import {
Component,
Input,
} from '@angular/core';
import { Router } from '@angular/router';
import { ViewMode } from '../../../core/shared/view-mode.model';
import { AdminNotifyMetricsRow } from './admin-notify-metrics.model';
@Component({
selector: 'ds-admin-notify-metrics',
@@ -33,7 +37,7 @@ export class AdminNotifyMetricsComponent {
this.router.navigate([this.adminSearchPath], {
queryParams: {
configuration: searchConfig,
view: ViewMode.ListElement
view: ViewMode.ListElement,
},
});
@@ -46,7 +50,7 @@ export class AdminNotifyMetricsComponent {
this.router.navigate([`${this.router.url}${selectedPath}`], {
queryParams: {
configuration: searchConfig,
view: ViewMode.Table
view: ViewMode.Table,
},
});
}

View File

@@ -1,26 +1,32 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AdminNotifySearchResultComponent } from './admin-notify-search-result.component';
import { AdminNotifyMessagesService } from '../services/admin-notify-messages.service';
import { ObjectCacheService } from '../../../core/cache/object-cache.service';
import { RequestService } from '../../../core/data/request.service';
import { HALEndpointService } from '../../../core/shared/hal-endpoint.service';
import { RemoteDataBuildService } from '../../../core/cache/builders/remote-data-build.service';
import { cold } from 'jasmine-marbles';
import { ConfigurationProperty } from '../../../core/shared/configuration-property.model';
import { RouteService } from '../../../core/services/route.service';
import { routeServiceStub } from '../../../shared/testing/route-service.stub';
import { ActivatedRoute } from '@angular/router';
import { RouterStub } from '../../../shared/testing/router.stub';
import { TranslateModule } from '@ngx-translate/core';
import { of as observableOf, of } from 'rxjs';
import { AdminNotifyMessage } from '../models/admin-notify-message.model';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { AdminNotifyDetailModalComponent } from '../admin-notify-detail-modal/admin-notify-detail-modal.component';
import { SearchConfigurationService } from '../../../core/shared/search/search-configuration.service';
import { SEARCH_CONFIG_SERVICE } from '../../../my-dspace-page/my-dspace-page.component';
import { DatePipe } from '@angular/common';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import {
ComponentFixture,
TestBed,
} from '@angular/core/testing';
import { ActivatedRoute } from '@angular/router';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { TranslateModule } from '@ngx-translate/core';
import { cold } from 'jasmine-marbles';
import {
of as observableOf,
of,
} from 'rxjs';
import { RemoteDataBuildService } from '../../../core/cache/builders/remote-data-build.service';
import { ObjectCacheService } from '../../../core/cache/object-cache.service';
import { RequestService } from '../../../core/data/request.service';
import { RouteService } from '../../../core/services/route.service';
import { ConfigurationProperty } from '../../../core/shared/configuration-property.model';
import { HALEndpointService } from '../../../core/shared/hal-endpoint.service';
import { SearchConfigurationService } from '../../../core/shared/search/search-configuration.service';
import { SEARCH_CONFIG_SERVICE } from '../../../my-dspace-page/my-dspace-page.component';
import { routeServiceStub } from '../../../shared/testing/route-service.stub';
import { RouterStub } from '../../../shared/testing/router.stub';
import { AdminNotifyDetailModalComponent } from '../admin-notify-detail-modal/admin-notify-detail-modal.component';
import { AdminNotifyMessage } from '../models/admin-notify-message.model';
import { AdminNotifyMessagesService } from '../services/admin-notify-messages.service';
import { AdminNotifySearchResultComponent } from './admin-notify-search-result.component';
export const mockAdminNotifyMessages = [
{
@@ -40,15 +46,15 @@ export const mockAdminNotifyMessages = [
'queueStatus': 3,
'_links': {
'self': {
'href': 'http://localhost:8080/server/api/ldn/messages/urn:uuid:5fb3af44-d4f8-4226-9475-2d09c2d8d9e0'
}
'href': 'http://localhost:8080/server/api/ldn/messages/urn:uuid:5fb3af44-d4f8-4226-9475-2d09c2d8d9e0',
},
},
'thumbnail': 'test',
'item': {},
'accessStatus': {},
'ldnService': 'NOTIFY inbox - Automatic service',
'relatedItem': 'test coar 2 demo',
'message': '{"@context":["https://www.w3.org/ns/activitystreams","https://purl.org/coar/notify"],"id":"urn:uuid:668f26e0-2e8d-4118-b0d2-ee713523bc45","type":["Reject","coar-notify:IngestAction"],"actor":{"id":"https://generic-service.com","type":["Service"],"name":"Generic Service"},"context":{"id":"https://dspace-coar.4science.cloud/handle/123456789/28","type":["Document"],"ietf:cite-as":"https://doi.org/10.4598/12123488"},"object":{"id":"https://dspace-coar.4science.cloud/handle/123456789/28","type":["Offer"]},"origin":{"id":"https://generic-service.com/system","type":["Service"],"inbox":"https://notify-inbox.info/inbox7"},"target":{"id":"https://some-organisation.org","type":["Organization"],"inbox":"https://dspace-coar.4science.cloud/server/ldn/inbox"},"inReplyTo":"urn:uuid:d9b4010a-f128-4815-abb2-83707a2ee9cf"}'
'message': '{"@context":["https://www.w3.org/ns/activitystreams","https://purl.org/coar/notify"],"id":"urn:uuid:668f26e0-2e8d-4118-b0d2-ee713523bc45","type":["Reject","coar-notify:IngestAction"],"actor":{"id":"https://generic-service.com","type":["Service"],"name":"Generic Service"},"context":{"id":"https://dspace-coar.4science.cloud/handle/123456789/28","type":["Document"],"ietf:cite-as":"https://doi.org/10.4598/12123488"},"object":{"id":"https://dspace-coar.4science.cloud/handle/123456789/28","type":["Offer"]},"origin":{"id":"https://generic-service.com/system","type":["Service"],"inbox":"https://notify-inbox.info/inbox7"},"target":{"id":"https://some-organisation.org","type":["Organization"],"inbox":"https://dspace-coar.4science.cloud/server/ldn/inbox"},"inReplyTo":"urn:uuid:d9b4010a-f128-4815-abb2-83707a2ee9cf"}',
},
{
'type': 'message',
@@ -67,16 +73,16 @@ export const mockAdminNotifyMessages = [
'queueStatus': 6,
'_links': {
'self': {
'href': 'http://localhost:8080/server/api/ldn/messages/urn:uuid:544c8777-e826-4810-a625-3e394cc3660d'
}
'href': 'http://localhost:8080/server/api/ldn/messages/urn:uuid:544c8777-e826-4810-a625-3e394cc3660d',
},
},
'thumbnail': {},
'item': {},
'accessStatus': {},
'ldnService': 'NOTIFY inbox - Automatic service',
'relatedItem': 'test coar demo',
'message': '{"@context":["https://www.w3.org/ns/activitystreams","https://purl.org/coar/notify"],"id":"urn:uuid:668f26e0-2e8d-4118-b0d2-ee713523bc45","type":["Reject","coar-notify:IngestAction"],"actor":{"id":"https://generic-service.com","type":["Service"],"name":"Generic Service"},"context":{"id":"https://dspace-coar.4science.cloud/handle/123456789/28","type":["Document"],"ietf:cite-as":"https://doi.org/10.4598/12123488"},"object":{"id":"https://dspace-coar.4science.cloud/handle/123456789/28","type":["Offer"]},"origin":{"id":"https://generic-service.com/system","type":["Service"],"inbox":"https://notify-inbox.info/inbox7"},"target":{"id":"https://some-organisation.org","type":["Organization"],"inbox":"https://dspace-coar.4science.cloud/server/ldn/inbox"},"inReplyTo":"urn:uuid:d9b4010a-f128-4815-abb2-83707a2ee9cf"}'
}
'message': '{"@context":["https://www.w3.org/ns/activitystreams","https://purl.org/coar/notify"],"id":"urn:uuid:668f26e0-2e8d-4118-b0d2-ee713523bc45","type":["Reject","coar-notify:IngestAction"],"actor":{"id":"https://generic-service.com","type":["Service"],"name":"Generic Service"},"context":{"id":"https://dspace-coar.4science.cloud/handle/123456789/28","type":["Document"],"ietf:cite-as":"https://doi.org/10.4598/12123488"},"object":{"id":"https://dspace-coar.4science.cloud/handle/123456789/28","type":["Offer"]},"origin":{"id":"https://generic-service.com/system","type":["Service"],"inbox":"https://notify-inbox.info/inbox7"},"target":{"id":"https://some-organisation.org","type":["Organization"],"inbox":"https://dspace-coar.4science.cloud/server/ldn/inbox"},"inReplyTo":"urn:uuid:d9b4010a-f128-4815-abb2-83707a2ee9cf"}',
},
] as unknown as AdminNotifyMessage[];
describe('AdminNotifySearchResultComponent', () => {
let component: AdminNotifySearchResultComponent;
@@ -92,12 +98,12 @@ describe('AdminNotifySearchResultComponent', () => {
const testObject = {
uuid: 'test-property',
name: 'test-property',
values: ['value-1', 'value-2']
values: ['value-1', 'value-2'],
} as ConfigurationProperty;
beforeEach(async () => {
halService = jasmine.createSpyObj('halService', {
getEndpoint: cold('a', { a: '' })
getEndpoint: cold('a', { a: '' }),
});
adminNotifyMessageService = jasmine.createSpyObj('adminNotifyMessageService', {
getDetailedMessages: of(mockAdminNotifyMessages),
@@ -105,18 +111,18 @@ describe('AdminNotifySearchResultComponent', () => {
});
requestService = jasmine.createSpyObj('requestService', {
generateRequestId: requestUUID,
send: true
send: true,
});
rdbService = jasmine.createSpyObj('rdbService', {
buildSingle: cold('a', {
a: {
payload: testObject
}
})
payload: testObject,
},
}),
});
searchConfigService = jasmine.createSpyObj('searchConfigService', {
getCurrentConfiguration: of('NOTIFY.outgoing')
getCurrentConfiguration: of('NOTIFY.outgoing'),
});
objectCache = {} as ObjectCacheService;
@@ -133,9 +139,9 @@ describe('AdminNotifySearchResultComponent', () => {
{ provide: RequestService, useValue: requestService },
{ provide: RemoteDataBuildService, useValue: rdbService },
{ provide: SEARCH_CONFIG_SERVICE, useValue: searchConfigService },
DatePipe
DatePipe,
],
schemas: [NO_ERRORS_SCHEMA]
schemas: [NO_ERRORS_SCHEMA],
})
.compileComponents();

View File

@@ -1,22 +1,27 @@
import { Component, Inject, OnDestroy, OnInit } from '@angular/core';
import { AdminNotifySearchResult } from '../models/admin-notify-message-search-result.model';
import { ViewMode } from '../../../core/shared/view-mode.model';
import { Context } from '../../../core/shared/context.model';
import { AdminNotifyMessage } from '../models/admin-notify-message.model';
import {
tabulatableObjectsComponent
} from '../../../shared/object-collection/shared/tabulatable-objects/tabulatable-objects.decorator';
import {
TabulatableResultListElementsComponent
} from '../../../shared/object-list/search-result-list-element/tabulatable-search-result/tabulatable-result-list-elements.component';
import { PaginatedList } from '../../../core/data/paginated-list.model';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { AdminNotifyDetailModalComponent } from '../admin-notify-detail-modal/admin-notify-detail-modal.component';
import { BehaviorSubject, Subscription } from 'rxjs';
import { AdminNotifyMessagesService } from '../services/admin-notify-messages.service';
import { SearchConfigurationService } from '../../../core/shared/search/search-configuration.service';
import { SEARCH_CONFIG_SERVICE } from '../../../my-dspace-page/my-dspace-page.component';
import { DatePipe } from '@angular/common';
import {
Component,
Inject,
OnDestroy,
OnInit,
} from '@angular/core';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import {
BehaviorSubject,
Subscription,
} from 'rxjs';
import { PaginatedList } from '../../../core/data/paginated-list.model';
import { Context } from '../../../core/shared/context.model';
import { SearchConfigurationService } from '../../../core/shared/search/search-configuration.service';
import { ViewMode } from '../../../core/shared/view-mode.model';
import { SEARCH_CONFIG_SERVICE } from '../../../my-dspace-page/my-dspace-page.component';
import { tabulatableObjectsComponent } from '../../../shared/object-collection/shared/tabulatable-objects/tabulatable-objects.decorator';
import { TabulatableResultListElementsComponent } from '../../../shared/object-list/search-result-list-element/tabulatable-search-result/tabulatable-result-list-elements.component';
import { AdminNotifyDetailModalComponent } from '../admin-notify-detail-modal/admin-notify-detail-modal.component';
import { AdminNotifyMessage } from '../models/admin-notify-message.model';
import { AdminNotifySearchResult } from '../models/admin-notify-message-search-result.model';
import { AdminNotifyMessagesService } from '../services/admin-notify-messages.service';
@tabulatableObjectsComponent(PaginatedList<AdminNotifySearchResult>, ViewMode.Table, Context.CoarNotify)
@Component({
@@ -25,9 +30,9 @@ import { DatePipe } from '@angular/common';
providers: [
{
provide: SEARCH_CONFIG_SERVICE,
useClass: SearchConfigurationService
}
]
useClass: SearchConfigurationService,
},
],
})
/**
* Component for visualization in table format of the search results related to the AdminNotifyDashboardComponent
@@ -47,7 +52,7 @@ export class AdminNotifySearchResultComponent extends TabulatableResultListEleme
'QUEUE_STATUS_UNTRUSTED',
'QUEUE_STATUS_UNTRUSTED_IP',
'QUEUE_STATUS_FAILED',
'QUEUE_STATUS_UNMAPPED_ACTION'
'QUEUE_STATUS_UNMAPPED_ACTION',
];
@@ -77,7 +82,7 @@ export class AdminNotifySearchResultComponent extends TabulatableResultListEleme
'queueAttempts',
'queueLastStartTime',
'queueStatusLabel',
'queueTimeout'
'queueTimeout',
];
/**
@@ -101,7 +106,7 @@ export class AdminNotifySearchResultComponent extends TabulatableResultListEleme
this.subs.push(this.searchConfigService.getCurrentConfiguration('')
.subscribe(configuration => {
this.isInbound = configuration.startsWith('NOTIFY.incoming');
})
}),
);
}
@@ -138,8 +143,8 @@ export class AdminNotifySearchResultComponent extends TabulatableResultListEleme
this.adminNotifyMessagesService.reprocessMessage(message, this.messagesSubject$)
.subscribe(response => {
this.messagesSubject$.next(response);
}
)
},
),
);
}

View File

@@ -1,7 +1,6 @@
import { AdminNotifyMessage } from './admin-notify-message.model';
import { searchResultFor } from '../../../shared/search/search-result-element-decorator';
import { SearchResult } from '../../../shared/search/models/search-result.model';
import { searchResultFor } from '../../../shared/search/search-result-element-decorator';
import { AdminNotifyMessage } from './admin-notify-message.model';
@searchResultFor(AdminNotifyMessage)
export class AdminNotifySearchResult extends SearchResult<AdminNotifyMessage> {

View File

@@ -1,11 +1,17 @@
import { autoserialize, deserialize, inheritSerialization } from 'cerialize';
import {
autoserialize,
deserialize,
inheritSerialization,
} from 'cerialize';
import { Observable } from 'rxjs';
import { typedObject } from '../../../core/cache/builders/build-decorators';
import { ADMIN_NOTIFY_MESSAGE } from './admin-notify-message.resource-type';
import { excludeFromEquals } from '../../../core/utilities/equals.decorators';
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
import { GenericConstructor } from '../../../core/shared/generic-constructor';
import { excludeFromEquals } from '../../../core/utilities/equals.decorators';
import { ListableObject } from '../../../shared/object-collection/shared/listable-object.model';
import { Observable } from 'rxjs';
import { ADMIN_NOTIFY_MESSAGE } from './admin-notify-message.resource-type';
/**
* A message that includes admin notify info
*/

View File

@@ -1,23 +1,26 @@
import { deepClone } from 'fast-json-patch';
import { cold } from 'jasmine-marbles';
import { AdminNotifyMessagesService } from './admin-notify-messages.service';
import { RequestService } from '../../../core/data/request.service';
import {
BehaviorSubject,
of,
} from 'rxjs';
import { take } from 'rxjs/operators';
import { RemoteDataBuildService } from '../../../core/cache/builders/remote-data-build.service';
import { ObjectCacheService } from '../../../core/cache/object-cache.service';
import { RestResponse } from '../../../core/cache/response.models';
import { ItemDataService } from '../../../core/data/item-data.service';
import { RemoteData } from '../../../core/data/remote-data';
import { RequestService } from '../../../core/data/request.service';
import { RequestEntry } from '../../../core/data/request-entry.model';
import { RequestEntryState } from '../../../core/data/request-entry-state.model';
import { HALEndpointService } from '../../../core/shared/hal-endpoint.service';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { LdnServicesService } from '../../admin-ldn-services/ldn-services-data/ldn-services-data.service';
import { ItemDataService } from '../../../core/data/item-data.service';
import { RequestEntry } from '../../../core/data/request-entry.model';
import { RestResponse } from '../../../core/cache/response.models';
import { BehaviorSubject, of } from 'rxjs';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
import { RemoteData } from '../../../core/data/remote-data';
import { RequestEntryState } from '../../../core/data/request-entry-state.model';
import {
mockAdminNotifyMessages} from '../admin-notify-search-result/admin-notify-search-result.component.spec';
import { take } from 'rxjs/operators';
import { deepClone } from 'fast-json-patch';
import { LdnServicesService } from '../../admin-ldn-services/ldn-services-data/ldn-services-data.service';
import { mockAdminNotifyMessages } from '../admin-notify-search-result/admin-notify-search-result.component.spec';
import { AdminNotifyMessage } from '../models/admin-notify-message.model';
import { AdminNotifyMessagesService } from './admin-notify-messages.service';
describe('AdminNotifyMessagesService test', () => {
let service: AdminNotifyMessagesService;
@@ -47,7 +50,7 @@ describe('AdminNotifyMessagesService test', () => {
halService,
notificationsService,
ldnServicesService,
itemDataService
itemDataService,
);
}
@@ -69,13 +72,13 @@ describe('AdminNotifyMessagesService test', () => {
});
halService = jasmine.createSpyObj('halService', {
getEndpoint: of(endpointURL)
getEndpoint: of(endpointURL),
});
rdbService = jasmine.createSpyObj('rdbService', {
buildSingle: createSuccessfulRemoteDataObject$({}, 500),
buildList: cold('a', { a: remoteDataMocks.Success }),
buildFromRequestUUID: createSuccessfulRemoteDataObject$(mockMessages)
buildFromRequestUUID: createSuccessfulRemoteDataObject$(mockMessages),
});
ldnServicesService = jasmine.createSpyObj('ldnServicesService', {

View File

@@ -1,20 +1,35 @@
import { Injectable } from '@angular/core';
import {dataService} from '../../../core/data/base/data-service.decorator';
import {IdentifiableDataService} from '../../../core/data/base/identifiable-data.service';
import {RequestService} from '../../../core/data/request.service';
import {
BehaviorSubject,
from,
Observable,
of,
scan,
} from 'rxjs';
import {
map,
mergeMap,
switchMap,
tap,
} from 'rxjs/operators';
import { RemoteDataBuildService } from '../../../core/cache/builders/remote-data-build.service';
import { ObjectCacheService } from '../../../core/cache/object-cache.service';
import {HALEndpointService} from '../../../core/shared/hal-endpoint.service';
import {NotificationsService} from '../../../shared/notifications/notifications.service';
import { BehaviorSubject, from, Observable, of, scan } from 'rxjs';
import { ADMIN_NOTIFY_MESSAGE } from '../models/admin-notify-message.resource-type';
import { AdminNotifyMessage } from '../models/admin-notify-message.model';
import { map, mergeMap, switchMap, tap } from 'rxjs/operators';
import { getAllSucceededRemoteDataPayload, getFirstCompletedRemoteData } from '../../../core/shared/operators';
import { LdnServicesService } from '../../admin-ldn-services/ldn-services-data/ldn-services-data.service';
import { dataService } from '../../../core/data/base/data-service.decorator';
import { IdentifiableDataService } from '../../../core/data/base/identifiable-data.service';
import { ItemDataService } from '../../../core/data/item-data.service';
import { PostRequest } from '../../../core/data/request.models';
import { RequestService } from '../../../core/data/request.service';
import { RestRequest } from '../../../core/data/rest-request.model';
import { HALEndpointService } from '../../../core/shared/hal-endpoint.service';
import {
getAllSucceededRemoteDataPayload,
getFirstCompletedRemoteData,
} from '../../../core/shared/operators';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { LdnServicesService } from '../../admin-ldn-services/ldn-services-data/ldn-services-data.service';
import { AdminNotifyMessage } from '../models/admin-notify-message.model';
import { ADMIN_NOTIFY_MESSAGE } from '../models/admin-notify-message.resource-type';
/**
* Injectable service responsible for fetching/sending data from/to the REST API on the messages endpoint.
@@ -51,13 +66,13 @@ export class AdminNotifyMessagesService extends IdentifiableDataService<AdminNot
mergeMap(message =>
message.target || message.origin ? this.ldnServicesService.findById((message.target || message.origin).toString()).pipe(
getAllSucceededRemoteDataPayload(),
map(detail => ({...message, ldnService: detail.name}))
map(detail => ({ ...message, ldnService: detail.name })),
) : of(message),
),
mergeMap(message =>
message.object || message.context ? this.itemDataService.findById(message.object || message.context).pipe(
getAllSucceededRemoteDataPayload(),
map(detail => ({...message, relatedItem: detail.name}))
map(detail => ({ ...message, relatedItem: detail.name })),
) : of(message),
),
scan((acc: any, value: any) => [...acc, value], []),
@@ -93,7 +108,7 @@ export class AdminNotifyMessagesService extends IdentifiableDataService<AdminNot
messages[indexOfMessageToUpdate] = detailedReprocessedMessage;
return messages;
})
}),
)),
);
}

View File

@@ -1,9 +1,10 @@
import { MetadataRegistryComponent } from './metadata-registry/metadata-registry.component';
import { RouterModule } from '@angular/router';
import { NgModule } from '@angular/core';
import { MetadataSchemaComponent } from './metadata-schema/metadata-schema.component';
import { RouterModule } from '@angular/router';
import { I18nBreadcrumbResolver } from '../../core/breadcrumbs/i18n-breadcrumb.resolver';
import { BITSTREAMFORMATS_MODULE_PATH } from './admin-registries-routing-paths';
import { MetadataRegistryComponent } from './metadata-registry/metadata-registry.component';
import { MetadataSchemaComponent } from './metadata-schema/metadata-schema.component';
@NgModule({
imports: [
@@ -15,25 +16,25 @@ import { BITSTREAMFORMATS_MODULE_PATH } from './admin-registries-routing-paths';
children: [
{
path: '',
component: MetadataRegistryComponent
component: MetadataRegistryComponent,
},
{
path: ':schemaName',
resolve: { breadcrumb: I18nBreadcrumbResolver },
component: MetadataSchemaComponent,
data: {title: 'admin.registries.schema.title', breadcrumbKey: 'admin.registries.schema'}
}
]
data: { title: 'admin.registries.schema.title', breadcrumbKey: 'admin.registries.schema' },
},
],
},
{
path: BITSTREAMFORMATS_MODULE_PATH,
resolve: { breadcrumb: I18nBreadcrumbResolver },
loadChildren: () => import('./bitstream-formats/bitstream-formats.module')
.then((m) => m.BitstreamFormatsModule),
data: {title: 'admin.registries.bitstream-formats.title', breadcrumbKey: 'admin.registries.bitstream-formats'}
data: { title: 'admin.registries.bitstream-formats.title', breadcrumbKey: 'admin.registries.bitstream-formats' },
},
])
]
]),
],
})
export class AdminRegistriesRoutingModule {

View File

@@ -1,14 +1,15 @@
import { NgModule } from '@angular/core';
import { MetadataRegistryComponent } from './metadata-registry/metadata-registry.component';
import { AdminRegistriesRoutingModule } from './admin-registries-routing.module';
import { CommonModule } from '@angular/common';
import { MetadataSchemaComponent } from './metadata-schema/metadata-schema.component';
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { FormModule } from '../../shared/form/form.module';
import { SharedModule } from '../../shared/shared.module';
import { AdminRegistriesRoutingModule } from './admin-registries-routing.module';
import { BitstreamFormatsModule } from './bitstream-formats/bitstream-formats.module';
import { MetadataRegistryComponent } from './metadata-registry/metadata-registry.component';
import { MetadataSchemaFormComponent } from './metadata-registry/metadata-schema-form/metadata-schema-form.component';
import { MetadataFieldFormComponent } from './metadata-schema/metadata-field-form/metadata-field-form.component';
import { BitstreamFormatsModule } from './bitstream-formats/bitstream-formats.module';
import { FormModule } from '../../shared/form/form.module';
import { MetadataSchemaComponent } from './metadata-schema/metadata-schema.component';
@NgModule({
imports: [
@@ -17,14 +18,14 @@ import { FormModule } from '../../shared/form/form.module';
RouterModule,
BitstreamFormatsModule,
AdminRegistriesRoutingModule,
FormModule
FormModule,
],
declarations: [
MetadataRegistryComponent,
MetadataSchemaComponent,
MetadataSchemaFormComponent,
MetadataFieldFormComponent
]
MetadataFieldFormComponent,
],
})
export class AdminRegistriesModule {

View File

@@ -1,19 +1,27 @@
import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import {
ComponentFixture,
TestBed,
waitForAsync,
} from '@angular/core/testing';
import { Router } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { TranslateModule } from '@ngx-translate/core';
import { of as observableOf } from 'rxjs';
import { BitstreamFormatDataService } from '../../../../core/data/bitstream-format-data.service';
import { BitstreamFormatSupportLevel } from '../../../../core/shared/bitstream-format-support-level';
import { BitstreamFormat } from '../../../../core/shared/bitstream-format.model';
import { BitstreamFormatSupportLevel } from '../../../../core/shared/bitstream-format-support-level';
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
import {
createFailedRemoteDataObject$,
createSuccessfulRemoteDataObject$,
} from '../../../../shared/remote-data.utils';
import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service.stub';
import { RouterStub } from '../../../../shared/testing/router.stub';
import { AddBitstreamFormatComponent } from './add-bitstream-format.component';
import { createFailedRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../../../shared/remote-data.utils';
describe('AddBitstreamFormatComponent', () => {
let comp: AddBitstreamFormatComponent;
@@ -38,7 +46,7 @@ describe('AddBitstreamFormatComponent', () => {
notificationService = new NotificationsServiceStub();
bitstreamFormatDataService = jasmine.createSpyObj('bitstreamFormatDataService', {
createBitstreamFormat: createSuccessfulRemoteDataObject$({}),
clearBitStreamFormatRequests: observableOf(null)
clearBitStreamFormatRequests: observableOf(null),
});
TestBed.configureTestingModule({
@@ -49,7 +57,7 @@ describe('AddBitstreamFormatComponent', () => {
{ provide: NotificationsService, useValue: notificationService },
{ provide: BitstreamFormatDataService, useValue: bitstreamFormatDataService },
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
schemas: [CUSTOM_ELEMENTS_SCHEMA],
}).compileComponents();
};
@@ -78,7 +86,7 @@ describe('AddBitstreamFormatComponent', () => {
notificationService = new NotificationsServiceStub();
bitstreamFormatDataService = jasmine.createSpyObj('bitstreamFormatDataService', {
createBitstreamFormat: createFailedRemoteDataObject$('Error', 500),
clearBitStreamFormatRequests: observableOf(null)
clearBitStreamFormatRequests: observableOf(null),
});
TestBed.configureTestingModule({
@@ -89,7 +97,7 @@ describe('AddBitstreamFormatComponent', () => {
{ provide: NotificationsService, useValue: notificationService },
{ provide: BitstreamFormatDataService, useValue: bitstreamFormatDataService },
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
schemas: [CUSTOM_ELEMENTS_SCHEMA],
}).compileComponents();
}));
beforeEach(initBeforeEach);

View File

@@ -1,12 +1,13 @@
import { Router } from '@angular/router';
import { Component } from '@angular/core';
import { BitstreamFormat } from '../../../../core/shared/bitstream-format.model';
import { BitstreamFormatDataService } from '../../../../core/data/bitstream-format-data.service';
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
import { Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { getBitstreamFormatsModuleRoute } from '../../admin-registries-routing-paths';
import { BitstreamFormatDataService } from '../../../../core/data/bitstream-format-data.service';
import { RemoteData } from '../../../../core/data/remote-data';
import { BitstreamFormat } from '../../../../core/shared/bitstream-format.model';
import { getFirstCompletedRemoteData } from '../../../../core/shared/operators';
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
import { getBitstreamFormatsModuleRoute } from '../../admin-registries-routing-paths';
/**
* This component renders the page to create a new bitstream format.
@@ -44,7 +45,7 @@ export class AddBitstreamFormatComponent {
this.notificationService.error(this.translateService.get('admin.registries.bitstream-formats.create.failure.head'),
this.translateService.get('admin.registries.bitstream-formats.create.failure.content'));
}
}
},
);
}
}

View File

@@ -1,7 +1,8 @@
/* eslint-disable max-classes-per-file */
import { Action } from '@ngrx/store';
import { type } from '../../../shared/ngrx/type';
import { BitstreamFormat } from '../../../core/shared/bitstream-format.model';
import { type } from '../../../shared/ngrx/type';
/**
* For each action type in an action group, make a simple
@@ -15,7 +16,7 @@ export const BitstreamFormatsRegistryActionTypes = {
SELECT_FORMAT: type('dspace/bitstream-formats-registry/SELECT_FORMAT'),
DESELECT_FORMAT: type('dspace/bitstream-formats-registry/DESELECT_FORMAT'),
DESELECT_ALL_FORMAT: type('dspace/bitstream-formats-registry/DESELECT_ALL_FORMAT')
DESELECT_ALL_FORMAT: type('dspace/bitstream-formats-registry/DESELECT_ALL_FORMAT'),
};
/**

View File

@@ -1,11 +1,15 @@
import { Action } from '@ngrx/store';
import { BitstreamFormat } from '../../../core/shared/bitstream-format.model';
import { bitstreamFormatReducer, BitstreamFormatRegistryState } from './bitstream-format.reducers';
import {
BitstreamFormatsRegistryDeselectAction,
BitstreamFormatsRegistryDeselectAllAction,
BitstreamFormatsRegistrySelectAction
BitstreamFormatsRegistrySelectAction,
} from './bitstream-format.actions';
import {
bitstreamFormatReducer,
BitstreamFormatRegistryState,
} from './bitstream-format.reducers';
const bitstreamFormat1: BitstreamFormat = new BitstreamFormat();
bitstreamFormat1.id = 'test-uuid-1';
@@ -16,15 +20,15 @@ bitstreamFormat2.id = 'test-uuid-2';
bitstreamFormat2.shortDescription = 'test-short-2';
const initialState: BitstreamFormatRegistryState = {
selectedBitstreamFormats: []
selectedBitstreamFormats: [],
};
const bitstream1SelectedState: BitstreamFormatRegistryState = {
selectedBitstreamFormats: [bitstreamFormat1]
selectedBitstreamFormats: [bitstreamFormat1],
};
const bitstream1and2SelectedState: BitstreamFormatRegistryState = {
selectedBitstreamFormats: [bitstreamFormat1, bitstreamFormat2]
selectedBitstreamFormats: [bitstreamFormat1, bitstreamFormat2],
};
describe('BitstreamFormatReducer', () => {

View File

@@ -3,7 +3,7 @@ import {
BitstreamFormatsRegistryAction,
BitstreamFormatsRegistryActionTypes,
BitstreamFormatsRegistryDeselectAction,
BitstreamFormatsRegistrySelectAction
BitstreamFormatsRegistrySelectAction,
} from './bitstream-format.actions';
/**
@@ -32,21 +32,21 @@ export function bitstreamFormatReducer(state = initialState, action: BitstreamFo
case BitstreamFormatsRegistryActionTypes.SELECT_FORMAT: {
return Object.assign({}, state, {
selectedBitstreamFormats: [...state.selectedBitstreamFormats, (action as BitstreamFormatsRegistrySelectAction).bitstreamFormat]
selectedBitstreamFormats: [...state.selectedBitstreamFormats, (action as BitstreamFormatsRegistrySelectAction).bitstreamFormat],
});
}
case BitstreamFormatsRegistryActionTypes.DESELECT_FORMAT: {
return Object.assign({}, state, {
selectedBitstreamFormats: state.selectedBitstreamFormats.filter(
(selectedBitstreamFormats) => selectedBitstreamFormats !== (action as BitstreamFormatsRegistryDeselectAction).bitstreamFormat
)
(selectedBitstreamFormats) => selectedBitstreamFormats !== (action as BitstreamFormatsRegistryDeselectAction).bitstreamFormat,
),
});
}
case BitstreamFormatsRegistryActionTypes.DESELECT_ALL_FORMAT: {
return Object.assign({}, state, {
selectedBitstreamFormats: []
selectedBitstreamFormats: [],
});
}
default:

View File

@@ -1,10 +1,11 @@
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { I18nBreadcrumbResolver } from '../../../core/breadcrumbs/i18n-breadcrumb.resolver';
import { AddBitstreamFormatComponent } from './add-bitstream-format/add-bitstream-format.component';
import { BitstreamFormatsComponent } from './bitstream-formats.component';
import { BitstreamFormatsResolver } from './bitstream-formats.resolver';
import { EditBitstreamFormatComponent } from './edit-bitstream-format/edit-bitstream-format.component';
import { BitstreamFormatsComponent } from './bitstream-formats.component';
import { AddBitstreamFormatComponent } from './add-bitstream-format/add-bitstream-format.component';
import { I18nBreadcrumbResolver } from '../../../core/breadcrumbs/i18n-breadcrumb.resolver';
const BITSTREAMFORMAT_EDIT_PATH = ':id/edit';
const BITSTREAMFORMAT_ADD_PATH = 'add';
@@ -14,28 +15,28 @@ const BITSTREAMFORMAT_ADD_PATH = 'add';
RouterModule.forChild([
{
path: '',
component: BitstreamFormatsComponent
component: BitstreamFormatsComponent,
},
{
path: BITSTREAMFORMAT_ADD_PATH,
resolve: { breadcrumb: I18nBreadcrumbResolver },
component: AddBitstreamFormatComponent,
data: {breadcrumbKey: 'admin.registries.bitstream-formats.create'}
data: { breadcrumbKey: 'admin.registries.bitstream-formats.create' },
},
{
path: BITSTREAMFORMAT_EDIT_PATH,
component: EditBitstreamFormatComponent,
resolve: {
bitstreamFormat: BitstreamFormatsResolver,
breadcrumb: I18nBreadcrumbResolver
breadcrumb: I18nBreadcrumbResolver,
},
data: {breadcrumbKey: 'admin.registries.bitstream-formats.edit'}
data: { breadcrumbKey: 'admin.registries.bitstream-formats.edit' },
},
])
]),
],
providers: [
BitstreamFormatsResolver,
]
],
})
export class BitstreamFormatsRoutingModule {

View File

@@ -47,7 +47,7 @@
</table>
</div>
</ds-pagination>
<div *ngIf="(bitstreamFormats | async)?.payload?.totalElements == 0" class="alert alert-info" role="alert">
<div *ngIf="(bitstreamFormats | async)?.payload?.totalElements === 0" class="alert alert-info" role="alert">
{{'admin.registries.bitstream-formats.no-items' | translate}}
</div>

View File

@@ -1,31 +1,40 @@
import { BitstreamFormatsComponent } from './bitstream-formats.component';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { of as observableOf } from 'rxjs';
import { CommonModule } from '@angular/common';
import { RouterTestingModule } from '@angular/router/testing';
import { TranslateModule } from '@ngx-translate/core';
import {
ComponentFixture,
TestBed,
waitForAsync,
} from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { PaginationComponent } from '../../../shared/pagination/pagination.component';
import { RouterTestingModule } from '@angular/router/testing';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { EnumKeysPipe } from '../../../shared/utils/enum-keys-pipe';
import { HostWindowService } from '../../../shared/host-window.service';
import { HostWindowServiceStub } from '../../../shared/testing/host-window-service.stub';
import { TranslateModule } from '@ngx-translate/core';
import {
cold,
getTestScheduler,
hot,
} from 'jasmine-marbles';
import { of as observableOf } from 'rxjs';
import { TestScheduler } from 'rxjs/testing';
import { BitstreamFormatDataService } from '../../../core/data/bitstream-format-data.service';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub';
import { PaginationService } from '../../../core/pagination/pagination.service';
import { BitstreamFormat } from '../../../core/shared/bitstream-format.model';
import { BitstreamFormatSupportLevel } from '../../../core/shared/bitstream-format-support-level';
import { cold, getTestScheduler, hot } from 'jasmine-marbles';
import { TestScheduler } from 'rxjs/testing';
import { HostWindowService } from '../../../shared/host-window.service';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { PaginationComponent } from '../../../shared/pagination/pagination.component';
import {
createFailedRemoteDataObject$,
createNoContentRemoteDataObject$,
createSuccessfulRemoteDataObject,
createSuccessfulRemoteDataObject$,
createFailedRemoteDataObject$
} from '../../../shared/remote-data.utils';
import { createPaginatedList } from '../../../shared/testing/utils.test';
import { PaginationService } from '../../../core/pagination/pagination.service';
import { HostWindowServiceStub } from '../../../shared/testing/host-window-service.stub';
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service.stub';
import { PaginationServiceStub } from '../../../shared/testing/pagination-service.stub';
import { createPaginatedList } from '../../../shared/testing/utils.test';
import { EnumKeysPipe } from '../../../shared/utils/enum-keys-pipe';
import { BitstreamFormatsComponent } from './bitstream-formats.component';
describe('BitstreamFormatsComponent', () => {
let comp: BitstreamFormatsComponent;
@@ -79,7 +88,7 @@ describe('BitstreamFormatsComponent', () => {
bitstreamFormat1,
bitstreamFormat2,
bitstreamFormat3,
bitstreamFormat4
bitstreamFormat4,
];
const mockFormatsRD = createSuccessfulRemoteDataObject(createPaginatedList(mockFormatsList));
@@ -96,7 +105,7 @@ describe('BitstreamFormatsComponent', () => {
deselectBitstreamFormat: {},
deselectAllBitstreamFormats: {},
delete: createSuccessfulRemoteDataObject$({}),
clearBitStreamFormatRequests: observableOf('cleared')
clearBitStreamFormatRequests: observableOf('cleared'),
});
paginationService = new PaginationServiceStub();
@@ -108,8 +117,8 @@ describe('BitstreamFormatsComponent', () => {
{ provide: BitstreamFormatDataService, useValue: bitstreamFormatService },
{ provide: HostWindowService, useValue: new HostWindowServiceStub(0) },
{ provide: NotificationsService, useValue: notificationsServiceStub },
{ provide: PaginationService, useValue: paginationService }
]
{ provide: PaginationService, useValue: paginationService },
],
}).compileComponents();
};
@@ -224,7 +233,7 @@ describe('BitstreamFormatsComponent', () => {
deselectBitstreamFormat: {},
deselectAllBitstreamFormats: {},
delete: createNoContentRemoteDataObject$(),
clearBitStreamFormatRequests: observableOf('cleared')
clearBitStreamFormatRequests: observableOf('cleared'),
});
paginationService = new PaginationServiceStub();
@@ -236,10 +245,10 @@ describe('BitstreamFormatsComponent', () => {
{ provide: BitstreamFormatDataService, useValue: bitstreamFormatService },
{ provide: HostWindowService, useValue: new HostWindowServiceStub(0) },
{ provide: NotificationsService, useValue: notificationsServiceStub },
{ provide: PaginationService, useValue: paginationService }
]
{ provide: PaginationService, useValue: paginationService },
],
}).compileComponents();
}
},
));
beforeEach(initBeforeEach);
@@ -273,7 +282,7 @@ describe('BitstreamFormatsComponent', () => {
deselectBitstreamFormat: {},
deselectAllBitstreamFormats: {},
delete: createFailedRemoteDataObject$(),
clearBitStreamFormatRequests: observableOf('cleared')
clearBitStreamFormatRequests: observableOf('cleared'),
});
paginationService = new PaginationServiceStub();
@@ -285,10 +294,10 @@ describe('BitstreamFormatsComponent', () => {
{ provide: BitstreamFormatDataService, useValue: bitstreamFormatService },
{ provide: HostWindowService, useValue: new HostWindowServiceStub(0) },
{ provide: NotificationsService, useValue: notificationsServiceStub },
{ provide: PaginationService, useValue: paginationService }
]
{ provide: PaginationService, useValue: paginationService },
],
}).compileComponents();
}
},
));
beforeEach(initBeforeEach);

View File

@@ -1,25 +1,39 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { combineLatest as observableCombineLatest, Observable} from 'rxjs';
import { RemoteData } from '../../../core/data/remote-data';
import { PaginatedList } from '../../../core/data/paginated-list.model';
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
import { BitstreamFormat } from '../../../core/shared/bitstream-format.model';
import { BitstreamFormatDataService } from '../../../core/data/bitstream-format-data.service';
import { map, mergeMap, switchMap, take, toArray } from 'rxjs/operators';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import {
Component,
OnDestroy,
OnInit,
} from '@angular/core';
import { Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { NoContent } from '../../../core/shared/NoContent.model';
import { PaginationService } from '../../../core/pagination/pagination.service';
import {
combineLatest as observableCombineLatest,
Observable,
} from 'rxjs';
import {
map,
mergeMap,
switchMap,
take,
toArray,
} from 'rxjs/operators';
import { BitstreamFormatDataService } from '../../../core/data/bitstream-format-data.service';
import { FindListOptions } from '../../../core/data/find-list-options.model';
import { PaginatedList } from '../../../core/data/paginated-list.model';
import { RemoteData } from '../../../core/data/remote-data';
import { PaginationService } from '../../../core/pagination/pagination.service';
import { BitstreamFormat } from '../../../core/shared/bitstream-format.model';
import { NoContent } from '../../../core/shared/NoContent.model';
import { getFirstCompletedRemoteData } from '../../../core/shared/operators';
import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
/**
* This component renders a list of bitstream formats
*/
@Component({
selector: 'ds-bitstream-formats',
templateUrl: './bitstream-formats.component.html'
templateUrl: './bitstream-formats.component.html',
})
export class BitstreamFormatsComponent implements OnInit, OnDestroy {
@@ -35,7 +49,7 @@ export class BitstreamFormatsComponent implements OnInit, OnDestroy {
pageConfig: PaginationComponentOptions = Object.assign(new PaginationComponentOptions(), {
id: 'rbp',
pageSize: 20,
pageSizeOptions: [20, 40, 60, 80, 100]
pageSizeOptions: [20, 40, 60, 80, 100],
});
constructor(private notificationsService: NotificationsService,
@@ -64,7 +78,7 @@ export class BitstreamFormatsComponent implements OnInit, OnDestroy {
map((response: RemoteData<NoContent>) => response.hasSucceeded),
)),
// wait for all responses to come in and return them as a single array
toArray()
toArray(),
).subscribe((results: boolean[]) => {
// Count the number of succeeded and failed deletions
const successResponses = results.filter((result: boolean) => result);
@@ -101,7 +115,7 @@ export class BitstreamFormatsComponent implements OnInit, OnDestroy {
return this.bitstreamFormatService.getSelectedBitstreamFormats().pipe(
map((bitstreamFormats: BitstreamFormat[]) => {
return bitstreamFormats.find((selectedFormat) => selectedFormat.id === bitstreamFormat.id) != null;
})
}),
);
}
@@ -127,7 +141,7 @@ export class BitstreamFormatsComponent implements OnInit, OnDestroy {
const messages = observableCombineLatest(
this.translateService.get(`${prefix}.${suffix}.head`),
this.translateService.get(`${prefix}.${suffix}.amount`, {amount: amount})
this.translateService.get(`${prefix}.${suffix}.amount`, { amount: amount }),
);
messages.subscribe(([head, content]) => {
@@ -144,7 +158,7 @@ export class BitstreamFormatsComponent implements OnInit, OnDestroy {
this.bitstreamFormats = this.paginationService.getFindListOptions(this.pageConfig.id, this.pageConfig).pipe(
switchMap((findListOptions: FindListOptions) => {
return this.bitstreamFormatService.findAll(findListOptions);
})
}),
);
}

View File

@@ -1,13 +1,14 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { BitstreamFormatsComponent } from './bitstream-formats.component';
import { SharedModule } from '../../../shared/shared.module';
import { FormatFormComponent } from './format-form/format-form.component';
import { EditBitstreamFormatComponent } from './edit-bitstream-format/edit-bitstream-format.component';
import { BitstreamFormatsRoutingModule } from './bitstream-formats-routing.module';
import { AddBitstreamFormatComponent } from './add-bitstream-format/add-bitstream-format.component';
import { FormModule } from '../../../shared/form/form.module';
import { SharedModule } from '../../../shared/shared.module';
import { AddBitstreamFormatComponent } from './add-bitstream-format/add-bitstream-format.component';
import { BitstreamFormatsComponent } from './bitstream-formats.component';
import { BitstreamFormatsRoutingModule } from './bitstream-formats-routing.module';
import { EditBitstreamFormatComponent } from './edit-bitstream-format/edit-bitstream-format.component';
import { FormatFormComponent } from './format-form/format-form.component';
@NgModule({
imports: [
@@ -15,14 +16,14 @@ import { FormModule } from '../../../shared/form/form.module';
SharedModule,
RouterModule,
BitstreamFormatsRoutingModule,
FormModule
FormModule,
],
declarations: [
BitstreamFormatsComponent,
EditBitstreamFormatComponent,
AddBitstreamFormatComponent,
FormatFormComponent
]
FormatFormComponent,
],
})
export class BitstreamFormatsModule {

View File

@@ -1,9 +1,14 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
import {
ActivatedRouteSnapshot,
Resolve,
RouterStateSnapshot,
} from '@angular/router';
import { Observable } from 'rxjs';
import { BitstreamFormatDataService } from '../../../core/data/bitstream-format-data.service';
import { RemoteData } from '../../../core/data/remote-data';
import { BitstreamFormat } from '../../../core/shared/bitstream-format.model';
import { BitstreamFormatDataService } from '../../../core/data/bitstream-format-data.service';
import { getFirstCompletedRemoteData } from '../../../core/shared/operators';
/**
@@ -24,7 +29,7 @@ export class BitstreamFormatsResolver implements Resolve<RemoteData<BitstreamFor
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<RemoteData<BitstreamFormat>> {
return this.bitstreamFormatDataService.findById(route.params.id)
.pipe(
getFirstCompletedRemoteData()
getFirstCompletedRemoteData(),
);
}
}

View File

@@ -1,24 +1,32 @@
import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { ActivatedRoute, Router } from '@angular/router';
import {
ComponentFixture,
TestBed,
waitForAsync,
} from '@angular/core/testing';
import {
ActivatedRoute,
Router,
} from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { TranslateModule } from '@ngx-translate/core';
import { of as observableOf } from 'rxjs';
import { BitstreamFormatDataService } from '../../../../core/data/bitstream-format-data.service';
import { RemoteData } from '../../../../core/data/remote-data';
import { BitstreamFormatSupportLevel } from '../../../../core/shared/bitstream-format-support-level';
import { BitstreamFormat } from '../../../../core/shared/bitstream-format.model';
import { BitstreamFormatSupportLevel } from '../../../../core/shared/bitstream-format-support-level';
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service.stub';
import { RouterStub } from '../../../../shared/testing/router.stub';
import { EditBitstreamFormatComponent } from './edit-bitstream-format.component';
import {
createFailedRemoteDataObject$,
createSuccessfulRemoteDataObject,
createSuccessfulRemoteDataObject$
createSuccessfulRemoteDataObject$,
} from '../../../../shared/remote-data.utils';
import { NotificationsServiceStub } from '../../../../shared/testing/notifications-service.stub';
import { RouterStub } from '../../../../shared/testing/router.stub';
import { EditBitstreamFormatComponent } from './edit-bitstream-format.component';
describe('EditBitstreamFormatComponent', () => {
let comp: EditBitstreamFormatComponent;
@@ -36,8 +44,8 @@ describe('EditBitstreamFormatComponent', () => {
const routeStub = {
data: observableOf({
bitstreamFormat: createSuccessfulRemoteDataObject(bitstreamFormat)
})
bitstreamFormat: createSuccessfulRemoteDataObject(bitstreamFormat),
}),
};
let router;
@@ -48,7 +56,7 @@ describe('EditBitstreamFormatComponent', () => {
router = new RouterStub();
notificationService = new NotificationsServiceStub();
bitstreamFormatDataService = jasmine.createSpyObj('bitstreamFormatDataService', {
updateBitstreamFormat: createSuccessfulRemoteDataObject$({})
updateBitstreamFormat: createSuccessfulRemoteDataObject$({}),
});
TestBed.configureTestingModule({
@@ -60,7 +68,7 @@ describe('EditBitstreamFormatComponent', () => {
{ provide: NotificationsService, useValue: notificationService },
{ provide: BitstreamFormatDataService, useValue: bitstreamFormatDataService },
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
schemas: [CUSTOM_ELEMENTS_SCHEMA],
}).compileComponents();
};
@@ -99,7 +107,7 @@ describe('EditBitstreamFormatComponent', () => {
router = new RouterStub();
notificationService = new NotificationsServiceStub();
bitstreamFormatDataService = jasmine.createSpyObj('bitstreamFormatDataService', {
updateBitstreamFormat: createFailedRemoteDataObject$('Error', 500)
updateBitstreamFormat: createFailedRemoteDataObject$('Error', 500),
});
TestBed.configureTestingModule({
@@ -111,7 +119,7 @@ describe('EditBitstreamFormatComponent', () => {
{ provide: NotificationsService, useValue: notificationService },
{ provide: BitstreamFormatDataService, useValue: bitstreamFormatDataService },
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
schemas: [CUSTOM_ELEMENTS_SCHEMA],
}).compileComponents();
}));
beforeEach(initBeforeEach);

View File

@@ -1,14 +1,21 @@
import { map } from 'rxjs/operators';
import { ActivatedRoute, Router } from '@angular/router';
import {
Component,
OnInit,
} from '@angular/core';
import {
ActivatedRoute,
Router,
} from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { Observable } from 'rxjs';
import { Component, OnInit } from '@angular/core';
import { map } from 'rxjs/operators';
import { BitstreamFormatDataService } from '../../../../core/data/bitstream-format-data.service';
import { RemoteData } from '../../../../core/data/remote-data';
import { BitstreamFormat } from '../../../../core/shared/bitstream-format.model';
import { BitstreamFormatDataService } from '../../../../core/data/bitstream-format-data.service';
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
import { TranslateService } from '@ngx-translate/core';
import { getBitstreamFormatsModuleRoute } from '../../admin-registries-routing-paths';
import { getFirstCompletedRemoteData } from '../../../../core/shared/operators';
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
import { getBitstreamFormatsModuleRoute } from '../../admin-registries-routing-paths';
/**
* This component renders the edit page of a bitstream format.
@@ -36,7 +43,7 @@ export class EditBitstreamFormatComponent implements OnInit {
ngOnInit(): void {
this.bitstreamFormatRD$ = this.route.data.pipe(
map((data) => data.bitstreamFormat as RemoteData<BitstreamFormat>)
map((data) => data.bitstreamFormat as RemoteData<BitstreamFormat>),
);
}
@@ -57,7 +64,7 @@ export class EditBitstreamFormatComponent implements OnInit {
this.notificationService.error('admin.registries.bitstream-formats.edit.failure.head',
'admin.registries.bitstream-formats.create.edit.content');
}
}
},
);
}
}

View File

@@ -1,17 +1,29 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { CommonModule } from '@angular/common';
import { RouterTestingModule } from '@angular/router/testing';
import { TranslateModule } from '@ngx-translate/core';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { RouterStub } from '../../../../shared/testing/router.stub';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import {
ComponentFixture,
TestBed,
waitForAsync,
} from '@angular/core/testing';
import {
FormsModule,
ReactiveFormsModule,
} from '@angular/forms';
import { Router } from '@angular/router';
import { FormatFormComponent } from './format-form.component';
import { RouterTestingModule } from '@angular/router/testing';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import {
DynamicCheckboxModel,
DynamicFormArrayModel,
DynamicInputModel,
} from '@ng-dynamic-forms/core';
import { TranslateModule } from '@ngx-translate/core';
import { BitstreamFormat } from '../../../../core/shared/bitstream-format.model';
import { BitstreamFormatSupportLevel } from '../../../../core/shared/bitstream-format-support-level';
import { DynamicCheckboxModel, DynamicFormArrayModel, DynamicInputModel } from '@ng-dynamic-forms/core';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { isEmpty } from '../../../../shared/empty.util';
import { RouterStub } from '../../../../shared/testing/router.stub';
import { FormatFormComponent } from './format-form.component';
describe('FormatFormComponent', () => {
let comp: FormatFormComponent;
@@ -45,7 +57,7 @@ describe('FormatFormComponent', () => {
providers: [
{ provide: Router, useValue: router },
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
schemas: [CUSTOM_ELEMENTS_SCHEMA],
}).compileComponents();
};

Some files were not shown because too many files have changed in this diff Show More