mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 18:14:17 +00:00
Merge branch 'main' into Removing-unnecessary-circular-dependencies
This commit is contained in:
@@ -79,6 +79,10 @@
|
|||||||
{
|
{
|
||||||
"replace": "src/environments/environment.ts",
|
"replace": "src/environments/environment.ts",
|
||||||
"with": "src/environments/environment.production.ts"
|
"with": "src/environments/environment.production.ts"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"replace": "src/config/store/devtools.ts",
|
||||||
|
"with": "src/config/store/devtools.prod.ts"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"optimization": true,
|
"optimization": true,
|
||||||
@@ -204,6 +208,10 @@
|
|||||||
{
|
{
|
||||||
"replace": "src/environments/environment.ts",
|
"replace": "src/environments/environment.ts",
|
||||||
"with": "src/environments/environment.production.ts"
|
"with": "src/environments/environment.production.ts"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"replace": "src/config/store/devtools.ts",
|
||||||
|
"with": "src/config/store/devtools.prod.ts"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@@ -237,7 +237,24 @@ describe('AdminSidebarComponent', () => {
|
|||||||
expect(menuService.addSection).toHaveBeenCalledWith(comp.menuID, jasmine.objectContaining({
|
expect(menuService.addSection).toHaveBeenCalledWith(comp.menuID, jasmine.objectContaining({
|
||||||
parentID: 'access_control', visible: false,
|
parentID: 'access_control', visible: false,
|
||||||
}));
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
// We check that the menu section has not been called with visible set to true
|
||||||
|
// The reason why we don't check if it has been called with visible set to false
|
||||||
|
// Is because the function does not get called unless a user is authorised
|
||||||
|
it('should not show the import section', () => {
|
||||||
|
expect(menuService.addSection).not.toHaveBeenCalledWith(comp.menuID, jasmine.objectContaining({
|
||||||
|
id: 'import', visible: true,
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
// We check that the menu section has not been called with visible set to true
|
||||||
|
// The reason why we don't check if it has been called with visible set to false
|
||||||
|
// Is because the function does not get called unless a user is authorised
|
||||||
|
it('should not show the export section', () => {
|
||||||
|
expect(menuService.addSection).not.toHaveBeenCalledWith(comp.menuID, jasmine.objectContaining({
|
||||||
|
id: 'export', visible: true,
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -268,6 +285,15 @@ describe('AdminSidebarComponent', () => {
|
|||||||
expect(menuService.addSection).toHaveBeenCalledWith(comp.menuID, jasmine.objectContaining({
|
expect(menuService.addSection).toHaveBeenCalledWith(comp.menuID, jasmine.objectContaining({
|
||||||
id: 'workflow', visible: true,
|
id: 'workflow', visible: true,
|
||||||
}));
|
}));
|
||||||
|
expect(menuService.addSection).toHaveBeenCalledWith(comp.menuID, jasmine.objectContaining({
|
||||||
|
id: 'workflow', visible: true,
|
||||||
|
}));
|
||||||
|
expect(menuService.addSection).toHaveBeenCalledWith(comp.menuID, jasmine.objectContaining({
|
||||||
|
id: 'import', visible: true,
|
||||||
|
}));
|
||||||
|
expect(menuService.addSection).toHaveBeenCalledWith(comp.menuID, jasmine.objectContaining({
|
||||||
|
id: 'export', visible: true,
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -1,9 +1,13 @@
|
|||||||
import { Component, HostListener, Injector, OnInit } from '@angular/core';
|
import { Component, HostListener, Injector, OnInit } from '@angular/core';
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||||
import { combineLatest, combineLatest as observableCombineLatest, Observable, BehaviorSubject } from 'rxjs';
|
import { combineLatest, combineLatest as observableCombineLatest, Observable, BehaviorSubject } from 'rxjs';
|
||||||
import { debounceTime, first, map, take, distinctUntilChanged, withLatestFrom } from 'rxjs/operators';
|
import { debounceTime, first, map, take, filter, distinctUntilChanged, withLatestFrom } from 'rxjs/operators';
|
||||||
import { AuthService } from '../../core/auth/auth.service';
|
import { AuthService } from '../../core/auth/auth.service';
|
||||||
import { ScriptDataService } from '../../core/data/processes/script-data.service';
|
import {
|
||||||
|
ScriptDataService,
|
||||||
|
METADATA_IMPORT_SCRIPT_NAME,
|
||||||
|
METADATA_EXPORT_SCRIPT_NAME
|
||||||
|
} from '../../core/data/processes/script-data.service';
|
||||||
import { slideHorizontal, slideSidebar } from '../../shared/animations/slide';
|
import { slideHorizontal, slideSidebar } from '../../shared/animations/slide';
|
||||||
import { CreateCollectionParentSelectorComponent } from '../../shared/dso-selector/modal-wrappers/create-collection-parent-selector/create-collection-parent-selector.component';
|
import { CreateCollectionParentSelectorComponent } from '../../shared/dso-selector/modal-wrappers/create-collection-parent-selector/create-collection-parent-selector.component';
|
||||||
import { CreateCommunityParentSelectorComponent } from '../../shared/dso-selector/modal-wrappers/create-community-parent-selector/create-community-parent-selector.component';
|
import { CreateCommunityParentSelectorComponent } from '../../shared/dso-selector/modal-wrappers/create-community-parent-selector/create-community-parent-selector.component';
|
||||||
@@ -322,19 +326,6 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
|
|||||||
*/
|
*/
|
||||||
createExportMenuSections() {
|
createExportMenuSections() {
|
||||||
const menuList = [
|
const menuList = [
|
||||||
/* Export */
|
|
||||||
{
|
|
||||||
id: 'export',
|
|
||||||
active: false,
|
|
||||||
visible: true,
|
|
||||||
model: {
|
|
||||||
type: MenuItemType.TEXT,
|
|
||||||
text: 'menu.section.export'
|
|
||||||
} as TextMenuItemModel,
|
|
||||||
icon: 'file-export',
|
|
||||||
index: 3,
|
|
||||||
shouldPersistOnRouteChange: true
|
|
||||||
},
|
|
||||||
// TODO: enable this menu item once the feature has been implemented
|
// TODO: enable this menu item once the feature has been implemented
|
||||||
// {
|
// {
|
||||||
// id: 'export_community',
|
// id: 'export_community',
|
||||||
@@ -379,12 +370,26 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
|
|||||||
|
|
||||||
observableCombineLatest(
|
observableCombineLatest(
|
||||||
this.authorizationService.isAuthorized(FeatureID.AdministratorOf),
|
this.authorizationService.isAuthorized(FeatureID.AdministratorOf),
|
||||||
// this.scriptDataService.scriptWithNameExistsAndCanExecute(METADATA_EXPORT_SCRIPT_NAME)
|
this.scriptDataService.scriptWithNameExistsAndCanExecute(METADATA_EXPORT_SCRIPT_NAME)
|
||||||
).pipe(
|
).pipe(
|
||||||
// TODO uncomment when #635 (https://github.com/DSpace/dspace-angular/issues/635) is fixed; otherwise even in production mode, the metadata export button is only available after a refresh (and not in dev mode)
|
filter(([authorized, metadataExportScriptExists]: boolean[]) => authorized && metadataExportScriptExists),
|
||||||
// filter(([authorized, metadataExportScriptExists]: boolean[]) => authorized && metadataExportScriptExists),
|
|
||||||
take(1)
|
take(1)
|
||||||
).subscribe(() => {
|
).subscribe(() => {
|
||||||
|
// Hides the export menu for unauthorised people
|
||||||
|
// If in the future more sub-menus are added,
|
||||||
|
// it should be reviewed if they need to be in this subscribe
|
||||||
|
this.menuService.addSection(this.menuID, {
|
||||||
|
id: 'export',
|
||||||
|
active: false,
|
||||||
|
visible: true,
|
||||||
|
model: {
|
||||||
|
type: MenuItemType.TEXT,
|
||||||
|
text: 'menu.section.export'
|
||||||
|
} as TextMenuItemModel,
|
||||||
|
icon: 'file-export',
|
||||||
|
index: 3,
|
||||||
|
shouldPersistOnRouteChange: true
|
||||||
|
});
|
||||||
this.menuService.addSection(this.menuID, {
|
this.menuService.addSection(this.menuID, {
|
||||||
id: 'export_metadata',
|
id: 'export_metadata',
|
||||||
parentID: 'export',
|
parentID: 'export',
|
||||||
@@ -408,18 +413,6 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
|
|||||||
*/
|
*/
|
||||||
createImportMenuSections() {
|
createImportMenuSections() {
|
||||||
const menuList = [
|
const menuList = [
|
||||||
/* Import */
|
|
||||||
{
|
|
||||||
id: 'import',
|
|
||||||
active: false,
|
|
||||||
visible: true,
|
|
||||||
model: {
|
|
||||||
type: MenuItemType.TEXT,
|
|
||||||
text: 'menu.section.import'
|
|
||||||
} as TextMenuItemModel,
|
|
||||||
icon: 'file-import',
|
|
||||||
index: 2
|
|
||||||
},
|
|
||||||
// TODO: enable this menu item once the feature has been implemented
|
// TODO: enable this menu item once the feature has been implemented
|
||||||
// {
|
// {
|
||||||
// id: 'import_batch',
|
// id: 'import_batch',
|
||||||
@@ -439,12 +432,25 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
|
|||||||
|
|
||||||
observableCombineLatest(
|
observableCombineLatest(
|
||||||
this.authorizationService.isAuthorized(FeatureID.AdministratorOf),
|
this.authorizationService.isAuthorized(FeatureID.AdministratorOf),
|
||||||
// this.scriptDataService.scriptWithNameExistsAndCanExecute(METADATA_IMPORT_SCRIPT_NAME)
|
this.scriptDataService.scriptWithNameExistsAndCanExecute(METADATA_IMPORT_SCRIPT_NAME)
|
||||||
).pipe(
|
).pipe(
|
||||||
// TODO uncomment when #635 (https://github.com/DSpace/dspace-angular/issues/635) is fixed
|
filter(([authorized, metadataImportScriptExists]: boolean[]) => authorized && metadataImportScriptExists),
|
||||||
// filter(([authorized, metadataImportScriptExists]: boolean[]) => authorized && metadataImportScriptExists),
|
|
||||||
take(1)
|
take(1)
|
||||||
).subscribe(() => {
|
).subscribe(() => {
|
||||||
|
// Hides the import menu for unauthorised people
|
||||||
|
// If in the future more sub-menus are added,
|
||||||
|
// it should be reviewed if they need to be in this subscribe
|
||||||
|
this.menuService.addSection(this.menuID, {
|
||||||
|
id: 'import',
|
||||||
|
active: false,
|
||||||
|
visible: true,
|
||||||
|
model: {
|
||||||
|
type: MenuItemType.TEXT,
|
||||||
|
text: 'menu.section.import'
|
||||||
|
} as TextMenuItemModel,
|
||||||
|
icon: 'file-import',
|
||||||
|
index: 2
|
||||||
|
});
|
||||||
this.menuService.addSection(this.menuID, {
|
this.menuService.addSection(this.menuID, {
|
||||||
id: 'import_metadata',
|
id: 'import_metadata',
|
||||||
parentID: 'import',
|
parentID: 'import',
|
||||||
|
@@ -8,7 +8,6 @@ import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
|||||||
import { EffectsModule } from '@ngrx/effects';
|
import { EffectsModule } from '@ngrx/effects';
|
||||||
import { RouterStateSerializer, StoreRouterConnectingModule } from '@ngrx/router-store';
|
import { RouterStateSerializer, StoreRouterConnectingModule } from '@ngrx/router-store';
|
||||||
import { MetaReducer, Store, StoreModule, USER_PROVIDED_META_REDUCERS } from '@ngrx/store';
|
import { MetaReducer, Store, StoreModule, USER_PROVIDED_META_REDUCERS } from '@ngrx/store';
|
||||||
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
|
|
||||||
import {
|
import {
|
||||||
DYNAMIC_ERROR_MESSAGES_MATCHER,
|
DYNAMIC_ERROR_MESSAGES_MATCHER,
|
||||||
DYNAMIC_MATCHER_PROVIDERS,
|
DYNAMIC_MATCHER_PROVIDERS,
|
||||||
@@ -61,6 +60,8 @@ import { ThemedAdminSidebarComponent } from './admin/admin-sidebar/themed-admin-
|
|||||||
import { APP_CONFIG, AppConfig } from '../config/app-config.interface';
|
import { APP_CONFIG, AppConfig } from '../config/app-config.interface';
|
||||||
import { NgxMaskModule } from 'ngx-mask';
|
import { NgxMaskModule } from 'ngx-mask';
|
||||||
|
|
||||||
|
import { StoreDevModules } from '../config/store/devtools';
|
||||||
|
|
||||||
export function getConfig() {
|
export function getConfig() {
|
||||||
return environment;
|
return environment;
|
||||||
}
|
}
|
||||||
@@ -96,15 +97,9 @@ const IMPORTS = [
|
|||||||
StoreModule.forRoot(appReducers, storeModuleConfig),
|
StoreModule.forRoot(appReducers, storeModuleConfig),
|
||||||
StoreRouterConnectingModule.forRoot(),
|
StoreRouterConnectingModule.forRoot(),
|
||||||
ThemedEntryComponentModule.withEntryComponents(),
|
ThemedEntryComponentModule.withEntryComponents(),
|
||||||
|
StoreDevModules,
|
||||||
];
|
];
|
||||||
|
|
||||||
IMPORTS.push(
|
|
||||||
StoreDevtoolsModule.instrument({
|
|
||||||
maxAge: 1000,
|
|
||||||
logOnly: environment.production,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
const PROVIDERS = [
|
const PROVIDERS = [
|
||||||
{
|
{
|
||||||
provide: APP_CONFIG,
|
provide: APP_CONFIG,
|
||||||
|
@@ -18,6 +18,8 @@ import { Observable } from 'rxjs';
|
|||||||
import { dataService } from '../../cache/builders/build-decorators';
|
import { dataService } from '../../cache/builders/build-decorators';
|
||||||
import { SCRIPT } from '../../../process-page/scripts/script.resource-type';
|
import { SCRIPT } from '../../../process-page/scripts/script.resource-type';
|
||||||
import { Process } from '../../../process-page/processes/process.model';
|
import { Process } from '../../../process-page/processes/process.model';
|
||||||
|
import { hasValue } from '../../../shared/empty.util';
|
||||||
|
import { getFirstCompletedRemoteData } from '../../shared/operators';
|
||||||
import { RestRequest } from '../rest-request.model';
|
import { RestRequest } from '../rest-request.model';
|
||||||
import { CoreState } from '../../core-state.model';
|
import { CoreState } from '../../core-state.model';
|
||||||
|
|
||||||
@@ -63,4 +65,16 @@ export class ScriptDataService extends DataService<Script> {
|
|||||||
});
|
});
|
||||||
return form;
|
return form;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether a script with given name exist; user needs to be allowed to execute script for this to to not throw a 401 Unauthorized
|
||||||
|
* @param scriptName script we want to check exists (and we can execute)
|
||||||
|
*/
|
||||||
|
public scriptWithNameExistsAndCanExecute(scriptName: string): Observable<boolean> {
|
||||||
|
return this.findById(scriptName).pipe(
|
||||||
|
getFirstCompletedRemoteData(),
|
||||||
|
map((rd: RemoteData<Script>) => {
|
||||||
|
return hasValue(rd.payload);
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,8 +1,10 @@
|
|||||||
|
|
||||||
<a class="nav-item nav-link"
|
<a class="nav-item nav-link"
|
||||||
[ngClass]="{ 'disabled': !hasLink }"
|
[ngClass]="{ 'disabled': !hasLink }"
|
||||||
[attr.aria-disabled]="!hasLink"
|
[attr.aria-disabled]="!hasLink"
|
||||||
[title]="item.text | translate"
|
[title]="item.text | translate"
|
||||||
[routerLink]="getRouterLink()"
|
[routerLink]="getRouterLink()"
|
||||||
|
[queryParams]="item.queryParams"
|
||||||
(click)="$event.stopPropagation()"
|
(click)="$event.stopPropagation()"
|
||||||
(keyup.space)="navigate($event)"
|
(keyup.space)="navigate($event)"
|
||||||
(keyup.enter)="navigate($event)"
|
(keyup.enter)="navigate($event)"
|
||||||
|
@@ -5,6 +5,7 @@ import { By } from '@angular/platform-browser';
|
|||||||
import { LinkMenuItemComponent } from './link-menu-item.component';
|
import { LinkMenuItemComponent } from './link-menu-item.component';
|
||||||
import { RouterLinkDirectiveStub } from '../../testing/router-link-directive.stub';
|
import { RouterLinkDirectiveStub } from '../../testing/router-link-directive.stub';
|
||||||
import { environment } from '../../../../environments/environment';
|
import { environment } from '../../../../environments/environment';
|
||||||
|
import { QueryParamsDirectiveStub } from '../../testing/query-params-directive.stub';
|
||||||
import { RouterStub } from '../../testing/router.stub';
|
import { RouterStub } from '../../testing/router.stub';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
@@ -14,19 +15,21 @@ describe('LinkMenuItemComponent', () => {
|
|||||||
let debugElement: DebugElement;
|
let debugElement: DebugElement;
|
||||||
let text;
|
let text;
|
||||||
let link;
|
let link;
|
||||||
|
let queryParams;
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
text = 'HELLO';
|
text = 'HELLO';
|
||||||
link = 'http://google.com';
|
link = 'http://google.com';
|
||||||
|
queryParams = {params: true};
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(waitForAsync(() => {
|
||||||
init();
|
init();
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [TranslateModule.forRoot()],
|
imports: [TranslateModule.forRoot()],
|
||||||
declarations: [LinkMenuItemComponent, RouterLinkDirectiveStub],
|
declarations: [LinkMenuItemComponent, RouterLinkDirectiveStub, QueryParamsDirectiveStub],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: 'itemModelProvider', useValue: { text: text, link: link } },
|
{ provide: 'itemModelProvider', useValue: { text: text, link: link, queryParams: queryParams } },
|
||||||
{ provide: Router, useValue: RouterStub },
|
{ provide: Router, useValue: RouterStub },
|
||||||
],
|
],
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
@@ -57,4 +60,12 @@ describe('LinkMenuItemComponent', () => {
|
|||||||
expect(routerLinkQuery.length).toBe(1);
|
expect(routerLinkQuery.length).toBe(1);
|
||||||
expect(routerLinkQuery[0].routerLink).toBe(environment.ui.nameSpace + link);
|
expect(routerLinkQuery[0].routerLink).toBe(environment.ui.nameSpace + link);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should have the right queryParams attribute', () => {
|
||||||
|
const queryDes = fixture.debugElement.queryAll(By.directive(QueryParamsDirectiveStub));
|
||||||
|
const routerParamsQuery = queryDes.map((de) => de.injector.get(QueryParamsDirectiveStub));
|
||||||
|
|
||||||
|
expect(routerParamsQuery.length).toBe(1);
|
||||||
|
expect(routerParamsQuery[0].queryParams).toBe(queryParams);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
import { MenuItemModel } from './menu-item.model';
|
import { MenuItemModel } from './menu-item.model';
|
||||||
import { MenuItemType } from '../../menu-item-type.model';
|
import { MenuItemType } from '../../menu-item-type.model';
|
||||||
|
import { Params } from '@angular/router';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model representing an Link Menu Section
|
* Model representing an Link Menu Section
|
||||||
@@ -8,4 +9,5 @@ export class LinkMenuItemModel implements MenuItemModel {
|
|||||||
type = MenuItemType.LINK;
|
type = MenuItemType.LINK;
|
||||||
text: string;
|
text: string;
|
||||||
link: string;
|
link: string;
|
||||||
|
queryParams?: Params | null;
|
||||||
}
|
}
|
||||||
|
4
src/config/store/devtools.prod.ts
Normal file
4
src/config/store/devtools.prod.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
/**
|
||||||
|
* This disabled DevTools in Production mode, overriding the defaults in devtools.ts
|
||||||
|
*/
|
||||||
|
export const StoreDevModules = [];
|
10
src/config/store/devtools.ts
Normal file
10
src/config/store/devtools.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
|
||||||
|
|
||||||
|
export const StoreDevModules = [
|
||||||
|
// This enables Redux DevTools by default.
|
||||||
|
// Note: this is overridden in production by devtools.prod.ts
|
||||||
|
StoreDevtoolsModule.instrument({
|
||||||
|
maxAge: 1000,
|
||||||
|
logOnly: false,
|
||||||
|
})
|
||||||
|
];
|
Reference in New Issue
Block a user