mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
build app config
This commit is contained in:
1
config/.gitignore
vendored
Normal file
1
config/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
appConfig.*.json
|
14
config/appConfig.json
Normal file
14
config/appConfig.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"ui": {
|
||||||
|
"ssl": false,
|
||||||
|
"host": "localhost",
|
||||||
|
"port": 4000,
|
||||||
|
"nameSpace": "/"
|
||||||
|
},
|
||||||
|
"rest": {
|
||||||
|
"ssl": true,
|
||||||
|
"host": "api7.dspace.org",
|
||||||
|
"port": 443,
|
||||||
|
"nameSpace": "/server"
|
||||||
|
}
|
||||||
|
}
|
@@ -1,6 +1,6 @@
|
|||||||
import { writeFile } from 'fs';
|
import { writeFile } from 'fs';
|
||||||
import { environment as commonEnv } from '../src/environments/environment.common';
|
import { environment as commonEnv } from '../src/environments/environment.common';
|
||||||
import { GlobalConfig } from '../src/config/global-config.interface';
|
import { AppConfig } from '../src/config/app-config.interface';
|
||||||
import { ServerConfig } from '../src/config/server-config.interface';
|
import { ServerConfig } from '../src/config/server-config.interface';
|
||||||
import { hasValue } from '../src/app/shared/empty.util';
|
import { hasValue } from '../src/app/shared/empty.util';
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ const processEnv = {
|
|||||||
process.env.DSPACE_REST_PORT,
|
process.env.DSPACE_REST_PORT,
|
||||||
process.env.DSPACE_REST_NAMESPACE,
|
process.env.DSPACE_REST_NAMESPACE,
|
||||||
process.env.DSPACE_REST_SSL)
|
process.env.DSPACE_REST_SSL)
|
||||||
} as GlobalConfig;
|
} as AppConfig;
|
||||||
|
|
||||||
import(environmentFilePath)
|
import(environmentFilePath)
|
||||||
.then((file) => generateEnvironmentFile(merge.all([commonEnv, file.environment, processEnv], mergeOptions)))
|
.then((file) => generateEnvironmentFile(merge.all([commonEnv, file.environment, processEnv], mergeOptions)))
|
||||||
@@ -51,7 +51,7 @@ import(environmentFilePath)
|
|||||||
generateEnvironmentFile(merge(commonEnv, processEnv, mergeOptions))
|
generateEnvironmentFile(merge(commonEnv, processEnv, mergeOptions))
|
||||||
});
|
});
|
||||||
|
|
||||||
function generateEnvironmentFile(file: GlobalConfig): void {
|
function generateEnvironmentFile(file: AppConfig): void {
|
||||||
file.production = production;
|
file.production = production;
|
||||||
buildBaseUrls(file);
|
buildBaseUrls(file);
|
||||||
const contents = `export const environment = ` + JSON.stringify(file);
|
const contents = `export const environment = ` + JSON.stringify(file);
|
||||||
@@ -86,7 +86,7 @@ function createServerConfig(host?: string, port?: string, nameSpace?: string, ss
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildBaseUrls(config: GlobalConfig): void {
|
function buildBaseUrls(config: AppConfig): void {
|
||||||
for (const key in config) {
|
for (const key in config) {
|
||||||
if (config.hasOwnProperty(key) && config[key].host) {
|
if (config.hasOwnProperty(key) && config[key].host) {
|
||||||
config[key].baseUrl = [
|
config[key].baseUrl = [
|
||||||
|
@@ -10,8 +10,6 @@ import { NotificationsService } from '../notifications.service';
|
|||||||
import { NotificationType } from '../models/notification-type';
|
import { NotificationType } from '../models/notification-type';
|
||||||
import { notificationsReducer } from '../notifications.reducers';
|
import { notificationsReducer } from '../notifications.reducers';
|
||||||
import { NotificationOptions } from '../models/notification-options.model';
|
import { NotificationOptions } from '../models/notification-options.model';
|
||||||
import { INotificationBoardOptions } from '../../../../config/notifications-config.interfaces';
|
|
||||||
import { GlobalConfig } from '../../../../config/global-config.interface';
|
|
||||||
import { Notification } from '../models/notification.model';
|
import { Notification } from '../models/notification.model';
|
||||||
import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core';
|
import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core';
|
||||||
import { TranslateLoaderMock } from '../../mocks/translate-loader.mock';
|
import { TranslateLoaderMock } from '../../mocks/translate-loader.mock';
|
||||||
@@ -33,16 +31,6 @@ describe('NotificationComponent', () => {
|
|||||||
/* tslint:disable:no-empty */
|
/* tslint:disable:no-empty */
|
||||||
notifications: []
|
notifications: []
|
||||||
});
|
});
|
||||||
const envConfig: GlobalConfig = {
|
|
||||||
notifications: {
|
|
||||||
rtl: false,
|
|
||||||
position: ['top', 'right'],
|
|
||||||
maxStack: 8,
|
|
||||||
timeOut: 5000,
|
|
||||||
clickToClose: true,
|
|
||||||
animate: 'scale'
|
|
||||||
} as INotificationBoardOptions,
|
|
||||||
} as any;
|
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
|
@@ -8,7 +8,6 @@ import { of as observableOf } from 'rxjs';
|
|||||||
import { NewNotificationAction, RemoveAllNotificationsAction, RemoveNotificationAction } from './notifications.actions';
|
import { NewNotificationAction, RemoveAllNotificationsAction, RemoveNotificationAction } from './notifications.actions';
|
||||||
import { Notification } from './models/notification.model';
|
import { Notification } from './models/notification.model';
|
||||||
import { NotificationType } from './models/notification-type';
|
import { NotificationType } from './models/notification-type';
|
||||||
import { GlobalConfig } from '../../../config/global-config.interface';
|
|
||||||
import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core';
|
import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core';
|
||||||
import { TranslateLoaderMock } from '../mocks/translate-loader.mock';
|
import { TranslateLoaderMock } from '../mocks/translate-loader.mock';
|
||||||
import { storeModuleConfig } from '../../app.reducer';
|
import { storeModuleConfig } from '../../app.reducer';
|
||||||
@@ -19,18 +18,6 @@ describe('NotificationsService test', () => {
|
|||||||
select: observableOf(true)
|
select: observableOf(true)
|
||||||
});
|
});
|
||||||
let service: NotificationsService;
|
let service: NotificationsService;
|
||||||
let envConfig: GlobalConfig;
|
|
||||||
|
|
||||||
envConfig = {
|
|
||||||
notifications: {
|
|
||||||
rtl: false,
|
|
||||||
position: ['top', 'right'],
|
|
||||||
maxStack: 8,
|
|
||||||
timeOut: 5000,
|
|
||||||
clickToClose: true,
|
|
||||||
animate: 'scale'
|
|
||||||
},
|
|
||||||
} as any;
|
|
||||||
|
|
||||||
beforeEach(waitForAsync(() => {
|
beforeEach(waitForAsync(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
|
1
src/assets/.gitignore
vendored
Normal file
1
src/assets/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
appConfig.json
|
@@ -1,3 +1,4 @@
|
|||||||
|
import { InjectionToken } from '@angular/core';
|
||||||
import { Config } from './config.interface';
|
import { Config } from './config.interface';
|
||||||
import { ServerConfig } from './server-config.interface';
|
import { ServerConfig } from './server-config.interface';
|
||||||
import { CacheConfig } from './cache-config.interface';
|
import { CacheConfig } from './cache-config.interface';
|
||||||
@@ -14,7 +15,7 @@ import { AuthConfig } from './auth-config.interfaces';
|
|||||||
import { UIServerConfig } from './ui-server-config.interface';
|
import { UIServerConfig } from './ui-server-config.interface';
|
||||||
import { MediaViewerConfig } from './media-viewer-config.interface';
|
import { MediaViewerConfig } from './media-viewer-config.interface';
|
||||||
|
|
||||||
export interface GlobalConfig extends Config {
|
interface AppConfig extends Config {
|
||||||
ui: UIServerConfig;
|
ui: UIServerConfig;
|
||||||
rest: ServerConfig;
|
rest: ServerConfig;
|
||||||
production: boolean;
|
production: boolean;
|
||||||
@@ -33,3 +34,10 @@ export interface GlobalConfig extends Config {
|
|||||||
themes: ThemeConfig[];
|
themes: ThemeConfig[];
|
||||||
mediaViewer: MediaViewerConfig;
|
mediaViewer: MediaViewerConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const APP_CONFIG = new InjectionToken<AppConfig>('APP_CONFIG');
|
||||||
|
|
||||||
|
export {
|
||||||
|
AppConfig,
|
||||||
|
APP_CONFIG
|
||||||
|
};
|
151
src/config/config.ts
Normal file
151
src/config/config.ts
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
import * as colors from 'colors';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import { join } from 'path';
|
||||||
|
import { AppConfig } from './app-config.interface';
|
||||||
|
import { Config } from './config.interface';
|
||||||
|
import { DefaultAppConfig } from './default-app-config';
|
||||||
|
import { ServerConfig } from './server-config.interface';
|
||||||
|
|
||||||
|
const CONFIG_PATH = join(process.cwd(), 'config');
|
||||||
|
|
||||||
|
const APP_CONFIG_PATH = join(CONFIG_PATH, 'appConfig.json');
|
||||||
|
|
||||||
|
type Environment = 'production' | 'development' | 'test';
|
||||||
|
|
||||||
|
const getEnvironment = (): Environment => {
|
||||||
|
let environment: Environment = 'development';
|
||||||
|
if (!!process.env.NODE_ENV) {
|
||||||
|
switch (process.env.NODE_ENV) {
|
||||||
|
case 'prod':
|
||||||
|
case 'production':
|
||||||
|
environment = 'production';
|
||||||
|
break;
|
||||||
|
case 'test':
|
||||||
|
environment = 'test';
|
||||||
|
break;
|
||||||
|
case 'dev':
|
||||||
|
case 'development':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.warn(`Unknown NODE_ENV ${process.env.NODE_ENV}. Defaulting to development`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return environment;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDistConfigPath = (env: Environment) => {
|
||||||
|
// determine app config filename variations
|
||||||
|
let envVariations;
|
||||||
|
switch (env) {
|
||||||
|
case 'production':
|
||||||
|
envVariations = ['prod', 'production'];
|
||||||
|
break;
|
||||||
|
case 'test':
|
||||||
|
envVariations = ['test'];
|
||||||
|
break;
|
||||||
|
case 'development':
|
||||||
|
default:
|
||||||
|
envVariations = ['dev', 'development']
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if any environment variations of app config exist
|
||||||
|
for (const envVariation of envVariations) {
|
||||||
|
const altDistConfigPath = join(CONFIG_PATH, `appConfig.${envVariation}.json`);
|
||||||
|
if (fs.existsSync(altDistConfigPath)) {
|
||||||
|
return altDistConfigPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// return default config/appConfig.json
|
||||||
|
return APP_CONFIG_PATH;
|
||||||
|
};
|
||||||
|
|
||||||
|
const overrideWithConfig = (config: Config, pathToConfig: string) => {
|
||||||
|
try {
|
||||||
|
console.log(`Overriding app config with ${pathToConfig}`);
|
||||||
|
const externalConfig = fs.readFileSync(pathToConfig, 'utf8');
|
||||||
|
Object.assign(config, JSON.parse(externalConfig));
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const overrideWithEnvironment = (config: Config, key: string = '') => {
|
||||||
|
for (const property in config) {
|
||||||
|
const variable = `${key}${!!key ? '_' : ''}${property.toUpperCase()}`;
|
||||||
|
const innerConfig = config[property];
|
||||||
|
if (!!innerConfig) {
|
||||||
|
if (typeof innerConfig === 'object') {
|
||||||
|
overrideWithEnvironment(innerConfig, variable);
|
||||||
|
} else {
|
||||||
|
if (!!process.env[variable]) {
|
||||||
|
console.log(`Applying environment variable ${variable} with value ${process.env[variable]}`);
|
||||||
|
config[property] = process.env[variable];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const buildBaseUrl = (config: ServerConfig): void => {
|
||||||
|
config.baseUrl = [
|
||||||
|
config.ssl ? 'https://' : 'http://',
|
||||||
|
config.host,
|
||||||
|
config.port && config.port !== 80 && config.port !== 443 ? `:${config.port}` : '',
|
||||||
|
config.nameSpace && config.nameSpace.startsWith('/') ? config.nameSpace : `/${config.nameSpace}`
|
||||||
|
].join('');
|
||||||
|
};
|
||||||
|
|
||||||
|
export const buildAppConfig = (destConfigPath: string): AppConfig => {
|
||||||
|
// start with default app config
|
||||||
|
const appConfig: AppConfig = new DefaultAppConfig();
|
||||||
|
|
||||||
|
// determine which dist app config by environment
|
||||||
|
const env = getEnvironment();
|
||||||
|
|
||||||
|
switch (env) {
|
||||||
|
case 'production':
|
||||||
|
console.log(`Building ${colors.red.bold(`production`)} app config`);
|
||||||
|
break;
|
||||||
|
case 'test':
|
||||||
|
console.log(`Building ${colors.blue.bold(`test`)} app config`);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.log(`Building ${colors.green.bold(`development`)} app config`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// override with dist config
|
||||||
|
const distConfigPath = getDistConfigPath(env);
|
||||||
|
if (fs.existsSync(distConfigPath)) {
|
||||||
|
overrideWithConfig(appConfig, distConfigPath);
|
||||||
|
} else {
|
||||||
|
console.warn(`Unable to find dist config file at ${distConfigPath}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// override with external config if specified by environment variable `APP_CONFIG_PATH`
|
||||||
|
const externalConfigPath = process.env.APP_CONFIG_PATH;
|
||||||
|
if (!!externalConfigPath) {
|
||||||
|
if (fs.existsSync(externalConfigPath)) {
|
||||||
|
overrideWithConfig(appConfig, externalConfigPath);
|
||||||
|
} else {
|
||||||
|
console.warn(`Unable to find external config file at ${externalConfigPath}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// override with environment variables
|
||||||
|
overrideWithEnvironment(appConfig);
|
||||||
|
|
||||||
|
// apply build defined production
|
||||||
|
appConfig.production = env === 'production';
|
||||||
|
|
||||||
|
// build base URLs
|
||||||
|
buildBaseUrl(appConfig.ui);
|
||||||
|
buildBaseUrl(appConfig.rest);
|
||||||
|
|
||||||
|
fs.writeFileSync(destConfigPath, JSON.stringify(appConfig, null, 2));
|
||||||
|
|
||||||
|
console.log(`Angular ${colors.bold('appConfig.json')} file generated correctly at ${colors.bold(destConfigPath)} \n`);
|
||||||
|
|
||||||
|
return appConfig;
|
||||||
|
}
|
306
src/config/default-app-config.ts
Normal file
306
src/config/default-app-config.ts
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
import { BrowseByType } from '../app/browse-by/browse-by-switcher/browse-by-decorator';
|
||||||
|
import { RestRequestMethod } from '../app/core/data/rest-request-method';
|
||||||
|
import { NotificationAnimationsType } from '../app/shared/notifications/models/notification-animations-type';
|
||||||
|
import { AppConfig } from './app-config.interface';
|
||||||
|
import { AuthConfig } from './auth-config.interfaces';
|
||||||
|
import { BrowseByConfig } from './browse-by-config.interface';
|
||||||
|
import { CacheConfig } from './cache-config.interface';
|
||||||
|
import { CollectionPageConfig } from './collection-page-config.interface';
|
||||||
|
import { FormConfig } from './form-config.interfaces';
|
||||||
|
import { ItemPageConfig } from './item-page-config.interface';
|
||||||
|
import { LangConfig } from './lang-config.interface';
|
||||||
|
import { MediaViewerConfig } from './media-viewer-config.interface';
|
||||||
|
import { INotificationBoardOptions } from './notifications-config.interfaces';
|
||||||
|
import { ServerConfig } from './server-config.interface';
|
||||||
|
import { SubmissionConfig } from './submission-config.interface';
|
||||||
|
import { ThemeConfig } from './theme.model';
|
||||||
|
import { UIServerConfig } from './ui-server-config.interface';
|
||||||
|
import { UniversalConfig } from './universal-config.interface';
|
||||||
|
|
||||||
|
export class DefaultAppConfig implements AppConfig {
|
||||||
|
production: boolean = false;
|
||||||
|
|
||||||
|
// Angular Universal server settings.
|
||||||
|
// NOTE: these must be 'synced' with the 'dspace.ui.url' setting in your backend's local.cfg.
|
||||||
|
ui: UIServerConfig = {
|
||||||
|
ssl: false,
|
||||||
|
host: 'localhost',
|
||||||
|
port: 4000,
|
||||||
|
// NOTE: Space is capitalized because 'namespace' is a reserved string in TypeScript
|
||||||
|
nameSpace: '/',
|
||||||
|
|
||||||
|
// The rateLimiter settings limit each IP to a 'max' of 500 requests per 'windowMs' (1 minute).
|
||||||
|
rateLimiter: {
|
||||||
|
windowMs: 1 * 60 * 1000, // 1 minute
|
||||||
|
max: 500 // limit each IP to 500 requests per windowMs
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// The REST API server settings.
|
||||||
|
// NOTE: these must be 'synced' with the 'dspace.server.url' setting in your backend's local.cfg.
|
||||||
|
rest: ServerConfig = {
|
||||||
|
ssl: false,
|
||||||
|
host: 'localhost',
|
||||||
|
port: 8080,
|
||||||
|
// NOTE: Space is capitalized because 'namespace' is a reserved string in TypeScript
|
||||||
|
nameSpace: '/',
|
||||||
|
};
|
||||||
|
|
||||||
|
// Caching settings
|
||||||
|
cache: CacheConfig = {
|
||||||
|
// NOTE: how long should objects be cached for by default
|
||||||
|
msToLive: {
|
||||||
|
default: 15 * 60 * 1000 // 15 minutes
|
||||||
|
},
|
||||||
|
control: 'max-age=60', // revalidate browser
|
||||||
|
autoSync: {
|
||||||
|
defaultTime: 0,
|
||||||
|
maxBufferSize: 100,
|
||||||
|
timePerMethod: { [RestRequestMethod.PATCH]: 3 } as any // time in seconds
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Authentication settings
|
||||||
|
auth: AuthConfig = {
|
||||||
|
// Authentication UI settings
|
||||||
|
ui: {
|
||||||
|
// the amount of time before the idle warning is shown
|
||||||
|
timeUntilIdle: 15 * 60 * 1000, // 15 minutes
|
||||||
|
// the amount of time the user has to react after the idle warning is shown before they are logged out.
|
||||||
|
idleGracePeriod: 5 * 60 * 1000 // 5 minutes
|
||||||
|
},
|
||||||
|
// Authentication REST settings
|
||||||
|
rest: {
|
||||||
|
// If the rest token expires in less than this amount of time, it will be refreshed automatically.
|
||||||
|
// This is independent from the idle warning.
|
||||||
|
timeLeftBeforeTokenRefresh: 2 * 60 * 1000 // 2 minutes
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Form settings
|
||||||
|
form: FormConfig = {
|
||||||
|
// NOTE: Map server-side validators to comparative Angular form validators
|
||||||
|
validatorMap: {
|
||||||
|
required: 'required',
|
||||||
|
regex: 'pattern'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Notifications
|
||||||
|
notifications: INotificationBoardOptions = {
|
||||||
|
rtl: false,
|
||||||
|
position: ['top', 'right'],
|
||||||
|
maxStack: 8,
|
||||||
|
// NOTE: after how many seconds notification is closed automatically. If set to zero notifications are not closed automatically
|
||||||
|
timeOut: 5000, // 5 second
|
||||||
|
clickToClose: true,
|
||||||
|
// NOTE: 'fade' | 'fromTop' | 'fromRight' | 'fromBottom' | 'fromLeft' | 'rotate' | 'scale'
|
||||||
|
animate: NotificationAnimationsType.Scale
|
||||||
|
};
|
||||||
|
|
||||||
|
// Submission settings
|
||||||
|
submission: SubmissionConfig = {
|
||||||
|
autosave: {
|
||||||
|
// NOTE: which metadata trigger an autosave
|
||||||
|
metadata: [],
|
||||||
|
/**
|
||||||
|
* NOTE: after how many time (milliseconds) submission is saved automatically
|
||||||
|
* eg. timer: 5 * (1000 * 60); // 5 minutes
|
||||||
|
*/
|
||||||
|
timer: 0
|
||||||
|
},
|
||||||
|
icons: {
|
||||||
|
metadata: [
|
||||||
|
/**
|
||||||
|
* NOTE: example of configuration
|
||||||
|
* {
|
||||||
|
* // NOTE: metadata name
|
||||||
|
* name: 'dc.author',
|
||||||
|
* // NOTE: fontawesome (v5.x) icon classes and bootstrap utility classes can be used
|
||||||
|
* style: 'fa-user'
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
name: 'dc.author',
|
||||||
|
style: 'fas fa-user'
|
||||||
|
},
|
||||||
|
// default configuration
|
||||||
|
{
|
||||||
|
name: 'default',
|
||||||
|
style: ''
|
||||||
|
}
|
||||||
|
],
|
||||||
|
authority: {
|
||||||
|
confidence: [
|
||||||
|
/**
|
||||||
|
* NOTE: example of configuration
|
||||||
|
* {
|
||||||
|
* // NOTE: confidence value
|
||||||
|
* value: 'dc.author',
|
||||||
|
* // NOTE: fontawesome (v4.x) icon classes and bootstrap utility classes can be used
|
||||||
|
* style: 'fa-user'
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
value: 600,
|
||||||
|
style: 'text-success'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 500,
|
||||||
|
style: 'text-info'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 400,
|
||||||
|
style: 'text-warning'
|
||||||
|
},
|
||||||
|
// default configuration
|
||||||
|
{
|
||||||
|
value: 'default',
|
||||||
|
style: 'text-muted'
|
||||||
|
}
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Angular Universal settings
|
||||||
|
universal: UniversalConfig = {
|
||||||
|
preboot: true,
|
||||||
|
async: true,
|
||||||
|
time: false
|
||||||
|
};
|
||||||
|
|
||||||
|
// NOTE: will log all redux actions and transfers in console
|
||||||
|
debug: boolean = false;
|
||||||
|
|
||||||
|
// Default Language in which the UI will be rendered if the user's browser language is not an active language
|
||||||
|
defaultLanguage: string = 'en';
|
||||||
|
|
||||||
|
// Languages. DSpace Angular holds a message catalog for each of the following languages.
|
||||||
|
// When set to active, users will be able to switch to the use of this language in the user interface.
|
||||||
|
languages: LangConfig[] = [
|
||||||
|
{ code: 'en', label: 'English', active: true },
|
||||||
|
{ code: 'cs', label: 'Čeština', active: true },
|
||||||
|
{ code: 'de', label: 'Deutsch', active: true },
|
||||||
|
{ code: 'es', label: 'Español', active: true },
|
||||||
|
{ code: 'fr', label: 'Français', active: true },
|
||||||
|
{ code: 'lv', label: 'Latviešu', active: true },
|
||||||
|
{ code: 'hu', label: 'Magyar', active: true },
|
||||||
|
{ code: 'nl', label: 'Nederlands', active: true },
|
||||||
|
{ code: 'pt-PT', label: 'Português', active: true },
|
||||||
|
{ code: 'pt-BR', label: 'Português do Brasil', active: true },
|
||||||
|
{ code: 'fi', label: 'Suomi', active: true }
|
||||||
|
];
|
||||||
|
|
||||||
|
// Browse-By Pages
|
||||||
|
browseBy: BrowseByConfig = {
|
||||||
|
// Amount of years to display using jumps of one year (current year - oneYearLimit)
|
||||||
|
oneYearLimit: 10,
|
||||||
|
// Limit for years to display using jumps of five years (current year - fiveYearLimit)
|
||||||
|
fiveYearLimit: 30,
|
||||||
|
// The absolute lowest year to display in the dropdown (only used when no lowest date can be found for all items)
|
||||||
|
defaultLowerLimit: 1900,
|
||||||
|
// List of all the active Browse-By types
|
||||||
|
// Adding a type will activate their Browse-By page and add them to the global navigation menu,
|
||||||
|
// as well as community and collection pages
|
||||||
|
// Allowed fields and their purpose:
|
||||||
|
// id: The browse id to use for fetching info from the rest api
|
||||||
|
// type: The type of Browse-By page to display
|
||||||
|
// metadataField: The metadata-field used to create starts-with options (only necessary when the type is set to 'date')
|
||||||
|
types: [
|
||||||
|
{
|
||||||
|
id: 'title',
|
||||||
|
type: BrowseByType.Title,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'dateissued',
|
||||||
|
type: BrowseByType.Date,
|
||||||
|
metadataField: 'dc.date.issued'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'author',
|
||||||
|
type: BrowseByType.Metadata
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'subject',
|
||||||
|
type: BrowseByType.Metadata
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
// Item Page Config
|
||||||
|
item: ItemPageConfig = {
|
||||||
|
edit: {
|
||||||
|
undoTimeout: 10000 // 10 seconds
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Collection Page Config
|
||||||
|
collection: CollectionPageConfig = {
|
||||||
|
edit: {
|
||||||
|
undoTimeout: 10000 // 10 seconds
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Theme Config
|
||||||
|
themes: ThemeConfig[] = [
|
||||||
|
// Add additional themes here. In the case where multiple themes match a route, the first one
|
||||||
|
// in this list will get priority. It is advisable to always have a theme that matches
|
||||||
|
// every route as the last one
|
||||||
|
|
||||||
|
// {
|
||||||
|
// // A theme with a handle property will match the community, collection or item with the given
|
||||||
|
// // handle, and all collections and/or items within it
|
||||||
|
// name: 'custom',
|
||||||
|
// handle: '10673/1233'
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// // A theme with a regex property will match the route using a regular expression. If it
|
||||||
|
// // matches the route for a community or collection it will also apply to all collections
|
||||||
|
// // and/or items within it
|
||||||
|
// name: 'custom',
|
||||||
|
// regex: 'collections\/e8043bc2.*'
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// // A theme with a uuid property will match the community, collection or item with the given
|
||||||
|
// // ID, and all collections and/or items within it
|
||||||
|
// name: 'custom',
|
||||||
|
// uuid: '0958c910-2037-42a9-81c7-dca80e3892b4'
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// // The extends property specifies an ancestor theme (by name). Whenever a themed component is not found
|
||||||
|
// // in the current theme, its ancestor theme(s) will be checked recursively before falling back to default.
|
||||||
|
// name: 'custom-A',
|
||||||
|
// extends: 'custom-B',
|
||||||
|
// // Any of the matching properties above can be used
|
||||||
|
// handle: '10673/34'
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: 'custom-B',
|
||||||
|
// extends: 'custom',
|
||||||
|
// handle: '10673/12'
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// // A theme with only a name will match every route
|
||||||
|
// name: 'custom'
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// // This theme will use the default bootstrap styling for DSpace components
|
||||||
|
// name: BASE_THEME_NAME
|
||||||
|
// },
|
||||||
|
|
||||||
|
{
|
||||||
|
// The default dspace theme
|
||||||
|
name: 'dspace'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
// Whether to enable media viewer for image and/or video Bitstreams (i.e. Bitstreams whose MIME type starts with 'image' or 'video').
|
||||||
|
// For images, this enables a gallery viewer where you can zoom or page through images.
|
||||||
|
// For videos, this enables embedded video streaming
|
||||||
|
mediaViewer: MediaViewerConfig = {
|
||||||
|
image: false,
|
||||||
|
video: false
|
||||||
|
};
|
||||||
|
}
|
@@ -1,9 +1,9 @@
|
|||||||
import { GlobalConfig } from '../config/global-config.interface';
|
import { AppConfig } from '../config/app-config.interface';
|
||||||
import { NotificationAnimationsType } from '../app/shared/notifications/models/notification-animations-type';
|
import { NotificationAnimationsType } from '../app/shared/notifications/models/notification-animations-type';
|
||||||
import { BrowseByType } from '../app/browse-by/browse-by-switcher/browse-by-decorator';
|
import { BrowseByType } from '../app/browse-by/browse-by-switcher/browse-by-decorator';
|
||||||
import { RestRequestMethod } from '../app/core/data/rest-request-method';
|
import { RestRequestMethod } from '../app/core/data/rest-request-method';
|
||||||
|
|
||||||
export const environment: GlobalConfig = {
|
export const environment: AppConfig = {
|
||||||
production: true,
|
production: true,
|
||||||
// Angular Universal server settings.
|
// Angular Universal server settings.
|
||||||
// NOTE: these must be "synced" with the 'dspace.ui.url' setting in your backend's local.cfg.
|
// NOTE: these must be "synced" with the 'dspace.ui.url' setting in your backend's local.cfg.
|
||||||
|
@@ -2,9 +2,9 @@
|
|||||||
import { BrowseByType } from '../app/browse-by/browse-by-switcher/browse-by-decorator';
|
import { BrowseByType } from '../app/browse-by/browse-by-switcher/browse-by-decorator';
|
||||||
import { RestRequestMethod } from '../app/core/data/rest-request-method';
|
import { RestRequestMethod } from '../app/core/data/rest-request-method';
|
||||||
import { NotificationAnimationsType } from '../app/shared/notifications/models/notification-animations-type';
|
import { NotificationAnimationsType } from '../app/shared/notifications/models/notification-animations-type';
|
||||||
import { GlobalConfig } from '../config/global-config.interface';
|
import { AppConfig } from '../config/app-config.interface';
|
||||||
|
|
||||||
export const environment: Partial<GlobalConfig> = {
|
export const environment: Partial<AppConfig> = {
|
||||||
rest: {
|
rest: {
|
||||||
ssl: true,
|
ssl: true,
|
||||||
host: 'rest.com',
|
host: 'rest.com',
|
||||||
|
20
src/main.ts
20
src/main.ts
@@ -1,20 +0,0 @@
|
|||||||
import 'core-js/es/reflect';
|
|
||||||
import 'zone.js/dist/zone';
|
|
||||||
import 'reflect-metadata';
|
|
||||||
|
|
||||||
import { enableProdMode } from '@angular/core';
|
|
||||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
|
||||||
|
|
||||||
import { AppModule } from './app/app.module';
|
|
||||||
import { environment } from './environments/environment';
|
|
||||||
|
|
||||||
if (environment.production) {
|
|
||||||
enableProdMode();
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
|
||||||
platformBrowserDynamic().bootstrapModule(AppModule)
|
|
||||||
.catch((err) => console.error(err));
|
|
||||||
});
|
|
||||||
});
|
|
@@ -1,8 +1,15 @@
|
|||||||
|
import { buildAppConfig } from '../src/config/config';
|
||||||
import { commonExports } from './webpack.common';
|
import { commonExports } from './webpack.common';
|
||||||
|
import { join } from 'path';
|
||||||
|
|
||||||
module.exports = Object.assign({}, commonExports, {
|
module.exports = Object.assign({}, commonExports, {
|
||||||
target: 'web',
|
target: 'web',
|
||||||
node: {
|
node: {
|
||||||
module: 'empty'
|
module: 'empty'
|
||||||
|
},
|
||||||
|
devServer: {
|
||||||
|
before(app, server) {
|
||||||
|
buildAppConfig(join(process.cwd(), 'src/assets/appConfig.json'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user