Merge branch 'master' into w2p-62769_Bitstream-format-registry

Conflicts:
	src/app/+admin/admin-registries/bitstream-formats/bitstream-formats.component.spec.ts
	src/app/core/core.module.ts
	src/app/core/registry/registry-bitstreamformats-response.model.ts
	src/app/core/registry/registry.service.ts
	src/app/core/shared/bitstream-format.model.ts
This commit is contained in:
Yana De Pauw
2019-08-06 17:22:03 +02:00
458 changed files with 4716 additions and 2583 deletions

2
.gitignore vendored
View File

@@ -5,6 +5,8 @@
/tsd_typings/ /tsd_typings/
npm-debug.log npm-debug.log
/build/
/config/environment.dev.js /config/environment.dev.js
/config/environment.prod.js /config/environment.prod.js

View File

@@ -13,7 +13,7 @@ module.exports = {
host: 'dspace7.4science.cloud', host: 'dspace7.4science.cloud',
port: 443, port: 443,
// NOTE: Space is capitalized because 'namespace' is a reserved string in TypeScript // NOTE: Space is capitalized because 'namespace' is a reserved string in TypeScript
nameSpace: '/dspace-spring-rest/api' nameSpace: '/server/api'
}, },
// Caching settings // Caching settings
cache: { cache: {
@@ -149,11 +149,39 @@ module.exports = {
// Limit for years to display using jumps of five years (current year - fiveYearLimit) // Limit for years to display using jumps of five years (current year - fiveYearLimit)
fiveYearLimit: 30, fiveYearLimit: 30,
// The absolute lowest year to display in the dropdown (only used when no lowest date can be found for all items) // The absolute lowest year to display in the dropdown (only used when no lowest date can be found for all items)
defaultLowerLimit: 1900 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: 'title'
},
{
id: 'dateissued',
type: 'date',
metadataField: 'dc.date.issued'
},
{
id: 'author',
type: 'metadata'
},
{
id: 'subject',
type: 'metadata'
}
]
}, },
item: { item: {
edit: { edit: {
undoTimeout: 10000 // 10 seconds undoTimeout: 10000 // 10 seconds
} }
},
theme: {
name: 'default',
} }
}; };

View File

@@ -17,15 +17,16 @@
"clean:doc": "rimraf doc", "clean:doc": "rimraf doc",
"clean:log": "rimraf *.log*", "clean:log": "rimraf *.log*",
"clean:json": "rimraf *.records.json", "clean:json": "rimraf *.records.json",
"clean:bld": "rimraf build",
"clean:node": "rimraf node_modules", "clean:node": "rimraf node_modules",
"clean:prod": "yarn run clean:coverage && yarn run clean:doc && yarn run clean:dist && yarn run clean:log && yarn run clean:json", "clean:prod": "yarn run clean:coverage && yarn run clean:doc && yarn run clean:dist && yarn run clean:log && yarn run clean:json && yarn run clean:bld",
"clean": "yarn run clean:prod && yarn run clean:node", "clean": "yarn run clean:prod && yarn run clean:node",
"prebuild": "yarn run clean:dist", "prebuild": "yarn run clean:bld && yarn run clean:dist",
"prebuild:aot": "yarn run prebuild", "prebuild:aot": "yarn run prebuild",
"prebuild:prod": "yarn run prebuild", "prebuild:prod": "yarn run prebuild",
"build": "node ./webpack/run-webpack.js --progress --mode development", "build": "node ./scripts/webpack.js --progress --mode development",
"build:aot": "node ./webpack/run-webpack.js --env.aot --env.server --mode development && node ./webpack/run-webpack.js --env.aot --env.client --mode development", "build:aot": "yarn run syncbuilddir && node ./scripts/webpack.js --env.aot --env.server --mode development && node ./scripts/webpack.js --env.aot --env.client --mode development",
"build:prod": "node ./webpack/run-webpack.js --env.aot --env.server --mode production && node ./webpack/run-webpack.js --env.aot --env.client --mode production", "build:prod": "yarn run syncbuilddir && node ./scripts/webpack.js --env.aot --env.server --mode production && node ./scripts/webpack.js --env.aot --env.client --mode production",
"postbuild:prod": "yarn run rollup", "postbuild:prod": "yarn run rollup",
"rollup": "rollup -c rollup.config.js", "rollup": "rollup -c rollup.config.js",
"prestart": "yarn run build:prod", "prestart": "yarn run build:prod",
@@ -40,7 +41,8 @@
"server": "node dist/server.js", "server": "node dist/server.js",
"server:watch": "nodemon dist/server.js", "server:watch": "nodemon dist/server.js",
"server:watch:debug": "nodemon --debug dist/server.js", "server:watch:debug": "nodemon --debug dist/server.js",
"webpack:watch": "node ./webpack/run-webpack.js -w --mode development", "syncbuilddir": "node ./scripts/sync-build-dir.js",
"webpack:watch": "node ./scripts/webpack.js -w --mode development",
"watch": "yarn run build && npm-run-all -p webpack:watch server:watch", "watch": "yarn run build && npm-run-all -p webpack:watch server:watch",
"watch:debug": "yarn run build && npm-run-all -p webpack:watch server:watch:debug", "watch:debug": "yarn run build && npm-run-all -p webpack:watch server:watch:debug",
"predebug": "yarn run build", "predebug": "yarn run build",
@@ -60,7 +62,9 @@
"webdriver:update": "node node_modules/protractor/bin/webdriver-manager update --standalone --gecko false", "webdriver:update": "node node_modules/protractor/bin/webdriver-manager update --standalone --gecko false",
"lint": "tslint \"src/**/*.ts\" && tslint \"e2e/**/*.ts\"", "lint": "tslint \"src/**/*.ts\" && tslint \"e2e/**/*.ts\"",
"docs": "typedoc --options typedoc.json ./src/", "docs": "typedoc --options typedoc.json ./src/",
"coverage": "http-server -c-1 -o -p 9875 ./coverage" "coverage": "http-server -c-1 -o -p 9875 ./coverage",
"postinstall": "yarn run patch-protractor",
"patch-protractor": "ncp node_modules/webdriver-manager node_modules/protractor/node_modules/webdriver-manager"
}, },
"dependencies": { "dependencies": {
"@angular/animations": "^6.1.4", "@angular/animations": "^6.1.4",
@@ -94,6 +98,7 @@
"compression": "1.7.1", "compression": "1.7.1",
"cookie-parser": "1.4.3", "cookie-parser": "1.4.3",
"core-js": "^2.5.7", "core-js": "^2.5.7",
"debug-loader": "^0.0.1",
"express": "4.16.2", "express": "4.16.2",
"express-session": "1.15.6", "express-session": "1.15.6",
"fast-json-patch": "^2.0.7", "fast-json-patch": "^2.0.7",
@@ -117,10 +122,11 @@
"ngx-moment": "^3.1.0", "ngx-moment": "^3.1.0",
"ngx-pagination": "3.0.3", "ngx-pagination": "3.0.3",
"nouislider": "^11.0.0", "nouislider": "^11.0.0",
"pem": "1.12.3", "pem": "1.13.2",
"reflect-metadata": "0.1.12", "reflect-metadata": "0.1.12",
"rxjs": "6.2.2", "rxjs": "6.2.2",
"rxjs-spy": "^7.5.1", "rxjs-spy": "^7.5.1",
"sass-resources-loader": "^2.0.0",
"sortablejs": "1.7.0", "sortablejs": "1.7.0",
"text-mask-core": "5.0.1", "text-mask-core": "5.0.1",
"ts-loader": "^5.2.1", "ts-loader": "^5.2.1",
@@ -163,6 +169,7 @@
"codelyzer": "^4.4.4", "codelyzer": "^4.4.4",
"compression-webpack-plugin": "^1.1.6", "compression-webpack-plugin": "^1.1.6",
"copy-webpack-plugin": "^4.4.1", "copy-webpack-plugin": "^4.4.1",
"copyfiles": "^2.1.0",
"coveralls": "3.0.0", "coveralls": "3.0.0",
"css-loader": "1.0.0", "css-loader": "1.0.0",
"cssnano": "^4.1.10", "cssnano": "^4.1.10",
@@ -187,6 +194,7 @@
"karma-sourcemap-loader": "0.3.7", "karma-sourcemap-loader": "0.3.7",
"karma-webdriver-launcher": "1.0.5", "karma-webdriver-launcher": "1.0.5",
"karma-webpack": "3.0.0", "karma-webpack": "3.0.0",
"ncp": "^2.0.0",
"ngrx-store-freeze": "^0.2.4", "ngrx-store-freeze": "^0.2.4",
"node-sass": "^4.11.0", "node-sass": "^4.11.0",
"nodemon": "^1.15.0", "nodemon": "^1.15.0",
@@ -199,7 +207,7 @@
"postcss-loader": "^3.0.0", "postcss-loader": "^3.0.0",
"postcss-responsive-type": "1.0.0", "postcss-responsive-type": "1.0.0",
"postcss-smart-import": "0.7.6", "postcss-smart-import": "0.7.6",
"protractor": "^5.3.0", "protractor": "^5.4.2",
"protractor-istanbul-plugin": "2.0.0", "protractor-istanbul-plugin": "2.0.0",
"raw-loader": "0.5.1", "raw-loader": "0.5.1",
"resolve-url-loader": "^2.3.0", "resolve-url-loader": "^2.3.0",
@@ -213,17 +221,19 @@
"script-ext-html-webpack-plugin": "2.0.1", "script-ext-html-webpack-plugin": "2.0.1",
"source-map": "0.7.3", "source-map": "0.7.3",
"source-map-loader": "0.2.4", "source-map-loader": "0.2.4",
"string-replace-loader": "2.1.1", "string-replace-loader": "^2.1.1",
"to-string-loader": "1.1.5", "to-string-loader": "1.1.5",
"ts-helpers": "1.1.2", "ts-helpers": "1.1.2",
"ts-node": "4.1.0", "ts-node": "4.1.0",
"tslint": "5.11.0", "tslint": "5.11.0",
"typedoc": "^0.9.0", "typedoc": "^0.9.0",
"typescript": "^2.9.1", "typescript": "^2.9.1",
"webdriver-manager": "^12.1.6",
"webpack": "^4.17.1", "webpack": "^4.17.1",
"webpack-bundle-analyzer": "^3.3.2", "webpack-bundle-analyzer": "^3.3.2",
"webpack-dev-middleware": "3.2.0", "webpack-dev-middleware": "3.2.0",
"webpack-dev-server": "^3.1.5", "webpack-dev-server": "^3.1.5",
"webpack-import-glob-loader": "^1.6.3",
"webpack-merge": "4.1.4", "webpack-merge": "4.1.4",
"webpack-node-externals": "1.7.2" "webpack-node-externals": "1.7.2"
} }

View File

@@ -73,7 +73,7 @@ exports.config = {
framework: 'jasmine', framework: 'jasmine',
jasmineNodeOpts: { jasmineNodeOpts: {
showColors: true, showColors: true,
defaultTimeoutInterval: 30000, defaultTimeoutInterval: 60000,
print: function () {} print: function () {}
}, },
useAllAngular2AppRoots: true, useAllAngular2AppRoots: true,

View File

@@ -109,6 +109,16 @@
"link": { "link": {
"simple": "Simple item page", "simple": "Simple item page",
"full": "Full item page" "full": "Full item page"
},
"journal": {
"search": {
"title": "Articles in this journal"
}
},
"person": {
"search": {
"title": "Articles by this author"
}
} }
}, },
"select": { "select": {
@@ -386,7 +396,10 @@
"titleprefix": "Publication: ", "titleprefix": "Publication: ",
"journal-title": "Journal Title", "journal-title": "Journal Title",
"journal-issn": "Journal ISSN", "journal-issn": "Journal ISSN",
"volume-title": "Volume Title" "volume-title": "Volume Title",
"publisher": "Publisher",
"description": "Description"
}, },
"listelement": { "listelement": {
"badge": "Publication" "badge": "Publication"
@@ -609,6 +622,34 @@
"birthDate": { "birthDate": {
"placeholder": "Birth Date", "placeholder": "Birth Date",
"head": "Birth Date" "head": "Birth Date"
},
"creativeWorkPublisher": {
"placeholder": "Publisher",
"head": "Publisher"
},
"creativeWorkEditor": {
"placeholder": "Editor",
"head": "Editor"
},
"creativeWorkKeywords": {
"placeholder": "Subject",
"head": "Subject"
},
"creativeDatePublished": {
"placeholder": "Date Published",
"head": "Date Published"
},
"organizationAddressCountry": {
"placeholder": "Country",
"head": "Country"
},
"organizationAddressLocality": {
"placeholder": "City",
"head": "City"
},
"organizationFoundingDate": {
"placeholder": "Date Founded",
"head": "Date Founded"
} }
} }
} }
@@ -839,7 +880,7 @@
"control_panel": "Control Panel", "control_panel": "Control Panel",
"browse_global": "All of DSpace", "browse_global": "All of DSpace",
"browse_global_communities_and_collections": "Communities & Collections", "browse_global_communities_and_collections": "Communities & Collections",
"browse_global_by_issue_date": "By Issue Date", "browse_global_by_dateissued": "By Issue Date",
"browse_global_by_author": "By Author", "browse_global_by_author": "By Author",
"browse_global_by_title": "By Title", "browse_global_by_title": "By Title",
"browse_global_by_subject": "By Subject", "browse_global_by_subject": "By Subject",

BIN
resources/images/banner.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="231.893px" height="167.458px" viewBox="0 0 231.893 167.458" enable-background="new 0 0 231.893 167.458"
xml:space="preserve">
<path fill="#43515F" d="M51.733,143.32c0-1.94,1.65-3.202,4.562-3.202c3.303,0,6.798,1.115,9.419,3.543l3.835-5.146
c-3.202-2.963-7.476-4.516-12.621-4.516c-7.622,0-12.284,4.467-12.284,9.855c0,12.188,18.644,8.254,18.644,13.887
c0,1.893-1.797,3.592-5.632,3.592c-4.466,0-8.011-2.039-10.292-4.418l-3.787,5.39c3.058,3.059,7.525,5.153,13.788,5.153
c8.691,0,12.964-4.474,12.964-10.396C70.329,144.971,51.733,148.418,51.733,143.32z M100.682,134.484H85.534v32.386h6.895v-11.557
h8.254c6.99,0,10.875-4.759,10.875-10.391C111.558,139.243,107.722,134.484,100.682,134.484z M99.71,149.245h-7.283v-8.69h7.283
c2.72,0,4.808,1.651,4.808,4.368C104.518,147.592,102.43,149.245,99.71,149.245z M180.759,140.067c3.302,0,6.215,2.09,7.573,4.71
l5.923-2.913c-2.28-4.078-6.407-7.914-13.496-7.914c-9.759,0-17.283,6.75-17.283,16.75c0,9.954,7.524,16.76,17.283,16.76
c7.089,0,11.216-3.94,13.496-7.971l-5.923-2.865c-1.358,2.623-4.271,4.711-7.573,4.711c-5.924,0-10.194-4.517-10.194-10.635
C170.564,144.583,174.835,140.067,180.759,140.067z M131.958,134.484l-12.485,32.386h7.823l2.04-5.486h13.887l2.038,5.486h7.816
l-12.479-32.386H131.958z M131.228,155.313l5.05-13.936l5.05,13.936H131.228z M231.892,140.553v-6.069h-22.916v32.386h22.916v-6.07
H215.87v-7.379h15.684v-6.069H215.87v-6.797L231.892,140.553L231.892,140.553z"/>
<path fill="#43515F" d="M29.956,150.652c0-9.71-7.04-16.168-17.187-16.168H0v32.386h12.817
C22.916,166.87,29.956,160.458,29.956,150.652z M12.769,160.799H6.894v-20.246h5.924c6.603,0,10.098,4.418,10.098,10.099
C22.916,156.187,19.177,160.799,12.769,160.799z"/>
<path fill="#43515F" d="M120.726,58.569l0.109-0.006l0.116-0.01l0.106-0.013l0.11-0.01l0.11-0.023l0.109-0.019l0.106-0.023
l0.106-0.029l0.105-0.023l0.106-0.033l0.103-0.034l0.097-0.035l0.104-0.04l0.101-0.042l0.1-0.042v-0.001l0.096-0.045l0,0
l0.095-0.044l0.097-0.049l0.091-0.056v-0.001l0.094-0.05v-0.002l0.09-0.056v-0.001l0.093-0.06l0.083-0.056v-0.001l0.085-0.063
l0.088-0.065v-0.002l0.087-0.062v-0.001c0.816-0.683,1.393-1.646,1.561-2.738l0.013-0.104V54.72l0.014-0.101v-0.011l0.009-0.098
v-0.012l0.009-0.101V54.38l0.005-0.095v-0.016l0.002-0.105v-16.46l-0.002-0.105v-0.016l-0.005-0.095v-0.013l-0.009-0.101v-0.012
l-0.009-0.098v-0.011l-0.014-0.1v-0.01l-0.013-0.104c-0.167-1.092-0.744-2.057-1.561-2.738V34.3l-0.087-0.063v-0.002l-0.088-0.065
l-0.085-0.063v-0.001l-0.083-0.056l-0.093-0.061l0,0l-0.09-0.056V33.93l-0.094-0.05v-0.001l-0.091-0.056l-0.097-0.049l-0.095-0.043
V33.73l-0.096-0.045v-0.001l-0.1-0.043l-0.101-0.042l-0.104-0.04l-0.097-0.035l-0.103-0.031l-0.106-0.036l-0.105-0.023l-0.106-0.028
l-0.106-0.024l-0.109-0.019l-0.11-0.023l-0.11-0.009l-0.106-0.014l-0.116-0.01l-0.109-0.006l-0.114-0.005h-7.89
c-9.716,0-15.858-7.838-15.858-17.15V6.92c0-3.812-3.102-6.915-6.914-6.915H74.085c-3.813,0-6.92,3.106-6.92,6.915v16.682
c0,3.806,3.104,6.909,6.92,6.909h8.414c9.169,0,16.906,5.95,17.146,15.403v0.04c-0.24,9.453-7.978,15.402-17.146,15.402h-8.414
c-3.815,0-6.92,3.103-6.92,6.909v16.682c0,3.81,3.106,6.915,6.92,6.915H89.95c3.812,0,6.914-3.104,6.914-6.915v-9.223
c0-9.312,6.144-17.149,15.858-17.149h7.89L120.726,58.569z M154.772,9.956C148.631,3.814,140.15,0,130.816,0h-15.024v17.424h15.024
c4.526,0,8.647,1.858,11.64,4.849c2.99,2.99,4.849,7.112,4.849,11.639v24.042c0,4.538-1.853,8.665-4.832,11.655l-0.017-0.016
c-2.991,2.991-7.113,4.849-11.64,4.849h-15.024v17.424h15.024c9.333,0,17.814-3.814,23.956-9.956v-0.033
c6.142-6.143,9.955-14.614,9.955-23.923V33.912C164.727,24.578,160.914,16.097,154.772,9.956z"/>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

22
scripts/sync-build-dir.js Normal file
View File

@@ -0,0 +1,22 @@
const syncBuildDir = require('copyfiles');
const path = require('path');
const {
projectRoot,
theme,
themePath,
} = require('../webpack/helpers');
const projectDepth = projectRoot('./').split(path.sep).length;
let callback;
if (theme !== null && theme !== undefined) {
callback = () => {
syncBuildDir([path.join(themePath, '**/*'), 'build'], { up: projectDepth + 2 }, () => {})
}
}
else {
callback = () => {};
}
syncBuildDir([projectRoot('src/**/*'), 'build'], { up: projectDepth + 1 }, callback);

View File

@@ -20,18 +20,15 @@ describe('AddBitstreamFormatComponent', () => {
let comp: AddBitstreamFormatComponent; let comp: AddBitstreamFormatComponent;
let fixture: ComponentFixture<AddBitstreamFormatComponent>; let fixture: ComponentFixture<AddBitstreamFormatComponent>;
const bitstreamFormat: BitstreamFormat = { const bitstreamFormat = new BitstreamFormat();
uuid: 'test-uuid', bitstreamFormat.uuid = 'test-uuid-1';
id: 'test-uuid', bitstreamFormat.id = 'test-uuid-1';
shortDescription: 'Adobe PDF', bitstreamFormat.shortDescription = 'Unknown';
description: 'Adobe Portable Document Format', bitstreamFormat.description = 'Unknown data format';
mimetype: 'application/pdf', bitstreamFormat.mimetype = 'application/octet-stream';
supportLevel: BitstreamFormatSupportLevel.Unknown, bitstreamFormat.supportLevel = BitstreamFormatSupportLevel.Unknown;
internal: false, bitstreamFormat.internal = false;
extensions: ['pdf', 'also-pdf'], bitstreamFormat.extensions = null;
type: ResourceType.BitstreamFormat,
self: 'self-link'
};
let router; let router;
let notificationService: NotificationsServiceStub; let notificationService: NotificationsServiceStub;

View File

@@ -16,7 +16,6 @@ import { BitstreamFormatDataService } from '../../../core/data/bitstream-format-
import { NotificationsService } from '../../../shared/notifications/notifications.service'; import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service-stub'; import { NotificationsServiceStub } from '../../../shared/testing/notifications-service-stub';
import { BitstreamFormat } from '../../../core/shared/bitstream-format.model'; import { BitstreamFormat } from '../../../core/shared/bitstream-format.model';
import { ResourceType } from '../../../core/shared/resource-type';
import { BitstreamFormatSupportLevel } from '../../../core/shared/bitstream-format-support-level'; import { BitstreamFormatSupportLevel } from '../../../core/shared/bitstream-format-support-level';
import { cold, getTestScheduler, hot } from 'jasmine-marbles'; import { cold, getTestScheduler, hot } from 'jasmine-marbles';
import { TestScheduler } from 'rxjs/testing'; import { TestScheduler } from 'rxjs/testing';
@@ -28,54 +27,45 @@ describe('BitstreamFormatsComponent', () => {
let scheduler: TestScheduler; let scheduler: TestScheduler;
let notificationsServiceStub; let notificationsServiceStub;
const bitstreamFormat1: BitstreamFormat = { const bitstreamFormat1 = new BitstreamFormat();
uuid: 'test-uuid-1', bitstreamFormat1.uuid = 'test-uuid-1';
id: 'test-uuid-1', bitstreamFormat1.id = 'test-uuid-1';
shortDescription: 'Unknown', bitstreamFormat1.shortDescription = 'Unknown';
description: 'Unknown data format', bitstreamFormat1.description = 'Unknown data format';
mimetype: 'application/octet-stream', bitstreamFormat1.mimetype = 'application/octet-stream';
supportLevel: BitstreamFormatSupportLevel.Unknown, bitstreamFormat1.supportLevel = BitstreamFormatSupportLevel.Unknown;
internal: false, bitstreamFormat1.internal = false;
extensions: null, bitstreamFormat1.extensions = null;
type: ResourceType.BitstreamFormat,
self: 'self-link' const bitstreamFormat2 = new BitstreamFormat();
}; bitstreamFormat2.uuid = 'test-uuid-2';
const bitstreamFormat2: BitstreamFormat = { bitstreamFormat2.id = 'test-uuid-2';
uuid: 'test-uuid-2', bitstreamFormat2.shortDescription = 'License';
id: 'test-uuid-2', bitstreamFormat2.description = 'Item-specific license agreed upon to submission';
shortDescription: 'License', bitstreamFormat2.mimetype = 'text/plain; charset=utf-8';
description: 'Item-specific license agreed upon to submission', bitstreamFormat2.supportLevel = BitstreamFormatSupportLevel.Known;
mimetype: 'text/plain; charset=utf-8', bitstreamFormat2.internal = true;
supportLevel: BitstreamFormatSupportLevel.Known, bitstreamFormat2.extensions = null;
internal: true,
extensions: null, const bitstreamFormat3 = new BitstreamFormat();
type: ResourceType.BitstreamFormat, bitstreamFormat3.uuid = 'test-uuid-3';
self: 'self-link' bitstreamFormat3.id = 'test-uuid-3';
}; bitstreamFormat3.shortDescription = 'CC License';
const bitstreamFormat3: BitstreamFormat = { bitstreamFormat3.description = 'Item-specific Creative Commons license agreed upon to submission';
uuid: 'test-uuid-3', bitstreamFormat3.mimetype = 'text/html; charset=utf-8';
id: 'test-uuid-3', bitstreamFormat3.supportLevel = BitstreamFormatSupportLevel.Supported;
shortDescription: 'CC License', bitstreamFormat3.internal = true;
description: 'Item-specific Creative Commons license agreed upon to submission', bitstreamFormat3.extensions = null;
mimetype: 'text/html; charset=utf-8',
supportLevel: BitstreamFormatSupportLevel.Supported, const bitstreamFormat4 = new BitstreamFormat();
internal: true, bitstreamFormat4.uuid = 'test-uuid-4';
extensions: null, bitstreamFormat4.id = 'test-uuid-4';
type: ResourceType.BitstreamFormat, bitstreamFormat4.shortDescription = 'Adobe PDF';
self: 'self-link' bitstreamFormat4.description = 'Adobe Portable Document Format';
}; bitstreamFormat4.mimetype = 'application/pdf';
const bitstreamFormat4: BitstreamFormat = { bitstreamFormat4.supportLevel = BitstreamFormatSupportLevel.Unknown;
uuid: 'test-uuid-4', bitstreamFormat4.internal = false;
id: 'test-uuid-4', bitstreamFormat4.extensions = null;
shortDescription: 'Adobe PDF',
description: 'Adobe Portable Document Format',
mimetype: 'application/pdf',
supportLevel: BitstreamFormatSupportLevel.Unknown,
internal: false,
extensions: null,
type: ResourceType.BitstreamFormat,
self: 'self-link'
};
const mockFormatsList: BitstreamFormat[] = [ const mockFormatsList: BitstreamFormat[] = [
bitstreamFormat1, bitstreamFormat1,

View File

@@ -21,18 +21,15 @@ describe('EditBitstreamFormatComponent', () => {
let comp: EditBitstreamFormatComponent; let comp: EditBitstreamFormatComponent;
let fixture: ComponentFixture<EditBitstreamFormatComponent>; let fixture: ComponentFixture<EditBitstreamFormatComponent>;
const bitstreamFormat: BitstreamFormat = { const bitstreamFormat = new BitstreamFormat();
uuid: 'test-uuid', bitstreamFormat.uuid = 'test-uuid-1';
id: 'test-uuid', bitstreamFormat.id = 'test-uuid-1';
shortDescription: 'Adobe PDF', bitstreamFormat.shortDescription = 'Unknown';
description: 'Adobe Portable Document Format', bitstreamFormat.description = 'Unknown data format';
mimetype: 'application/pdf', bitstreamFormat.mimetype = 'application/octet-stream';
supportLevel: BitstreamFormatSupportLevel.Unknown, bitstreamFormat.supportLevel = BitstreamFormatSupportLevel.Unknown;
internal: false, bitstreamFormat.internal = false;
extensions: ['pdf', 'also-pdf'], bitstreamFormat.extensions = null;
type: ResourceType.BitstreamFormat,
self: 'self-link'
};
const routeStub = { const routeStub = {
data: observableOf({ data: observableOf({

View File

@@ -9,7 +9,6 @@ import { Router } from '@angular/router';
import { FormatFormComponent } from './format-form.component'; import { FormatFormComponent } from './format-form.component';
import { BitstreamFormat } from '../../../../core/shared/bitstream-format.model'; import { BitstreamFormat } from '../../../../core/shared/bitstream-format.model';
import { BitstreamFormatSupportLevel } from '../../../../core/shared/bitstream-format-support-level'; import { BitstreamFormatSupportLevel } from '../../../../core/shared/bitstream-format-support-level';
import { ResourceType } from '../../../../core/shared/resource-type';
import { DynamicCheckboxModel, DynamicFormArrayModel, DynamicInputModel } from '@ng-dynamic-forms/core'; import { DynamicCheckboxModel, DynamicFormArrayModel, DynamicInputModel } from '@ng-dynamic-forms/core';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { isEmpty } from '../../../../shared/empty.util'; import { isEmpty } from '../../../../shared/empty.util';
@@ -20,18 +19,15 @@ describe('FormatFormComponent', () => {
const router = new RouterStub(); const router = new RouterStub();
const bitstreamFormat: BitstreamFormat = { const bitstreamFormat = new BitstreamFormat();
uuid: 'test-uuid', bitstreamFormat.uuid = 'test-uuid-1';
id: 'test-uuid', bitstreamFormat.id = 'test-uuid-1';
shortDescription: 'Adobe PDF', bitstreamFormat.shortDescription = 'Unknown';
description: 'Adobe Portable Document Format', bitstreamFormat.description = 'Unknown data format';
mimetype: 'application/pdf', bitstreamFormat.mimetype = 'application/octet-stream';
supportLevel: BitstreamFormatSupportLevel.Unknown, bitstreamFormat.supportLevel = BitstreamFormatSupportLevel.Unknown;
internal: false, bitstreamFormat.internal = false;
extensions: ['pdf', 'also-pdf'], bitstreamFormat.extensions = [];
type: ResourceType.BitstreamFormat,
self: 'self-link'
};
const submittedBitstreamFormat = new BitstreamFormat(); const submittedBitstreamFormat = new BitstreamFormat();
submittedBitstreamFormat.id = bitstreamFormat.id; submittedBitstreamFormat.id = bitstreamFormat.id;

View File

@@ -1,7 +1,7 @@
import { Action } from '@ngrx/store'; import { Action } from '@ngrx/store';
import { type } from '../../../shared/ngrx/type'; import { type } from '../../../shared/ngrx/type';
import { MetadataSchema } from '../../../core/metadata/metadataschema.model'; import { MetadataSchema } from '../../../core/metadata/metadata-schema.model';
import { MetadataField } from '../../../core/metadata/metadatafield.model'; import { MetadataField } from '../../../core/metadata/metadata-field.model';
/** /**
* For each action type in an action group, make a simple * For each action type in an action group, make a simple

View File

@@ -1,5 +1,3 @@
@import '../../../../styles/variables.scss';
.selectable-row:hover { .selectable-row:hover {
cursor: pointer; cursor: pointer;
} }

View File

@@ -17,6 +17,7 @@ import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
import { NotificationsService } from '../../../shared/notifications/notifications.service'; import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service-stub'; import { NotificationsServiceStub } from '../../../shared/testing/notifications-service-stub';
import { RestResponse } from '../../../core/cache/response.models'; import { RestResponse } from '../../../core/cache/response.models';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/testing/utils';
describe('MetadataRegistryComponent', () => { describe('MetadataRegistryComponent', () => {
let comp: MetadataRegistryComponent; let comp: MetadataRegistryComponent;
@@ -36,7 +37,7 @@ describe('MetadataRegistryComponent', () => {
namespace: 'http://dspace.org/mockschema' namespace: 'http://dspace.org/mockschema'
} }
]; ];
const mockSchemas = observableOf(new RemoteData(false, false, true, undefined, new PaginatedList(null, mockSchemasList))); const mockSchemas = createSuccessfulRemoteDataObject$(new PaginatedList(null, mockSchemasList));
/* tslint:disable:no-empty */ /* tslint:disable:no-empty */
const registryServiceStub = { const registryServiceStub = {
getMetadataSchemas: () => mockSchemas, getMetadataSchemas: () => mockSchemas,

View File

@@ -3,7 +3,6 @@ import { RegistryService } from '../../../core/registry/registry.service';
import { Observable, combineLatest as observableCombineLatest } from 'rxjs'; import { Observable, combineLatest as observableCombineLatest } from 'rxjs';
import { RemoteData } from '../../../core/data/remote-data'; import { RemoteData } from '../../../core/data/remote-data';
import { PaginatedList } from '../../../core/data/paginated-list'; import { PaginatedList } from '../../../core/data/paginated-list';
import { MetadataSchema } from '../../../core/metadata/metadataschema.model';
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
import { map, take } from 'rxjs/operators'; import { map, take } from 'rxjs/operators';
import { hasValue } from '../../../shared/empty.util'; import { hasValue } from '../../../shared/empty.util';
@@ -12,6 +11,7 @@ import { zip } from 'rxjs/internal/observable/zip';
import { NotificationsService } from '../../../shared/notifications/notifications.service'; import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { Route, Router } from '@angular/router'; import { Route, Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { MetadataSchema } from '../../../core/metadata/metadata-schema.model';
@Component({ @Component({
selector: 'ds-metadata-registry', selector: 'ds-metadata-registry',

View File

@@ -7,8 +7,8 @@ import {
MetadataRegistrySelectSchemaAction MetadataRegistrySelectSchemaAction
} from './metadata-registry.actions'; } from './metadata-registry.actions';
import { metadataRegistryReducer, MetadataRegistryState } from './metadata-registry.reducers'; import { metadataRegistryReducer, MetadataRegistryState } from './metadata-registry.reducers';
import { MetadataSchema } from '../../../core/metadata/metadataschema.model'; import { MetadataSchema } from '../../../core/metadata/metadata-schema.model';
import { MetadataField } from '../../../core/metadata/metadatafield.model'; import { MetadataField } from '../../../core/metadata/metadata-field.model';
class NullAction extends MetadataRegistryEditSchemaAction { class NullAction extends MetadataRegistryEditSchemaAction {
type = null; type = null;

View File

@@ -1,4 +1,3 @@
import { MetadataSchema } from '../../../core/metadata/metadataschema.model';
import { import {
MetadataRegistryAction, MetadataRegistryAction,
MetadataRegistryActionTypes, MetadataRegistryActionTypes,
@@ -9,7 +8,8 @@ import {
MetadataRegistrySelectFieldAction, MetadataRegistrySelectFieldAction,
MetadataRegistrySelectSchemaAction MetadataRegistrySelectSchemaAction
} from './metadata-registry.actions'; } from './metadata-registry.actions';
import { MetadataField } from '../../../core/metadata/metadatafield.model'; import { MetadataField } from '../../../core/metadata/metadata-field.model';
import { MetadataSchema } from '../../../core/metadata/metadata-schema.model';
/** /**
* The metadata registry state. * The metadata registry state.

View File

@@ -10,7 +10,7 @@ import { EnumKeysPipe } from '../../../../shared/utils/enum-keys-pipe';
import { RegistryService } from '../../../../core/registry/registry.service'; import { RegistryService } from '../../../../core/registry/registry.service';
import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service'; import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service';
import { of as observableOf } from 'rxjs/internal/observable/of'; import { of as observableOf } from 'rxjs/internal/observable/of';
import { MetadataSchema } from '../../../../core/metadata/metadataschema.model'; import { MetadataSchema } from '../../../../core/metadata/metadata-schema.model';
describe('MetadataSchemaFormComponent', () => { describe('MetadataSchemaFormComponent', () => {
let component: MetadataSchemaFormComponent; let component: MetadataSchemaFormComponent;

View File

@@ -9,9 +9,9 @@ import { FormGroup } from '@angular/forms';
import { RegistryService } from '../../../../core/registry/registry.service'; import { RegistryService } from '../../../../core/registry/registry.service';
import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service'; import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service';
import { take } from 'rxjs/operators'; import { take } from 'rxjs/operators';
import { MetadataSchema } from '../../../../core/metadata/metadataschema.model';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { combineLatest } from 'rxjs/internal/observable/combineLatest'; import { combineLatest } from 'rxjs/internal/observable/combineLatest';
import { MetadataSchema } from '../../../../core/metadata/metadata-schema.model';
@Component({ @Component({
selector: 'ds-metadata-schema-form', selector: 'ds-metadata-schema-form',

View File

@@ -3,7 +3,6 @@ import { async, ComponentFixture, inject, TestBed } from '@angular/core/testing'
import { MetadataFieldFormComponent } from './metadata-field-form.component'; import { MetadataFieldFormComponent } from './metadata-field-form.component';
import { RegistryService } from '../../../../core/registry/registry.service'; import { RegistryService } from '../../../../core/registry/registry.service';
import { of as observableOf } from 'rxjs/internal/observable/of'; import { of as observableOf } from 'rxjs/internal/observable/of';
import { MetadataField } from '../../../../core/metadata/metadatafield.model';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { RouterTestingModule } from '@angular/router/testing'; import { RouterTestingModule } from '@angular/router/testing';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
@@ -11,7 +10,8 @@ import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { EnumKeysPipe } from '../../../../shared/utils/enum-keys-pipe'; import { EnumKeysPipe } from '../../../../shared/utils/enum-keys-pipe';
import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service'; import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service';
import { NO_ERRORS_SCHEMA } from '@angular/core'; import { NO_ERRORS_SCHEMA } from '@angular/core';
import { MetadataSchema } from '../../../../core/metadata/metadataschema.model'; import { MetadataField } from '../../../../core/metadata/metadata-field.model';
import { MetadataSchema } from '../../../../core/metadata/metadata-schema.model';
describe('MetadataFieldFormComponent', () => { describe('MetadataFieldFormComponent', () => {
let component: MetadataFieldFormComponent; let component: MetadataFieldFormComponent;

View File

@@ -1,5 +1,4 @@
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'; import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';
import { MetadataSchema } from '../../../../core/metadata/metadataschema.model';
import { import {
DynamicFormControlModel, DynamicFormControlModel,
DynamicFormLayout, DynamicFormLayout,
@@ -8,10 +7,11 @@ import {
import { FormGroup } from '@angular/forms'; import { FormGroup } from '@angular/forms';
import { RegistryService } from '../../../../core/registry/registry.service'; import { RegistryService } from '../../../../core/registry/registry.service';
import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service'; import { FormBuilderService } from '../../../../shared/form/builder/form-builder.service';
import { MetadataField } from '../../../../core/metadata/metadatafield.model';
import { take } from 'rxjs/operators'; import { take } from 'rxjs/operators';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { combineLatest } from 'rxjs/internal/observable/combineLatest'; import { combineLatest } from 'rxjs/internal/observable/combineLatest';
import { MetadataSchema } from '../../../../core/metadata/metadata-schema.model';
import { MetadataField } from '../../../../core/metadata/metadata-field.model';
@Component({ @Component({
selector: 'ds-metadata-field-form', selector: 'ds-metadata-field-form',

View File

@@ -1,5 +1,3 @@
@import '../../../../styles/variables.scss';
.selectable-row:hover { .selectable-row:hover {
cursor: pointer; cursor: pointer;
} }

View File

@@ -3,7 +3,6 @@ import { async, ComponentFixture, inject, TestBed } from '@angular/core/testing'
import { of as observableOf } from 'rxjs'; import { of as observableOf } from 'rxjs';
import { RemoteData } from '../../../core/data/remote-data'; import { RemoteData } from '../../../core/data/remote-data';
import { PaginatedList } from '../../../core/data/paginated-list'; import { PaginatedList } from '../../../core/data/paginated-list';
import { MetadataSchema } from '../../../core/metadata/metadataschema.model';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
@@ -21,6 +20,8 @@ import { NO_ERRORS_SCHEMA } from '@angular/core';
import { NotificationsService } from '../../../shared/notifications/notifications.service'; import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { NotificationsServiceStub } from '../../../shared/testing/notifications-service-stub'; import { NotificationsServiceStub } from '../../../shared/testing/notifications-service-stub';
import { RestResponse } from '../../../core/cache/response.models'; import { RestResponse } from '../../../core/cache/response.models';
import { MetadataSchema } from '../../../core/metadata/metadata-schema.model';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/testing/utils';
describe('MetadataSchemaComponent', () => { describe('MetadataSchemaComponent', () => {
let comp: MetadataSchemaComponent; let comp: MetadataSchemaComponent;
@@ -74,12 +75,12 @@ describe('MetadataSchemaComponent', () => {
schema: mockSchemasList[1] schema: mockSchemasList[1]
} }
]; ];
const mockSchemas = observableOf(new RemoteData(false, false, true, undefined, new PaginatedList(null, mockSchemasList))); const mockSchemas = createSuccessfulRemoteDataObject$(new PaginatedList(null, mockSchemasList));
/* tslint:disable:no-empty */ /* tslint:disable:no-empty */
const registryServiceStub = { const registryServiceStub = {
getMetadataSchemas: () => mockSchemas, getMetadataSchemas: () => mockSchemas,
getMetadataFieldsBySchema: (schema: MetadataSchema) => observableOf(new RemoteData(false, false, true, undefined, new PaginatedList(null, mockFieldsList.filter((value) => value.schema === schema)))), getMetadataFieldsBySchema: (schema: MetadataSchema) => createSuccessfulRemoteDataObject$(new PaginatedList(null, mockFieldsList.filter((value) => value.schema === schema))),
getMetadataSchemaByName: (schemaName: string) => observableOf(new RemoteData(false, false, true, undefined, mockSchemasList.filter((value) => value.prefix === schemaName)[0])), getMetadataSchemaByName: (schemaName: string) => createSuccessfulRemoteDataObject$(mockSchemasList.filter((value) => value.prefix === schemaName)[0]),
getActiveMetadataField: () => observableOf(undefined), getActiveMetadataField: () => observableOf(undefined),
getSelectedMetadataFields: () => observableOf([]), getSelectedMetadataFields: () => observableOf([]),
editMetadataField: (schema) => {}, editMetadataField: (schema) => {},

View File

@@ -4,8 +4,6 @@ import { ActivatedRoute, Router } from '@angular/router';
import { Observable, combineLatest as observableCombineLatest } from 'rxjs'; import { Observable, combineLatest as observableCombineLatest } from 'rxjs';
import { RemoteData } from '../../../core/data/remote-data'; import { RemoteData } from '../../../core/data/remote-data';
import { PaginatedList } from '../../../core/data/paginated-list'; import { PaginatedList } from '../../../core/data/paginated-list';
import { MetadataField } from '../../../core/metadata/metadatafield.model';
import { MetadataSchema } from '../../../core/metadata/metadataschema.model';
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
import { map, take } from 'rxjs/operators'; import { map, take } from 'rxjs/operators';
import { hasValue } from '../../../shared/empty.util'; import { hasValue } from '../../../shared/empty.util';
@@ -13,6 +11,8 @@ import { RestResponse } from '../../../core/cache/response.models';
import { zip } from 'rxjs/internal/observable/zip'; import { zip } from 'rxjs/internal/observable/zip';
import { NotificationsService } from '../../../shared/notifications/notifications.service'; import { NotificationsService } from '../../../shared/notifications/notifications.service';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { MetadataField } from '../../../core/metadata/metadata-field.model';
import { MetadataSchema } from '../../../core/metadata/metadata-schema.model';
@Component({ @Component({
selector: 'ds-metadata-schema', selector: 'ds-metadata-schema',

View File

@@ -1 +0,0 @@
@import '../../../../styles/variables.scss';

View File

@@ -1,4 +1,4 @@
<nav @slideHorizontal class="navbar navbar-dark bg-dark p-0" <nav @slideHorizontal class="navbar navbar-dark p-0"
[ngClass]="{'active': sidebarOpen, 'inactive': sidebarClosed}" [ngClass]="{'active': sidebarOpen, 'inactive': sidebarClosed}"
[@slideSidebar]="{ [@slideSidebar]="{
value: (!(sidebarExpanded | async) ? 'collapsed' : 'expanded'), value: (!(sidebarExpanded | async) ? 'collapsed' : 'expanded'),

View File

@@ -1,5 +1,3 @@
@import '../../../styles/variables.scss';
@import '../../../styles/mixins.scss';
$icon-z-index: 10; $icon-z-index: 10;
:host { :host {
@@ -8,6 +6,7 @@ $icon-z-index: 10;
height: 100vh; height: 100vh;
flex: 1 1 auto; flex: 1 1 auto;
nav { nav {
background-color: $admin-sidebar-bg;
height: 100%; height: 100%;
flex-direction: column; flex-direction: column;
> div { > div {
@@ -44,7 +43,7 @@ $icon-z-index: 10;
.sidebar-section { .sidebar-section {
display: flex; display: flex;
align-content: stretch; align-content: stretch;
background-color: $dark; background-color: $admin-sidebar-bg;
.nav-item { .nav-item {
padding-top: $spacer; padding-top: $spacer;
padding-bottom: $spacer; padding-bottom: $spacer;

View File

@@ -1,5 +1,3 @@
@import '../../../../styles/variables.scss';
::ng-deep { ::ng-deep {
.fa-chevron-right { .fa-chevron-right {
padding-left: $spacer/2; padding-left: $spacer/2;

View File

@@ -18,6 +18,7 @@ import { Item } from '../../core/shared/item.model';
import { ENV_CONFIG, GLOBAL_CONFIG } from '../../../config'; import { ENV_CONFIG, GLOBAL_CONFIG } from '../../../config';
import { BrowseEntrySearchOptions } from '../../core/browse/browse-entry-search-options.model'; import { BrowseEntrySearchOptions } from '../../core/browse/browse-entry-search-options.model';
import { toRemoteData } from '../+browse-by-metadata-page/browse-by-metadata-page.component.spec'; import { toRemoteData } from '../+browse-by-metadata-page/browse-by-metadata-page.component.spec';
import { createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils';
describe('BrowseByDatePageComponent', () => { describe('BrowseByDatePageComponent', () => {
let comp: BrowseByDatePageComponent; let comp: BrowseByDatePageComponent;
@@ -48,11 +49,11 @@ describe('BrowseByDatePageComponent', () => {
const mockBrowseService = { const mockBrowseService = {
getBrowseEntriesFor: (options: BrowseEntrySearchOptions) => toRemoteData([]), getBrowseEntriesFor: (options: BrowseEntrySearchOptions) => toRemoteData([]),
getBrowseItemsFor: (value: string, options: BrowseEntrySearchOptions) => toRemoteData([firstItem]), getBrowseItemsFor: (value: string, options: BrowseEntrySearchOptions) => toRemoteData([firstItem]),
getFirstItemFor: () => observableOf(new RemoteData(false, false, true, undefined, firstItem)) getFirstItemFor: () => createSuccessfulRemoteDataObject$(firstItem)
}; };
const mockDsoService = { const mockDsoService = {
findById: () => observableOf(new RemoteData(false, false, true, null, mockCommunity)) findById: () => createSuccessfulRemoteDataObject$(mockCommunity)
}; };
const activatedRouteStub = Object.assign(new ActivatedRouteStub(), { const activatedRouteStub = Object.assign(new ActivatedRouteStub(), {

View File

@@ -13,6 +13,7 @@ import { BrowseService } from '../../core/browse/browse.service';
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service'; import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
import { GLOBAL_CONFIG, GlobalConfig } from '../../../config'; import { GLOBAL_CONFIG, GlobalConfig } from '../../../config';
import { StartsWithType } from '../../shared/starts-with/starts-with-decorator'; import { StartsWithType } from '../../shared/starts-with/starts-with-decorator';
import { BrowseByType, rendersBrowseBy } from '../+browse-by-switcher/browse-by-decorator';
@Component({ @Component({
selector: 'ds-browse-by-date-page', selector: 'ds-browse-by-date-page',
@@ -21,9 +22,10 @@ import { StartsWithType } from '../../shared/starts-with/starts-with-decorator';
}) })
/** /**
* Component for browsing items by metadata definition of type 'date' * Component for browsing items by metadata definition of type 'date'
* A metadata definition is a short term used to describe one or multiple metadata fields. * A metadata definition (a.k.a. browse id) is a short term used to describe one or multiple metadata fields.
* An example would be 'dateissued' for 'dc.date.issued' * An example would be 'dateissued' for 'dc.date.issued'
*/ */
@rendersBrowseBy(BrowseByType.Date)
export class BrowseByDatePageComponent extends BrowseByMetadataPageComponent { export class BrowseByDatePageComponent extends BrowseByMetadataPageComponent {
/** /**
@@ -53,12 +55,12 @@ export class BrowseByDatePageComponent extends BrowseByMetadataPageComponent {
}) })
.subscribe((params) => { .subscribe((params) => {
const metadataField = params.metadataField || this.defaultMetadataField; const metadataField = params.metadataField || this.defaultMetadataField;
this.metadata = params.metadata || this.defaultMetadata; this.browseId = params.id || this.defaultBrowseId;
this.startsWith = +params.startsWith || params.startsWith; this.startsWith = +params.startsWith || params.startsWith;
const searchOptions = browseParamsToOptions(params, Object.assign({}), this.sortConfig, this.metadata); const searchOptions = browseParamsToOptions(params, Object.assign({}), this.sortConfig, this.browseId);
this.updatePageWithItems(searchOptions, this.value); this.updatePageWithItems(searchOptions, this.value);
this.updateParent(params.scope); this.updateParent(params.scope);
this.updateStartsWithOptions(this.metadata, metadataField, params.scope); this.updateStartsWithOptions(this.browseId, metadataField, params.scope);
})); }));
} }
@@ -78,8 +80,9 @@ export class BrowseByDatePageComponent extends BrowseByMetadataPageComponent {
let lowerLimit = this.config.browseBy.defaultLowerLimit; let lowerLimit = this.config.browseBy.defaultLowerLimit;
if (hasValue(firstItemRD.payload)) { if (hasValue(firstItemRD.payload)) {
const date = firstItemRD.payload.firstMetadataValue(metadataField); const date = firstItemRD.payload.firstMetadataValue(metadataField);
if (hasValue(date) && hasValue(+date.split('-')[0])) { if (hasValue(date)) {
lowerLimit = +date.split('-')[0]; const dateObj = new Date(date);
lowerLimit = dateObj.getFullYear();
} }
} }
const options = []; const options = [];

View File

@@ -1,7 +1,7 @@
<div class="container"> <div class="container">
<div class="browse-by-metadata w-100"> <div class="browse-by-metadata w-100">
<ds-browse-by *ngIf="startsWithOptions" class="col-xs-12 w-100" <ds-browse-by *ngIf="startsWithOptions" class="col-xs-12 w-100"
title="{{'browse.title' | translate:{collection: (parent$ | async)?.payload?.name || '', field: 'browse.metadata.' + metadata | translate, value: (value)? '&quot;' + value + '&quot;': ''} }}" title="{{'browse.title' | translate:{collection: (parent$ | async)?.payload?.name || '', field: 'browse.metadata.' + browseId | translate, value: (value)? '&quot;' + value + '&quot;': ''} }}"
[objects$]="(items$ !== undefined)? items$ : browseEntries$" [objects$]="(items$ !== undefined)? items$ : browseEntries$"
[paginationConfig]="paginationConfig" [paginationConfig]="paginationConfig"
[sortConfig]="sortConfig" [sortConfig]="sortConfig"

View File

@@ -20,6 +20,9 @@ import { Item } from '../../core/shared/item.model';
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service'; import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
import { Community } from '../../core/shared/community.model'; import { Community } from '../../core/shared/community.model';
import { MockRouter } from '../../shared/mocks/mock-router'; import { MockRouter } from '../../shared/mocks/mock-router';
import { ResourceType } from '../../core/shared/resource-type';
import { createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils';
import { BrowseEntry } from '../../core/shared/browse-entry.model';
describe('BrowseByMetadataPageComponent', () => { describe('BrowseByMetadataPageComponent', () => {
let comp: BrowseByMetadataPageComponent; let comp: BrowseByMetadataPageComponent;
@@ -39,21 +42,21 @@ describe('BrowseByMetadataPageComponent', () => {
const mockEntries = [ const mockEntries = [
{ {
type: 'author', type: BrowseEntry.type,
authority: null, authority: null,
value: 'John Doe', value: 'John Doe',
language: 'en', language: 'en',
count: 1 count: 1
}, },
{ {
type: 'author', type: BrowseEntry.type,
authority: null, authority: null,
value: 'James Doe', value: 'James Doe',
language: 'en', language: 'en',
count: 3 count: 3
}, },
{ {
type: 'subject', type: BrowseEntry.type,
authority: null, authority: null,
value: 'Fake subject', value: 'Fake subject',
language: 'en', language: 'en',
@@ -68,12 +71,12 @@ describe('BrowseByMetadataPageComponent', () => {
]; ];
const mockBrowseService = { const mockBrowseService = {
getBrowseEntriesFor: (options: BrowseEntrySearchOptions) => toRemoteData(mockEntries.filter((entry) => entry.type === options.metadataDefinition)), getBrowseEntriesFor: (options: BrowseEntrySearchOptions) => toRemoteData(mockEntries),
getBrowseItemsFor: (value: string, options: BrowseEntrySearchOptions) => toRemoteData(mockItems) getBrowseItemsFor: (value: string, options: BrowseEntrySearchOptions) => toRemoteData(mockItems)
}; };
const mockDsoService = { const mockDsoService = {
findById: () => observableOf(new RemoteData(false, false, true, null, mockCommunity)) findById: () => createSuccessfulRemoteDataObject$(mockCommunity)
}; };
const activatedRouteStub = Object.assign(new ActivatedRouteStub(), { const activatedRouteStub = Object.assign(new ActivatedRouteStub(), {
@@ -105,12 +108,6 @@ describe('BrowseByMetadataPageComponent', () => {
fixture.detectChanges(); fixture.detectChanges();
}); });
it('should fetch the correct entries depending on the metadata definition', () => {
comp.browseEntries$.subscribe((result) => {
expect(result.payload.page).toEqual(mockEntries.filter((entry) => entry.type === 'author'));
});
});
it('should not fetch any items when no value is provided', () => { it('should not fetch any items when no value is provided', () => {
expect(comp.items$).toBeUndefined(); expect(comp.items$).toBeUndefined();
}); });
@@ -160,5 +157,5 @@ describe('BrowseByMetadataPageComponent', () => {
}); });
export function toRemoteData(objects: any[]): Observable<RemoteData<PaginatedList<any>>> { export function toRemoteData(objects: any[]): Observable<RemoteData<PaginatedList<any>>> {
return observableOf(new RemoteData(false, false, true, null, new PaginatedList(new PageInfo(), objects))); return createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), objects));
} }

View File

@@ -15,6 +15,7 @@ import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.serv
import { DSpaceObject } from '../../core/shared/dspace-object.model'; import { DSpaceObject } from '../../core/shared/dspace-object.model';
import { take } from 'rxjs/operators'; import { take } from 'rxjs/operators';
import { StartsWithType } from '../../shared/starts-with/starts-with-decorator'; import { StartsWithType } from '../../shared/starts-with/starts-with-decorator';
import { BrowseByType, rendersBrowseBy } from '../+browse-by-switcher/browse-by-decorator';
@Component({ @Component({
selector: 'ds-browse-by-metadata-page', selector: 'ds-browse-by-metadata-page',
@@ -23,9 +24,10 @@ import { StartsWithType } from '../../shared/starts-with/starts-with-decorator';
}) })
/** /**
* Component for browsing (items) by metadata definition * Component for browsing (items) by metadata definition
* A metadata definition is a short term used to describe one or multiple metadata fields. * A metadata definition (a.k.a. browse id) is a short term used to describe one or multiple metadata fields.
* An example would be 'author' for 'dc.contributor.*' * An example would be 'author' for 'dc.contributor.*'
*/ */
@rendersBrowseBy(BrowseByType.Metadata)
export class BrowseByMetadataPageComponent implements OnInit { export class BrowseByMetadataPageComponent implements OnInit {
/** /**
@@ -63,14 +65,14 @@ export class BrowseByMetadataPageComponent implements OnInit {
subs: Subscription[] = []; subs: Subscription[] = [];
/** /**
* The default metadata definition to resort to when none is provided * The default browse id to resort to when none is provided
*/ */
defaultMetadata = 'author'; defaultBrowseId = 'author';
/** /**
* The current metadata definition * The current browse id
*/ */
metadata = this.defaultMetadata; browseId = this.defaultBrowseId;
/** /**
* The type of StartsWith options to render * The type of StartsWith options to render
@@ -112,10 +114,10 @@ export class BrowseByMetadataPageComponent implements OnInit {
return Object.assign({}, params, queryParams); return Object.assign({}, params, queryParams);
}) })
.subscribe((params) => { .subscribe((params) => {
this.metadata = params.metadata || this.defaultMetadata; this.browseId = params.id || this.defaultBrowseId;
this.value = +params.value || params.value || ''; this.value = +params.value || params.value || '';
this.startsWith = +params.startsWith || params.startsWith; this.startsWith = +params.startsWith || params.startsWith;
const searchOptions = browseParamsToOptions(params, this.paginationConfig, this.sortConfig, this.metadata); const searchOptions = browseParamsToOptions(params, this.paginationConfig, this.sortConfig, this.browseId);
if (isNotEmpty(this.value)) { if (isNotEmpty(this.value)) {
this.updatePageWithItems(searchOptions, this.value); this.updatePageWithItems(searchOptions, this.value);
} else { } else {

View File

@@ -0,0 +1,12 @@
import { BrowseByType, rendersBrowseBy } from './browse-by-decorator';
describe('BrowseByDecorator', () => {
const titleDecorator = rendersBrowseBy(BrowseByType.Title);
const dateDecorator = rendersBrowseBy(BrowseByType.Date);
const metadataDecorator = rendersBrowseBy(BrowseByType.Metadata);
it('should have a decorator for all types', () => {
expect(titleDecorator.length).not.toEqual(0);
expect(dateDecorator.length).not.toEqual(0);
expect(metadataDecorator.length).not.toEqual(0);
});
});

View File

@@ -0,0 +1,37 @@
import { hasNoValue } from '../../shared/empty.util';
export enum BrowseByType {
Title = 'title',
Metadata = 'metadata',
Date = 'date'
}
export const DEFAULT_BROWSE_BY_TYPE = BrowseByType.Metadata;
const map = new Map();
/**
* Decorator used for rendering Browse-By pages by type
* @param browseByType The type of page
*/
export function rendersBrowseBy(browseByType: BrowseByType) {
return function decorator(component: any) {
if (hasNoValue(map.get(browseByType))) {
map.set(browseByType, component);
} else {
throw new Error(`There can't be more than one component to render Browse-By of type "${browseByType}"`);
}
};
}
/**
* Get the component used for rendering a Browse-By page by type
* @param browseByType The type of page
*/
export function getComponentByBrowseByType(browseByType) {
const comp = map.get(browseByType);
if (hasNoValue(comp)) {
map.get(DEFAULT_BROWSE_BY_TYPE);
}
return comp;
}

View File

@@ -0,0 +1 @@
<ng-container *ngComponentOutlet="browseByComponent | async"></ng-container>

View File

@@ -0,0 +1,55 @@
import { BrowseBySwitcherComponent } from './browse-by-switcher.component';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { ENV_CONFIG, GLOBAL_CONFIG } from '../../../config';
import { ActivatedRoute } from '@angular/router';
import * as decorator from './browse-by-decorator';
import createSpy = jasmine.createSpy;
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
describe('BrowseBySwitcherComponent', () => {
let comp: BrowseBySwitcherComponent;
let fixture: ComponentFixture<BrowseBySwitcherComponent>;
const types = ENV_CONFIG.browseBy.types;
const params = new BehaviorSubject(createParamsWithId('initialValue'));
const activatedRouteStub = {
params: params
};
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ BrowseBySwitcherComponent ],
providers: [
{ provide: GLOBAL_CONFIG, useValue: ENV_CONFIG },
{ provide: ActivatedRoute, useValue: activatedRouteStub }
],
schemas: [ NO_ERRORS_SCHEMA ]
}).compileComponents();
}));
beforeEach(async(() => {
fixture = TestBed.createComponent(BrowseBySwitcherComponent);
comp = fixture.componentInstance;
spyOnProperty(decorator, 'getComponentByBrowseByType').and.returnValue(createSpy('getComponentByItemType'));
}));
types.forEach((type) => {
describe(`when switching to a browse-by page for "${type.id}"`, () => {
beforeEach(() => {
params.next(createParamsWithId(type.id));
fixture.detectChanges();
});
it(`should call getComponentByBrowseByType with type "${type.type}"`, () => {
expect(decorator.getComponentByBrowseByType).toHaveBeenCalledWith(type.type);
});
});
});
});
export function createParamsWithId(id) {
return { id: id };
}

View File

@@ -0,0 +1,40 @@
import { Component, Inject, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Observable } from 'rxjs/internal/Observable';
import { GLOBAL_CONFIG, GlobalConfig } from '../../../config';
import { BrowseByTypeConfig } from '../../../config/browse-by-type-config.interface';
import { map, tap } from 'rxjs/operators';
import { getComponentByBrowseByType } from './browse-by-decorator';
@Component({
selector: 'ds-browse-by-switcher',
templateUrl: './browse-by-switcher.component.html'
})
/**
* Component for determining what Browse-By component to use depending on the metadata (browse ID) provided
*/
export class BrowseBySwitcherComponent implements OnInit {
/**
* Resolved browse-by component
*/
browseByComponent: Observable<any>;
public constructor(@Inject(GLOBAL_CONFIG) public config: GlobalConfig,
protected route: ActivatedRoute) {
}
/**
* Fetch the correct browse-by component by using the relevant config from environment.js
*/
ngOnInit(): void {
this.browseByComponent = this.route.params.pipe(
map((params) => {
const id = params.id;
return this.config.browseBy.types.find((config: BrowseByTypeConfig) => config.id === id);
}),
map((config: BrowseByTypeConfig) => getComponentByBrowseByType(config.type))
);
}
}

View File

@@ -17,6 +17,7 @@ import { RemoteData } from '../../core/data/remote-data';
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service'; import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
import { BrowseService } from '../../core/browse/browse.service'; import { BrowseService } from '../../core/browse/browse.service';
import { MockRouter } from '../../shared/mocks/mock-router'; import { MockRouter } from '../../shared/mocks/mock-router';
import { createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils';
describe('BrowseByTitlePageComponent', () => { describe('BrowseByTitlePageComponent', () => {
let comp: BrowseByTitlePageComponent; let comp: BrowseByTitlePageComponent;
@@ -52,7 +53,7 @@ describe('BrowseByTitlePageComponent', () => {
}; };
const mockDsoService = { const mockDsoService = {
findById: () => observableOf(new RemoteData(false, false, true, null, mockCommunity)) findById: () => createSuccessfulRemoteDataObject$(mockCommunity)
}; };
const activatedRouteStub = Object.assign(new ActivatedRouteStub(), { const activatedRouteStub = Object.assign(new ActivatedRouteStub(), {

View File

@@ -1,6 +1,5 @@
import { combineLatest as observableCombineLatest } from 'rxjs'; import { combineLatest as observableCombineLatest } from 'rxjs';
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { ItemDataService } from '../../core/data/item-data.service';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { hasValue } from '../../shared/empty.util'; import { hasValue } from '../../shared/empty.util';
import { import {
@@ -11,6 +10,7 @@ import { BrowseEntrySearchOptions } from '../../core/browse/browse-entry-search-
import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service'; import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service';
import { BrowseService } from '../../core/browse/browse.service'; import { BrowseService } from '../../core/browse/browse.service';
import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model'; import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model';
import { BrowseByType, rendersBrowseBy } from '../+browse-by-switcher/browse-by-decorator';
@Component({ @Component({
selector: 'ds-browse-by-title-page', selector: 'ds-browse-by-title-page',
@@ -20,6 +20,7 @@ import { SortDirection, SortOptions } from '../../core/cache/models/sort-options
/** /**
* Component for browsing items by title (dc.title) * Component for browsing items by title (dc.title)
*/ */
@rendersBrowseBy(BrowseByType.Title)
export class BrowseByTitlePageComponent extends BrowseByMetadataPageComponent { export class BrowseByTitlePageComponent extends BrowseByMetadataPageComponent {
public constructor(protected route: ActivatedRoute, public constructor(protected route: ActivatedRoute,
@@ -41,8 +42,8 @@ export class BrowseByTitlePageComponent extends BrowseByMetadataPageComponent {
return Object.assign({}, params, queryParams, data); return Object.assign({}, params, queryParams, data);
}) })
.subscribe((params) => { .subscribe((params) => {
this.metadata = params.metadata || this.defaultMetadata; this.browseId = params.id || this.defaultBrowseId;
this.updatePageWithItems(browseParamsToOptions(params, this.paginationConfig, this.sortConfig, this.metadata), undefined); this.updatePageWithItems(browseParamsToOptions(params, this.paginationConfig, this.sortConfig, this.browseId), undefined);
this.updateParent(params.scope) this.updateParent(params.scope)
})); }));
this.updateStartsWithTextOptions(); this.updateStartsWithTextOptions();

View File

@@ -1,6 +1,7 @@
import { first } from 'rxjs/operators'; import { first } from 'rxjs/operators';
import { BrowseByGuard } from './browse-by-guard'; import { BrowseByGuard } from './browse-by-guard';
import { of as observableOf } from 'rxjs'; import { of as observableOf } from 'rxjs';
import { ENV_CONFIG } from '../../config';
describe('BrowseByGuard', () => { describe('BrowseByGuard', () => {
describe('canActivate', () => { describe('canActivate', () => {
@@ -11,20 +12,20 @@ describe('BrowseByGuard', () => {
const name = 'An interesting DSO'; const name = 'An interesting DSO';
const title = 'Author'; const title = 'Author';
const field = 'Author'; const field = 'Author';
const metadata = 'author'; const id = 'author';
const metadataField = 'dc.contributor'; const metadataField = 'dc.contributor';
const scope = '1234-65487-12354-1235'; const scope = '1234-65487-12354-1235';
const value = 'Filter'; const value = 'Filter';
beforeEach(() => { beforeEach(() => {
dsoService = { dsoService = {
findById: (id: string) => observableOf({ payload: { name: name }, hasSucceeded: true }) findById: (dsoId: string) => observableOf({ payload: { name: name }, hasSucceeded: true })
}; };
translateService = { translateService = {
instant: () => field instant: () => field
}; };
guard = new BrowseByGuard(dsoService, translateService); guard = new BrowseByGuard(ENV_CONFIG, dsoService, translateService);
}); });
it('should return true, and sets up the data correctly, with a scope and value', () => { it('should return true, and sets up the data correctly, with a scope and value', () => {
@@ -34,7 +35,7 @@ describe('BrowseByGuard', () => {
metadataField, metadataField,
}, },
params: { params: {
metadata, id,
}, },
queryParams: { queryParams: {
scope, scope,
@@ -47,7 +48,7 @@ describe('BrowseByGuard', () => {
(canActivate) => { (canActivate) => {
const result = { const result = {
title, title,
metadata, id,
metadataField, metadataField,
collection: name, collection: name,
field, field,
@@ -66,7 +67,7 @@ describe('BrowseByGuard', () => {
metadataField, metadataField,
}, },
params: { params: {
metadata, id,
}, },
queryParams: { queryParams: {
scope scope
@@ -79,7 +80,7 @@ describe('BrowseByGuard', () => {
(canActivate) => { (canActivate) => {
const result = { const result = {
title, title,
metadata, id,
metadataField, metadataField,
collection: name, collection: name,
field, field,
@@ -98,7 +99,7 @@ describe('BrowseByGuard', () => {
metadataField, metadataField,
}, },
params: { params: {
metadata, id,
}, },
queryParams: { queryParams: {
value value
@@ -110,7 +111,7 @@ describe('BrowseByGuard', () => {
(canActivate) => { (canActivate) => {
const result = { const result = {
title, title,
metadata, id,
metadataField, metadataField,
collection: '', collection: '',
field, field,

View File

@@ -1,11 +1,12 @@
import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot } from '@angular/router'; import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot } from '@angular/router';
import { Injectable } from '@angular/core'; import { Inject, Injectable } from '@angular/core';
import { DSpaceObjectDataService } from '../core/data/dspace-object-data.service'; import { DSpaceObjectDataService } from '../core/data/dspace-object-data.service';
import { hasValue } from '../shared/empty.util'; import { hasNoValue, hasValue } from '../shared/empty.util';
import { map } from 'rxjs/operators'; import { map } from 'rxjs/operators';
import { getSucceededRemoteData } from '../core/shared/operators'; import { getSucceededRemoteData } from '../core/shared/operators';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { of as observableOf } from 'rxjs'; import { of as observableOf } from 'rxjs';
import { GLOBAL_CONFIG, GlobalConfig } from '../../config';
@Injectable() @Injectable()
/** /**
@@ -13,36 +14,43 @@ import { of as observableOf } from 'rxjs';
*/ */
export class BrowseByGuard implements CanActivate { export class BrowseByGuard implements CanActivate {
constructor(protected dsoService: DSpaceObjectDataService, constructor(@Inject(GLOBAL_CONFIG) public config: GlobalConfig,
protected dsoService: DSpaceObjectDataService,
protected translate: TranslateService) { protected translate: TranslateService) {
} }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
const title = route.data.title; const title = route.data.title;
const metadata = route.params.metadata || route.queryParams.metadata || route.data.metadata; const id = route.params.id || route.queryParams.id || route.data.id;
const metadataField = route.data.metadataField; let metadataField = route.data.metadataField;
if (hasNoValue(metadataField) && hasValue(id)) {
const config = this.config.browseBy.types.find((conf) => conf.id === id);
if (hasValue(config) && hasValue(config.metadataField)) {
metadataField = config.metadataField;
}
}
const scope = route.queryParams.scope; const scope = route.queryParams.scope;
const value = route.queryParams.value; const value = route.queryParams.value;
const metadataTranslated = this.translate.instant('browse.metadata.' + metadata); const metadataTranslated = this.translate.instant('browse.metadata.' + id);
if (hasValue(scope)) { if (hasValue(scope)) {
const dsoAndMetadata$ = this.dsoService.findById(scope).pipe(getSucceededRemoteData()); const dsoAndMetadata$ = this.dsoService.findById(scope).pipe(getSucceededRemoteData());
return dsoAndMetadata$.pipe( return dsoAndMetadata$.pipe(
map((dsoRD) => { map((dsoRD) => {
const name = dsoRD.payload.name; const name = dsoRD.payload.name;
route.data = this.createData(title, metadata, metadataField, name, metadataTranslated, value); route.data = this.createData(title, id, metadataField, name, metadataTranslated, value);
return true; return true;
}) })
); );
} else { } else {
route.data = this.createData(title, metadata, metadataField, '', metadataTranslated, value); route.data = this.createData(title, id, metadataField, '', metadataTranslated, value);
return observableOf(true); return observableOf(true);
} }
} }
private createData(title, metadata, metadataField, collection, field, value) { private createData(title, id, metadataField, collection, field, value) {
return { return {
title: title, title: title,
metadata: metadata, id: id,
metadataField: metadataField, metadataField: metadataField,
collection: collection, collection: collection,
field: field, field: field,

View File

@@ -1,16 +1,12 @@
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { BrowseByTitlePageComponent } from './+browse-by-title-page/browse-by-title-page.component';
import { BrowseByMetadataPageComponent } from './+browse-by-metadata-page/browse-by-metadata-page.component';
import { BrowseByDatePageComponent } from './+browse-by-date-page/browse-by-date-page.component';
import { BrowseByGuard } from './browse-by-guard'; import { BrowseByGuard } from './browse-by-guard';
import { BrowseBySwitcherComponent } from './+browse-by-switcher/browse-by-switcher.component';
@NgModule({ @NgModule({
imports: [ imports: [
RouterModule.forChild([ RouterModule.forChild([
{ path: 'title', component: BrowseByTitlePageComponent, canActivate: [BrowseByGuard], data: { metadata: 'title', title: 'browse.title' } }, { path: ':id', component: BrowseBySwitcherComponent, canActivate: [BrowseByGuard], data: { title: 'browse.title' } }
{ path: 'dateissued', component: BrowseByDatePageComponent, canActivate: [BrowseByGuard], data: { metadata: 'dateissued', metadataField: 'dc.date.issued', title: 'browse.title' } },
{ path: ':metadata', component: BrowseByMetadataPageComponent, canActivate: [BrowseByGuard], data: { title: 'browse.title' } }
]) ])
] ]
}) })

View File

@@ -8,6 +8,7 @@ import { BrowseService } from '../core/browse/browse.service';
import { BrowseByMetadataPageComponent } from './+browse-by-metadata-page/browse-by-metadata-page.component'; import { BrowseByMetadataPageComponent } from './+browse-by-metadata-page/browse-by-metadata-page.component';
import { BrowseByDatePageComponent } from './+browse-by-date-page/browse-by-date-page.component'; import { BrowseByDatePageComponent } from './+browse-by-date-page/browse-by-date-page.component';
import { BrowseByGuard } from './browse-by-guard'; import { BrowseByGuard } from './browse-by-guard';
import { BrowseBySwitcherComponent } from './+browse-by-switcher/browse-by-switcher.component';
@NgModule({ @NgModule({
imports: [ imports: [
@@ -18,12 +19,18 @@ import { BrowseByGuard } from './browse-by-guard';
declarations: [ declarations: [
BrowseByTitlePageComponent, BrowseByTitlePageComponent,
BrowseByMetadataPageComponent, BrowseByMetadataPageComponent,
BrowseByDatePageComponent BrowseByDatePageComponent,
BrowseBySwitcherComponent
], ],
providers: [ providers: [
ItemDataService, ItemDataService,
BrowseService, BrowseService,
BrowseByGuard BrowseByGuard
],
entryComponents: [
BrowseByTitlePageComponent,
BrowseByMetadataPageComponent,
BrowseByDatePageComponent
] ]
}) })
export class BrowseByModule { export class BrowseByModule {

View File

@@ -1,12 +1,9 @@
import { Component, Input } from '@angular/core'; import { Component, Input } from '@angular/core';
import { import { DynamicInputModel, DynamicTextAreaModel } from '@ng-dynamic-forms/core';
DynamicInputModel,
DynamicTextAreaModel
} from '@ng-dynamic-forms/core';
import { DynamicFormControlModel } from '@ng-dynamic-forms/core/src/model/dynamic-form-control.model'; import { DynamicFormControlModel } from '@ng-dynamic-forms/core/src/model/dynamic-form-control.model';
import { ResourceType } from '../../core/shared/resource-type';
import { Collection } from '../../core/shared/collection.model'; import { Collection } from '../../core/shared/collection.model';
import { ComColFormComponent } from '../../shared/comcol-forms/comcol-form/comcol-form.component'; import { ComColFormComponent } from '../../shared/comcol-forms/comcol-form/comcol-form.component';
import { NormalizedCollection } from '../../core/cache/models/normalized-collection.model';
/** /**
* Form used for creating and editing collections * Form used for creating and editing collections
@@ -23,9 +20,9 @@ export class CollectionFormComponent extends ComColFormComponent<Collection> {
@Input() dso: Collection = new Collection(); @Input() dso: Collection = new Collection();
/** /**
* @type {ResourceType.Collection} This is a collection-type form * @type {Collection.type} This is a collection-type form
*/ */
protected type = ResourceType.Collection; protected type = Collection.type;
/** /**
* The dynamic form fields used for creating/editing a collection * The dynamic form fields used for creating/editing a collection

View File

@@ -1 +0,0 @@
@import '../../styles/variables.scss';

View File

@@ -1,9 +1,11 @@
import { CreateCollectionPageGuard } from './create-collection-page.guard'; import { CreateCollectionPageGuard } from './create-collection-page.guard';
import { MockRouter } from '../../shared/mocks/mock-router'; import { MockRouter } from '../../shared/mocks/mock-router';
import { RemoteData } from '../../core/data/remote-data';
import { Community } from '../../core/shared/community.model'; import { Community } from '../../core/shared/community.model';
import { of as observableOf } from 'rxjs';
import { first } from 'rxjs/operators'; import { first } from 'rxjs/operators';
import {
createFailedRemoteDataObject$,
createSuccessfulRemoteDataObject$
} from '../../shared/testing/utils';
describe('CreateCollectionPageGuard', () => { describe('CreateCollectionPageGuard', () => {
describe('canActivate', () => { describe('canActivate', () => {
@@ -15,11 +17,11 @@ describe('CreateCollectionPageGuard', () => {
communityDataServiceStub = { communityDataServiceStub = {
findById: (id: string) => { findById: (id: string) => {
if (id === 'valid-id') { if (id === 'valid-id') {
return observableOf(new RemoteData(false, false, true, null, new Community())); return createSuccessfulRemoteDataObject$(new Community());
} else if (id === 'invalid-id') { } else if (id === 'invalid-id') {
return observableOf(new RemoteData(false, false, true, null, undefined)); return createSuccessfulRemoteDataObject$(undefined);
} else if (id === 'error-id') { } else if (id === 'error-id') {
return observableOf(new RemoteData(false, false, false, null, new Community())); return createFailedRemoteDataObject$(new Community());
} }
} }
}; };

View File

@@ -20,9 +20,9 @@ export class CommunityFormComponent extends ComColFormComponent<Community> {
@Input() dso: Community = new Community(); @Input() dso: Community = new Community();
/** /**
* @type {ResourceType.Community} This is a community-type form * @type {Community.type} This is a community-type form
*/ */
protected type = ResourceType.Community; protected type = Community.type;
/** /**
* The dynamic form fields used for creating/editing a community * The dynamic form fields used for creating/editing a community

View File

@@ -1 +0,0 @@
@import '../../styles/variables.scss';

View File

@@ -1,9 +1,11 @@
import { CreateCommunityPageGuard } from './create-community-page.guard'; import { CreateCommunityPageGuard } from './create-community-page.guard';
import { MockRouter } from '../../shared/mocks/mock-router'; import { MockRouter } from '../../shared/mocks/mock-router';
import { RemoteData } from '../../core/data/remote-data';
import { Community } from '../../core/shared/community.model'; import { Community } from '../../core/shared/community.model';
import { of as observableOf } from 'rxjs';
import { first } from 'rxjs/operators'; import { first } from 'rxjs/operators';
import {
createFailedRemoteDataObject$,
createSuccessfulRemoteDataObject$
} from '../../shared/testing/utils';
describe('CreateCommunityPageGuard', () => { describe('CreateCommunityPageGuard', () => {
describe('canActivate', () => { describe('canActivate', () => {
@@ -15,11 +17,11 @@ describe('CreateCommunityPageGuard', () => {
communityDataServiceStub = { communityDataServiceStub = {
findById: (id: string) => { findById: (id: string) => {
if (id === 'valid-id') { if (id === 'valid-id') {
return observableOf(new RemoteData(false, false, true, null, new Community())); return createSuccessfulRemoteDataObject$(new Community());
} else if (id === 'invalid-id') { } else if (id === 'invalid-id') {
return observableOf(new RemoteData(false, false, true, null, undefined)); return createSuccessfulRemoteDataObject$(undefined);
} else if (id === 'error-id') { } else if (id === 'error-id') {
return observableOf(new RemoteData(false, false, false, null, new Community())); return createFailedRemoteDataObject$(new Community());
} }
} }
}; };

View File

@@ -1 +0,0 @@
@import '../../../styles/variables.scss';

View File

@@ -1 +0,0 @@
@import '../../../styles/variables.scss';

View File

@@ -11,6 +11,7 @@ import {RouterTestingModule} from '@angular/router/testing';
import {NoopAnimationsModule} from '@angular/platform-browser/animations'; import {NoopAnimationsModule} from '@angular/platform-browser/animations';
import {By} from '@angular/platform-browser'; import {By} from '@angular/platform-browser';
import {of as observableOf, Observable } from 'rxjs'; import {of as observableOf, Observable } from 'rxjs';
import { createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils';
describe('SubCommunityList Component', () => { describe('SubCommunityList Component', () => {
let comp: CommunityPageSubCommunityListComponent; let comp: CommunityPageSubCommunityListComponent;
@@ -40,8 +41,7 @@ describe('SubCommunityList Component', () => {
{ language: 'en_US', value: 'Test title' } { language: 'en_US', value: 'Test title' }
] ]
}, },
subcommunities: observableOf(new RemoteData(true, true, true, subcommunities: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), []))
undefined, new PaginatedList(new PageInfo(), [])))
}); });
const mockCommunity = Object.assign(new Community(), { const mockCommunity = Object.assign(new Community(), {
@@ -50,8 +50,7 @@ describe('SubCommunityList Component', () => {
{ language: 'en_US', value: 'Test title' } { language: 'en_US', value: 'Test title' }
] ]
}, },
subcommunities: observableOf(new RemoteData(true, true, true, subcommunities: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), subcommunities))
undefined, new PaginatedList(new PageInfo(), subcommunities)))
}) })
; ;

View File

@@ -1,16 +1,14 @@
@import '../../../styles/variables.scss';
:host { :host {
display: block; display: block;
margin-top: -$content-spacing; margin-top: -$content-spacing;
margin-bottom: -$content-spacing; margin-bottom: -$content-spacing;
} }
.display-3 { .display-3 {
word-break: break-word; word-break: break-word;
} }
.dspace-logo { .dspace-logo {
height: 110px; height: 110px;
width: 110px; width: 110px;
} }

View File

@@ -1 +1,2 @@
@import '../../styles/variables.scss'; :host {
}

View File

@@ -2,6 +2,10 @@ import {RemoteData} from '../../core/data/remote-data';
import {hot} from 'jasmine-marbles'; import {hot} from 'jasmine-marbles';
import {Item} from '../../core/shared/item.model'; import {Item} from '../../core/shared/item.model';
import {findSuccessfulAccordingTo} from './edit-item-operators'; import {findSuccessfulAccordingTo} from './edit-item-operators';
import {
createFailedRemoteDataObject,
createSuccessfulRemoteDataObject
} from '../../shared/testing/utils';
describe('findSuccessfulAccordingTo', () => { describe('findSuccessfulAccordingTo', () => {
let mockItem1; let mockItem1;
@@ -19,11 +23,11 @@ describe('findSuccessfulAccordingTo', () => {
}); });
it('should return first successful RemoteData Observable that complies to predicate', () => { it('should return first successful RemoteData Observable that complies to predicate', () => {
const testRD = { const testRD = {
a: new RemoteData(false, false, true, null, undefined), a: createSuccessfulRemoteDataObject(undefined),
b: new RemoteData(false, false, false, null, mockItem1), b: createFailedRemoteDataObject(mockItem1),
c: new RemoteData(false, false, true, null, mockItem2), c: createSuccessfulRemoteDataObject(mockItem2),
d: new RemoteData(false, false, true, null, mockItem1), d: createSuccessfulRemoteDataObject(mockItem1),
e: new RemoteData(false, false, true, null, mockItem2), e: createSuccessfulRemoteDataObject(mockItem2),
}; };
const source = hot('abcde', testRD); const source = hot('abcde', testRD);

View File

@@ -1,5 +1,3 @@
@import '../../../styles/variables.scss';
.btn { .btn {
min-width: $edit-item-button-min-width; min-width: $edit-item-button-min-width;
} }

View File

@@ -1 +0,0 @@
@import '../../../../styles/variables.scss';

View File

@@ -17,6 +17,7 @@ import { By } from '@angular/platform-browser';
import { ItemDeleteComponent } from './item-delete.component'; import { ItemDeleteComponent } from './item-delete.component';
import { getItemEditPath } from '../../item-page-routing.module'; import { getItemEditPath } from '../../item-page-routing.module';
import { RestResponse } from '../../../core/cache/response.models'; import { RestResponse } from '../../../core/cache/response.models';
import { createSuccessfulRemoteDataObject } from '../../../shared/testing/utils';
let comp: ItemDeleteComponent; let comp: ItemDeleteComponent;
let fixture: ComponentFixture<ItemDeleteComponent>; let fixture: ComponentFixture<ItemDeleteComponent>;
@@ -49,7 +50,7 @@ describe('ItemDeleteComponent', () => {
routeStub = { routeStub = {
data: observableOf({ data: observableOf({
item: new RemoteData(false, false, true, null, mockItem) item: createSuccessfulRemoteDataObject(mockItem)
}) })
}; };

View File

@@ -1,4 +1,3 @@
@import '../../../../../styles/variables.scss';
.btn[disabled] { .btn[disabled] {
color: $gray-600; color: $gray-600;
border-color: $gray-600; border-color: $gray-600;

View File

@@ -6,17 +6,18 @@ import { ObjectUpdatesService } from '../../../../core/data/object-updates/objec
import { of as observableOf } from 'rxjs'; import { of as observableOf } from 'rxjs';
import { RemoteData } from '../../../../core/data/remote-data'; import { RemoteData } from '../../../../core/data/remote-data';
import { PaginatedList } from '../../../../core/data/paginated-list'; import { PaginatedList } from '../../../../core/data/paginated-list';
import { MetadataField } from '../../../../core/metadata/metadatafield.model';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
import { SharedModule } from '../../../../shared/shared.module'; import { SharedModule } from '../../../../shared/shared.module';
import { getTestScheduler } from 'jasmine-marbles'; import { getTestScheduler } from 'jasmine-marbles';
import { InputSuggestion } from '../../../../shared/input-suggestions/input-suggestions.model'; import { InputSuggestion } from '../../../../shared/input-suggestions/input-suggestions.model';
import { TestScheduler } from 'rxjs/testing'; import { TestScheduler } from 'rxjs/testing';
import { MetadataSchema } from '../../../../core/metadata/metadataschema.model';
import { FieldChangeType } from '../../../../core/data/object-updates/object-updates.actions'; import { FieldChangeType } from '../../../../core/data/object-updates/object-updates.actions';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { MetadatumViewModel } from '../../../../core/shared/metadata.models'; import { MetadatumViewModel } from '../../../../core/shared/metadata.models';
import { MetadataSchema } from '../../../../core/metadata/metadata-schema.model';
import { MetadataField } from '../../../../core/metadata/metadata-field.model';
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';
let comp: EditInPlaceFieldComponent; let comp: EditInPlaceFieldComponent;
let fixture: ComponentFixture<EditInPlaceFieldComponent>; let fixture: ComponentFixture<EditInPlaceFieldComponent>;
@@ -59,7 +60,7 @@ describe('EditInPlaceFieldComponent', () => {
paginatedMetadataFields = new PaginatedList(undefined, [mdField1, mdField2, mdField3]); paginatedMetadataFields = new PaginatedList(undefined, [mdField1, mdField2, mdField3]);
metadataFieldService = jasmine.createSpyObj({ metadataFieldService = jasmine.createSpyObj({
queryMetadataFields: observableOf(new RemoteData(false, false, true, undefined, paginatedMetadataFields)), queryMetadataFields: createSuccessfulRemoteDataObject$(paginatedMetadataFields),
}); });
objectUpdatesService = jasmine.createSpyObj('objectUpdatesService', objectUpdatesService = jasmine.createSpyObj('objectUpdatesService',
{ {

View File

@@ -4,13 +4,13 @@ import { RegistryService } from '../../../../core/registry/registry.service';
import { cloneDeep } from 'lodash'; import { cloneDeep } from 'lodash';
import { BehaviorSubject, Observable, of as observableOf } from 'rxjs'; import { BehaviorSubject, Observable, of as observableOf } from 'rxjs';
import { map, take } from 'rxjs/operators'; import { map, take } from 'rxjs/operators';
import { MetadataField } from '../../../../core/metadata/metadatafield.model';
import { InputSuggestion } from '../../../../shared/input-suggestions/input-suggestions.model'; import { InputSuggestion } from '../../../../shared/input-suggestions/input-suggestions.model';
import { FieldChangeType } from '../../../../core/data/object-updates/object-updates.actions'; import { FieldChangeType } from '../../../../core/data/object-updates/object-updates.actions';
import { FieldUpdate } from '../../../../core/data/object-updates/object-updates.reducer'; import { FieldUpdate } from '../../../../core/data/object-updates/object-updates.reducer';
import { ObjectUpdatesService } from '../../../../core/data/object-updates/object-updates.service'; import { ObjectUpdatesService } from '../../../../core/data/object-updates/object-updates.service';
import { NgModel } from '@angular/forms'; import { NgModel } from '@angular/forms';
import { MetadatumViewModel } from '../../../../core/shared/metadata.models'; import { MetadatumViewModel } from '../../../../core/shared/metadata.models';
import { MetadataField } from '../../../../core/metadata/metadata-field.model';
@Component({ @Component({
// tslint:disable-next-line:component-selector // tslint:disable-next-line:component-selector

View File

@@ -1,5 +1,3 @@
@import '../../../../styles/variables.scss';
.button-row { .button-row {
.btn { .btn {
margin-right: 0.5 * $spacer; margin-right: 0.5 * $spacer;

View File

@@ -20,13 +20,16 @@ import { RouterStub } from '../../../shared/testing/router-stub';
import { GLOBAL_CONFIG } from '../../../../config'; import { GLOBAL_CONFIG } from '../../../../config';
import { Item } from '../../../core/shared/item.model'; import { Item } from '../../../core/shared/item.model';
import { FieldChangeType } from '../../../core/data/object-updates/object-updates.actions'; import { FieldChangeType } from '../../../core/data/object-updates/object-updates.actions';
import { RemoteData } from '../../../core/data/remote-data';
import { MetadatumViewModel } from '../../../core/shared/metadata.models'; import { MetadatumViewModel } from '../../../core/shared/metadata.models';
import { RegistryService } from '../../../core/registry/registry.service'; import { RegistryService } from '../../../core/registry/registry.service';
import { PaginatedList } from '../../../core/data/paginated-list'; import { PaginatedList } from '../../../core/data/paginated-list';
import { MetadataSchema } from '../../../core/metadata/metadataschema.model';
import { MetadataField } from '../../../core/metadata/metadatafield.model';
import { Metadata } from '../../../core/shared/metadata.utils'; import { Metadata } from '../../../core/shared/metadata.utils';
import { MetadataSchema } from '../../../core/metadata/metadata-schema.model';
import { MetadataField } from '../../../core/metadata/metadata-field.model';
import {
createSuccessfulRemoteDataObject,
createSuccessfulRemoteDataObject$
} from '../../../shared/testing/utils';
let comp: ItemMetadataComponent; let comp: ItemMetadataComponent;
let fixture: ComponentFixture<ItemMetadataComponent>; let fixture: ComponentFixture<ItemMetadataComponent>;
@@ -116,18 +119,18 @@ describe('ItemMetadataComponent', () => {
) )
; ;
itemService = jasmine.createSpyObj('itemService', { itemService = jasmine.createSpyObj('itemService', {
update: observableOf(new RemoteData(false, false, true, undefined, item)), update: createSuccessfulRemoteDataObject$(item),
commitUpdates: {} commitUpdates: {}
}); });
routeStub = { routeStub = {
parent: { parent: {
data: observableOf({ item: new RemoteData(false, false, true, null, item) }) data: observableOf({ item: createSuccessfulRemoteDataObject(item) })
} }
}; };
paginatedMetadataFields = new PaginatedList(undefined, [mdField1, mdField2, mdField3]); paginatedMetadataFields = new PaginatedList(undefined, [mdField1, mdField2, mdField3]);
metadataFieldService = jasmine.createSpyObj({ metadataFieldService = jasmine.createSpyObj({
getAllMetadataFields: observableOf(new RemoteData(false, false, true, undefined, paginatedMetadataFields)) getAllMetadataFields:createSuccessfulRemoteDataObject$(paginatedMetadataFields)
}); });
scheduler = getTestScheduler(); scheduler = getTestScheduler();
objectUpdatesService = jasmine.createSpyObj('objectUpdatesService', objectUpdatesService = jasmine.createSpyObj('objectUpdatesService',

View File

@@ -17,9 +17,9 @@ import { NotificationsService } from '../../../shared/notifications/notification
import { GLOBAL_CONFIG, GlobalConfig } from '../../../../config'; import { GLOBAL_CONFIG, GlobalConfig } from '../../../../config';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { RegistryService } from '../../../core/registry/registry.service'; import { RegistryService } from '../../../core/registry/registry.service';
import { MetadataField } from '../../../core/metadata/metadatafield.model';
import { MetadatumViewModel } from '../../../core/shared/metadata.models'; import { MetadatumViewModel } from '../../../core/shared/metadata.models';
import { Metadata } from '../../../core/shared/metadata.utils'; import { Metadata } from '../../../core/shared/metadata.utils';
import { MetadataField } from '../../../core/metadata/metadata-field.model';
@Component({ @Component({
selector: 'ds-item-metadata', selector: 'ds-item-metadata',

View File

@@ -16,6 +16,7 @@ import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { ItemPrivateComponent } from './item-private.component'; import { ItemPrivateComponent } from './item-private.component';
import { RestResponse } from '../../../core/cache/response.models'; import { RestResponse } from '../../../core/cache/response.models';
import { createSuccessfulRemoteDataObject } from '../../../shared/testing/utils';
let comp: ItemPrivateComponent; let comp: ItemPrivateComponent;
let fixture: ComponentFixture<ItemPrivateComponent>; let fixture: ComponentFixture<ItemPrivateComponent>;
@@ -50,7 +51,7 @@ describe('ItemPrivateComponent', () => {
routeStub = { routeStub = {
data: observableOf({ data: observableOf({
item: new RemoteData(false, false, true, null, { item: createSuccessfulRemoteDataObject({
id: 'fake-id' id: 'fake-id'
}) })
}) })

View File

@@ -16,6 +16,7 @@ import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { ItemPublicComponent } from './item-public.component'; import { ItemPublicComponent } from './item-public.component';
import { RestResponse } from '../../../core/cache/response.models'; import { RestResponse } from '../../../core/cache/response.models';
import { createSuccessfulRemoteDataObject } from '../../../shared/testing/utils';
let comp: ItemPublicComponent; let comp: ItemPublicComponent;
let fixture: ComponentFixture<ItemPublicComponent>; let fixture: ComponentFixture<ItemPublicComponent>;
@@ -50,7 +51,7 @@ describe('ItemPublicComponent', () => {
routeStub = { routeStub = {
data: observableOf({ data: observableOf({
item: new RemoteData(false, false, true, null, { item: createSuccessfulRemoteDataObject({
id: 'fake-id' id: 'fake-id'
}) })
}) })

View File

@@ -16,6 +16,7 @@ import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { ItemReinstateComponent } from './item-reinstate.component'; import { ItemReinstateComponent } from './item-reinstate.component';
import { RestResponse } from '../../../core/cache/response.models'; import { RestResponse } from '../../../core/cache/response.models';
import { createSuccessfulRemoteDataObject } from '../../../shared/testing/utils';
let comp: ItemReinstateComponent; let comp: ItemReinstateComponent;
let fixture: ComponentFixture<ItemReinstateComponent>; let fixture: ComponentFixture<ItemReinstateComponent>;
@@ -50,7 +51,7 @@ describe('ItemReinstateComponent', () => {
routeStub = { routeStub = {
data: observableOf({ data: observableOf({
item: new RemoteData(false, false, true, null, { item: createSuccessfulRemoteDataObject({
id: 'fake-id' id: 'fake-id'
}) })
}) })

View File

@@ -12,7 +12,7 @@
{{'item.edit.tabs.status.labels.itemPage' | translate}}: {{'item.edit.tabs.status.labels.itemPage' | translate}}:
</div> </div>
<div class="col-9 float-left status-data" id="status-itemPage"> <div class="col-9 float-left status-data" id="status-itemPage">
<a href="{{getItemPage((itemRD$ | async)?.payload)}}">{{getItemPage((itemRD$ | async)?.payload)}}</a> <a [routerLink]="getItemPage((itemRD$ | async)?.payload)">{{getItemPage((itemRD$ | async)?.payload)}}</a>
</div> </div>
<div *ngFor="let operation of operations" class="w-100 pt-3"> <div *ngFor="let operation of operations" class="w-100 pt-3">

View File

@@ -11,7 +11,7 @@ import { Item } from '../../../core/shared/item.model';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { of as observableOf } from 'rxjs'; import { of as observableOf } from 'rxjs';
import { RemoteData } from '../../../core/data/remote-data'; import { createSuccessfulRemoteDataObject } from '../../../shared/testing/utils';
describe('ItemStatusComponent', () => { describe('ItemStatusComponent', () => {
let comp: ItemStatusComponent; let comp: ItemStatusComponent;
@@ -27,7 +27,7 @@ describe('ItemStatusComponent', () => {
const routeStub = { const routeStub = {
parent: { parent: {
data: observableOf({ item: new RemoteData(false, false, true, null, mockItem) }) data: observableOf({ item: createSuccessfulRemoteDataObject(mockItem) })
} }
}; };

View File

@@ -16,6 +16,7 @@ import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { ItemWithdrawComponent } from './item-withdraw.component'; import { ItemWithdrawComponent } from './item-withdraw.component';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { RestResponse } from '../../../core/cache/response.models'; import { RestResponse } from '../../../core/cache/response.models';
import { createSuccessfulRemoteDataObject } from '../../../shared/testing/utils';
let comp: ItemWithdrawComponent; let comp: ItemWithdrawComponent;
let fixture: ComponentFixture<ItemWithdrawComponent>; let fixture: ComponentFixture<ItemWithdrawComponent>;
@@ -50,7 +51,7 @@ describe('ItemWithdrawComponent', () => {
routeStub = { routeStub = {
data: observableOf({ data: observableOf({
item: new RemoteData(false, false, true, null, { item: createSuccessfulRemoteDataObject({
id: 'fake-id' id: 'fake-id'
}) })
}) })

View File

@@ -17,6 +17,10 @@ import { By } from '@angular/platform-browser';
import { of as observableOf } from 'rxjs'; import { of as observableOf } from 'rxjs';
import { getItemEditPath } from '../../item-page-routing.module'; import { getItemEditPath } from '../../item-page-routing.module';
import { RestResponse } from '../../../core/cache/response.models'; import { RestResponse } from '../../../core/cache/response.models';
import {
createSuccessfulRemoteDataObject,
createSuccessfulRemoteDataObject$
} from '../../../shared/testing/utils';
/** /**
* Test component that implements the AbstractSimpleItemActionComponent used to test the * Test component that implements the AbstractSimpleItemActionComponent used to test the
@@ -65,12 +69,12 @@ describe('AbstractSimpleItemActionComponent', () => {
}); });
mockItemDataService = jasmine.createSpyObj({ mockItemDataService = jasmine.createSpyObj({
findById: observableOf(new RemoteData(false, false, true, undefined, mockItem)) findById: createSuccessfulRemoteDataObject$(mockItem)
}); });
routeStub = { routeStub = {
data: observableOf({ data: observableOf({
item: new RemoteData(false, false, true, null, { item: createSuccessfulRemoteDataObject({
id: 'fake-id' id: 'fake-id'
}) })
}) })

View File

@@ -9,6 +9,10 @@ import { Item } from '../../../core/shared/item.model';
import { of as observableOf } from 'rxjs'; import { of as observableOf } from 'rxjs';
import { RemoteData } from '../../../core/data/remote-data'; import { RemoteData } from '../../../core/data/remote-data';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import {
createFailedRemoteDataObject$,
createSuccessfulRemoteDataObject$
} from '../../../shared/testing/utils';
let collectionsComponent: CollectionsComponent; let collectionsComponent: CollectionsComponent;
let fixture: ComponentFixture<CollectionsComponent>; let fixture: ComponentFixture<CollectionsComponent>;
@@ -24,8 +28,8 @@ const mockCollection1: Collection = Object.assign(new Collection(), {
} }
}); });
const succeededMockItem: Item = Object.assign(new Item(), {owningCollection: observableOf(new RemoteData(false, false, true, null, mockCollection1))}); const succeededMockItem: Item = Object.assign(new Item(), {owningCollection: createSuccessfulRemoteDataObject$(mockCollection1)});
const failedMockItem: Item = Object.assign(new Item(), {owningCollection: observableOf(new RemoteData(false, false, false, null, mockCollection1))}); const failedMockItem: Item = Object.assign(new Item(), {owningCollection: createFailedRemoteDataObject$(mockCollection1)});
describe('CollectionsComponent', () => { describe('CollectionsComponent', () => {
beforeEach(async(() => { beforeEach(async(() => {

View File

@@ -1,5 +1,3 @@
@import '../../../../styles/variables.scss';
:host { :host {
.simple-view-element { .simple-view-element {
margin-bottom: 15px; margin-bottom: 15px;

View File

@@ -1 +0,0 @@
@import '../../../../styles/variables.scss';

View File

@@ -1 +0,0 @@
@import '../../../../styles/variables.scss';

View File

@@ -1,5 +1,3 @@
@import '../../../../../styles/variables';
@import '../../../../../styles/mixins';
@media screen and (min-width: map-get($grid-breakpoints, md)) { @media screen and (min-width: map-get($grid-breakpoints, md)) {
dt { dt {
text-align: right; text-align: right;

View File

@@ -1,5 +1,3 @@
@import '../../../styles/variables.scss';
:host { :host {
div.simple-view-link { div.simple-view-link {
text-align: center; text-align: center;

View File

@@ -17,9 +17,13 @@ import { RemoteData } from '../../core/data/remote-data';
import { of as observableOf } from 'rxjs'; import { of as observableOf } from 'rxjs';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import {
createSuccessfulRemoteDataObject,
createSuccessfulRemoteDataObject$
} from '../../shared/testing/utils';
const mockItem: Item = Object.assign(new Item(), { const mockItem: Item = Object.assign(new Item(), {
bitstreams: observableOf(new RemoteData(false, false, true, null, new PaginatedList(new PageInfo(), []))), bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: { metadata: {
'dc.title': [ 'dc.title': [
{ {
@@ -30,7 +34,7 @@ const mockItem: Item = Object.assign(new Item(), {
} }
}); });
const routeStub = Object.assign(new ActivatedRouteStub(), { const routeStub = Object.assign(new ActivatedRouteStub(), {
data: observableOf({ item: new RemoteData(false, false, true, null, mockItem) }) data: observableOf({ item: createSuccessfulRemoteDataObject(mockItem) })
}); });
const metadataServiceStub = { const metadataServiceStub = {
/* tslint:disable:no-empty */ /* tslint:disable:no-empty */

View File

@@ -11,6 +11,7 @@ import { ItemPageFieldComponent } from './item-page-field.component';
import { MetadataValuesComponent } from '../../../field-components/metadata-values/metadata-values.component'; import { MetadataValuesComponent } from '../../../field-components/metadata-values/metadata-values.component';
import { of as observableOf } from 'rxjs'; import { of as observableOf } from 'rxjs';
import { MetadataMap, MetadataValue } from '../../../../core/shared/metadata.models'; import { MetadataMap, MetadataValue } from '../../../../core/shared/metadata.models';
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';
let comp: ItemPageFieldComponent; let comp: ItemPageFieldComponent;
let fixture: ComponentFixture<ItemPageFieldComponent>; let fixture: ComponentFixture<ItemPageFieldComponent>;
@@ -52,7 +53,7 @@ describe('ItemPageFieldComponent', () => {
export function mockItemWithMetadataFieldAndValue(field: string, value: string): Item { export function mockItemWithMetadataFieldAndValue(field: string, value: string): Item {
const item = Object.assign(new Item(), { const item = Object.assign(new Item(), {
bitstreams: observableOf(new RemoteData(false, false, true, null, new PaginatedList(new PageInfo(), []))), bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: new MetadataMap() metadata: new MetadataMap()
}); });
item.metadata[field] = [{ item.metadata[field] = [{

View File

@@ -16,9 +16,13 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { createRelationshipsObservable } from './item-types/shared/item.component.spec'; import { createRelationshipsObservable } from './item-types/shared/item.component.spec';
import { of as observableOf } from 'rxjs'; import { of as observableOf } from 'rxjs';
import {
createFailedRemoteDataObject$, createPendingRemoteDataObject$, createSuccessfulRemoteDataObject,
createSuccessfulRemoteDataObject$
} from '../../shared/testing/utils';
const mockItem: Item = Object.assign(new Item(), { const mockItem: Item = Object.assign(new Item(), {
bitstreams: observableOf(new RemoteData(false, false, true, null, new PaginatedList(new PageInfo(), []))), bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: [], metadata: [],
relationships: createRelationshipsObservable() relationships: createRelationshipsObservable()
}); });
@@ -33,7 +37,7 @@ describe('ItemPageComponent', () => {
/* tslint:enable:no-empty */ /* tslint:enable:no-empty */
}; };
const mockRoute = Object.assign(new ActivatedRouteStub(), { const mockRoute = Object.assign(new ActivatedRouteStub(), {
data: observableOf({ item: new RemoteData(false, false, true, null, mockItem) }) data: observableOf({ item: createSuccessfulRemoteDataObject(mockItem) })
}); });
beforeEach(async(() => { beforeEach(async(() => {
@@ -66,7 +70,8 @@ describe('ItemPageComponent', () => {
describe('when the item is loading', () => { describe('when the item is loading', () => {
beforeEach(() => { beforeEach(() => {
comp.itemRD$ = observableOf(new RemoteData(true, true, true, null, undefined)); comp.itemRD$ = createPendingRemoteDataObject$(undefined);
// comp.itemRD$ = observableOf(new RemoteData(true, true, true, null, undefined));
fixture.detectChanges(); fixture.detectChanges();
}); });
@@ -78,7 +83,7 @@ describe('ItemPageComponent', () => {
describe('when the item failed loading', () => { describe('when the item failed loading', () => {
beforeEach(() => { beforeEach(() => {
comp.itemRD$ = observableOf(new RemoteData(false, false, false, null, undefined)); comp.itemRD$ = createFailedRemoteDataObject$(undefined);
fixture.detectChanges(); fixture.detectChanges();
}); });

View File

@@ -21,6 +21,10 @@
[fields]="['journalvolume.identifier.name']" [fields]="['journalvolume.identifier.name']"
[label]="'publication.page.volume-title'"> [label]="'publication.page.volume-title'">
</ds-generic-item-page-field> </ds-generic-item-page-field>
<ds-generic-item-page-field [item]="item"
[fields]="['dc.publisher']"
[label]="'publication.page.publisher'">
</ds-generic-item-page-field>
</div> </div>
<div class="col-xs-12 col-md-6"> <div class="col-xs-12 col-md-6">
<ds-metadata-representation-list <ds-metadata-representation-list
@@ -40,6 +44,11 @@
[label]="'relationships.isJournalIssueOf' | translate"> [label]="'relationships.isJournalIssueOf' | translate">
</ds-related-items> </ds-related-items>
<ds-item-page-abstract-field [item]="item"></ds-item-page-abstract-field> <ds-item-page-abstract-field [item]="item"></ds-item-page-abstract-field>
<ds-generic-item-page-field [item]="item"
[fields]="['dc.description']"
[label]="'publication.page.description'">
</ds-generic-item-page-field>
<ds-generic-item-page-field [item]="item" <ds-generic-item-page-field [item]="item"
[fields]="['dc.subject']" [fields]="['dc.subject']"
[separator]="','" [separator]="','"

View File

@@ -17,9 +17,10 @@ import { createRelationshipsObservable } from '../shared/item.component.spec';
import { PublicationComponent } from './publication.component'; import { PublicationComponent } from './publication.component';
import { of as observableOf } from 'rxjs'; import { of as observableOf } from 'rxjs';
import { MetadataMap } from '../../../../core/shared/metadata.models'; import { MetadataMap } from '../../../../core/shared/metadata.models';
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';
const mockItem: Item = Object.assign(new Item(), { const mockItem: Item = Object.assign(new Item(), {
bitstreams: observableOf(new RemoteData(false, false, true, null, new PaginatedList(new PageInfo(), []))), bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: new MetadataMap(), metadata: new MetadataMap(),
relationships: createRelationshipsObservable() relationships: createRelationshipsObservable()
}); });

View File

@@ -7,7 +7,7 @@ import {
} from '../../../../shared/items/item-type-decorator'; } from '../../../../shared/items/item-type-decorator';
import { ItemComponent } from '../shared/item.component'; import { ItemComponent } from '../shared/item.component';
import { MetadataRepresentation } from '../../../../core/shared/metadata-representation/metadata-representation.model'; import { MetadataRepresentation } from '../../../../core/shared/metadata-representation/metadata-representation.model';
import { filterRelationsByTypeLabel, relationsToItems } from '../shared/item-relationships-utils'; import { getRelatedItemsByTypeLabel } from '../shared/item-relationships-utils';
@rendersItemType('Publication', ItemViewMode.Full) @rendersItemType('Publication', ItemViewMode.Full)
@rendersItemType(DEFAULT_ITEM_TYPE, ItemViewMode.Full) @rendersItemType(DEFAULT_ITEM_TYPE, ItemViewMode.Full)
@@ -46,18 +46,15 @@ export class PublicationComponent extends ItemComponent implements OnInit {
this.authors$ = this.buildRepresentations('Person', 'dc.contributor.author'); this.authors$ = this.buildRepresentations('Person', 'dc.contributor.author');
this.projects$ = this.resolvedRelsAndTypes$.pipe( this.projects$ = this.resolvedRelsAndTypes$.pipe(
filterRelationsByTypeLabel('isProjectOfPublication'), getRelatedItemsByTypeLabel(this.item.id, 'isProjectOfPublication')
relationsToItems(this.item.id)
); );
this.orgUnits$ = this.resolvedRelsAndTypes$.pipe( this.orgUnits$ = this.resolvedRelsAndTypes$.pipe(
filterRelationsByTypeLabel('isOrgUnitOfPublication'), getRelatedItemsByTypeLabel(this.item.id, 'isOrgUnitOfPublication')
relationsToItems(this.item.id)
); );
this.journalIssues$ = this.resolvedRelsAndTypes$.pipe( this.journalIssues$ = this.resolvedRelsAndTypes$.pipe(
filterRelationsByTypeLabel('isJournalIssueOfPublication'), getRelatedItemsByTypeLabel(this.item.id, 'isJournalIssueOfPublication')
relationsToItems(this.item.id)
); );
} }

View File

@@ -2,16 +2,15 @@ import { ItemMetadataRepresentation } from '../../../../core/shared/metadata-rep
import { MetadataRepresentation } from '../../../../core/shared/metadata-representation/metadata-representation.model'; import { MetadataRepresentation } from '../../../../core/shared/metadata-representation/metadata-representation.model';
import { MetadatumRepresentation } from '../../../../core/shared/metadata-representation/metadatum/metadatum-representation.model'; import { MetadatumRepresentation } from '../../../../core/shared/metadata-representation/metadatum/metadatum-representation.model';
import { MetadataValue } from '../../../../core/shared/metadata.models'; import { MetadataValue } from '../../../../core/shared/metadata.models';
import { getSucceededRemoteData } from '../../../../core/shared/operators'; import { getRemoteDataPayload, getSucceededRemoteData } from '../../../../core/shared/operators';
import { hasValue } from '../../../../shared/empty.util'; import { hasNoValue, hasValue } from '../../../../shared/empty.util';
import { Observable } from 'rxjs/internal/Observable'; import { Observable } from 'rxjs/internal/Observable';
import { Relationship } from '../../../../core/shared/item-relationships/relationship.model'; import { Relationship } from '../../../../core/shared/item-relationships/relationship.model';
import { RelationshipType } from '../../../../core/shared/item-relationships/relationship-type.model'; import { RelationshipType } from '../../../../core/shared/item-relationships/relationship-type.model';
import { distinctUntilChanged, flatMap, map } from 'rxjs/operators'; import { distinctUntilChanged, flatMap, map, switchMap } from 'rxjs/operators';
import { of as observableOf, zip as observableZip, combineLatest as observableCombineLatest } from 'rxjs'; import { of as observableOf, zip as observableZip, combineLatest as observableCombineLatest } from 'rxjs';
import { ItemDataService } from '../../../../core/data/item-data.service'; import { ItemDataService } from '../../../../core/data/item-data.service';
import { Item } from '../../../../core/shared/item.model'; import { Item } from '../../../../core/shared/item.model';
import { RemoteData } from '../../../../core/data/remote-data';
/** /**
* Operator for comparing arrays using a mapping function * Operator for comparing arrays using a mapping function
@@ -43,23 +42,36 @@ export const compareArraysUsingIds = <T extends { id: string }>() =>
/** /**
* Fetch the relationships which match the type label given * Fetch the relationships which match the type label given
* @param {string} label Type label * @param {string} label Type label
* @param thisId The item's id of which the relations belong to
* @returns {(source: Observable<[Relationship[] , RelationshipType[]]>) => Observable<Relationship[]>} * @returns {(source: Observable<[Relationship[] , RelationshipType[]]>) => Observable<Relationship[]>}
*/ */
export const filterRelationsByTypeLabel = (label: string) => export const filterRelationsByTypeLabel = (label: string, thisId?: string) =>
(source: Observable<[Relationship[], RelationshipType[]]>): Observable<Relationship[]> => (source: Observable<[Relationship[], RelationshipType[]]>): Observable<Relationship[]> =>
source.pipe( source.pipe(
map(([relsCurrentPage, relTypesCurrentPage]) => switchMap(([relsCurrentPage, relTypesCurrentPage]) => {
relsCurrentPage.filter((rel: Relationship, idx: number) => const relatedItems$ = observableZip(...relsCurrentPage.map((rel: Relationship) =>
hasValue(relTypesCurrentPage[idx]) && (relTypesCurrentPage[idx].leftLabel === label || observableCombineLatest(
relTypesCurrentPage[idx].rightLabel === label) rel.leftItem.pipe(getSucceededRemoteData(), getRemoteDataPayload()),
) rel.rightItem.pipe(getSucceededRemoteData(), getRemoteDataPayload()))
), )
);
return relatedItems$.pipe(
map((arr) => relsCurrentPage.filter((rel: Relationship, idx: number) =>
hasValue(relTypesCurrentPage[idx]) && (
(hasNoValue(thisId) && (relTypesCurrentPage[idx].leftLabel === label ||
relTypesCurrentPage[idx].rightLabel === label)) ||
(thisId === arr[idx][0].id && relTypesCurrentPage[idx].leftLabel === label) ||
(thisId === arr[idx][1].id && relTypesCurrentPage[idx].rightLabel === label)
)
))
);
}),
distinctUntilChanged(compareArraysUsingIds()) distinctUntilChanged(compareArraysUsingIds())
); );
/** /**
* Operator for turning a list of relationships into a list of the relevant items * Operator for turning a list of relationships into a list of the relevant items
* @param {string} thisId The item's id of which the relations belong to * @param {string} thisId The item's id of which the relations belong to
* @returns {(source: Observable<Relationship[]>) => Observable<Item[]>} * @returns {(source: Observable<Relationship[]>) => Observable<Item[]>}
*/ */
export const relationsToItems = (thisId: string) => export const relationsToItems = (thisId: string) =>
@@ -79,10 +91,25 @@ export const relationsToItems = (thisId: string) =>
} else if (rightItem.payload.id === thisId) { } else if (rightItem.payload.id === thisId) {
return leftItem.payload; return leftItem.payload;
} }
})), })
.filter((item: Item) => hasValue(item))
),
distinctUntilChanged(compareArraysUsingIds()), distinctUntilChanged(compareArraysUsingIds()),
); );
/**
* Operator for turning a list of relationships and their relationship-types into a list of relevant items by relationship label
* @param thisId The item's id of which the relations belong to
* @param label The label of the relationship-type to filter on
* @param side Filter only on one side of the relationship (for example: child-parent relationships)
*/
export const getRelatedItemsByTypeLabel = (thisId: string, label: string) =>
(source: Observable<[Relationship[], RelationshipType[]]>): Observable<Item[]> =>
source.pipe(
filterRelationsByTypeLabel(label, thisId),
relationsToItems(thisId)
);
/** /**
* Operator for turning a list of relationships into a list of metadatarepresentations given the original metadata * Operator for turning a list of relationships into a list of metadatarepresentations given the original metadata
* @param parentId The id of the parent item * @param parentId The id of the parent item

View File

@@ -26,6 +26,7 @@ import { MetadatumRepresentation } from '../../../../core/shared/metadata-repres
import { ItemMetadataRepresentation } from '../../../../core/shared/metadata-representation/item/item-metadata-representation.model'; import { ItemMetadataRepresentation } from '../../../../core/shared/metadata-representation/item/item-metadata-representation.model';
import { MetadataMap, MetadataValue } from '../../../../core/shared/metadata.models'; import { MetadataMap, MetadataValue } from '../../../../core/shared/metadata.models';
import { compareArraysUsing, compareArraysUsingIds } from './item-relationships-utils'; import { compareArraysUsing, compareArraysUsingIds } from './item-relationships-utils';
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';
/** /**
* Create a generic test for an item-page-fields component using a mockItem and the type of component * Create a generic test for an item-page-fields component using a mockItem and the type of component
@@ -102,11 +103,13 @@ export function containsFieldInput(fields: DebugElement[], metadataKey: string):
} }
export function createRelationshipsObservable() { export function createRelationshipsObservable() {
return observableOf(new RemoteData(false, false, true, null, new PaginatedList(new PageInfo(), [ return createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [
Object.assign(new Relationship(), { Object.assign(new Relationship(), {
relationshipType: observableOf(new RemoteData(false, false, true, null, new RelationshipType())) relationshipType: createSuccessfulRemoteDataObject$(new RelationshipType()),
leftItem: createSuccessfulRemoteDataObject$(new Item()),
rightItem: createSuccessfulRemoteDataObject$(new Item())
}) })
]))); ]));
} }
describe('ItemComponent', () => { describe('ItemComponent', () => {
const arr1 = [ const arr1 = [
@@ -335,15 +338,15 @@ describe('ItemComponent', () => {
uuid: '1', uuid: '1',
metadata: new MetadataMap() metadata: new MetadataMap()
}); });
mockItem.relationships = observableOf(new RemoteData(false, false, true, null, new PaginatedList(new PageInfo(), [ mockItem.relationships = createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [
Object.assign(new Relationship(), { Object.assign(new Relationship(), {
uuid: '123', uuid: '123',
id: '123', id: '123',
leftItem: observableOf(new RemoteData(false, false, true, null, mockItem)), leftItem: createSuccessfulRemoteDataObject$(mockItem),
rightItem: observableOf(new RemoteData(false, false, true, null, relatedItem)), rightItem: createSuccessfulRemoteDataObject$(relatedItem),
relationshipType: observableOf(new RemoteData(false, false, true, null, new RelationshipType())) relationshipType: createSuccessfulRemoteDataObject$(new RelationshipType())
}) })
]))); ]));
mockItem.metadata[metadataField] = [ mockItem.metadata[metadataField] = [
{ {
value: 'Second value', value: 'Second value',
@@ -367,7 +370,7 @@ describe('ItemComponent', () => {
const mockItemDataService = Object.assign({ const mockItemDataService = Object.assign({
findById: (id) => { findById: (id) => {
if (id === relatedItem.id) { if (id === relatedItem.id) {
return observableOf(new RemoteData(false, false, true, null, relatedItem)) return createSuccessfulRemoteDataObject$(relatedItem)
} }
} }
}) as ItemDataService; }) as ItemDataService;

View File

@@ -8,14 +8,15 @@ import { PageInfo } from '../../../core/shared/page-info.model';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { createRelationshipsObservable } from '../item-types/shared/item.component.spec'; import { createRelationshipsObservable } from '../item-types/shared/item.component.spec';
import { of as observableOf } from 'rxjs'; import { of as observableOf } from 'rxjs';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/testing/utils';
const mockItem1: Item = Object.assign(new Item(), { const mockItem1: Item = Object.assign(new Item(), {
bitstreams: observableOf(new RemoteData(false, false, true, null, new PaginatedList(new PageInfo(), []))), bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: [], metadata: [],
relationships: createRelationshipsObservable() relationships: createRelationshipsObservable()
}); });
const mockItem2: Item = Object.assign(new Item(), { const mockItem2: Item = Object.assign(new Item(), {
bitstreams: observableOf(new RemoteData(false, false, true, null, new PaginatedList(new PageInfo(), []))), bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])),
metadata: [], metadata: [],
relationships: createRelationshipsObservable() relationships: createRelationshipsObservable()
}); });

View File

@@ -1,5 +1,3 @@
@import '../../styles/variables.scss';
.login-logo { .login-logo {
height: $login-logo-height; height: $login-logo-height;
width: $login-logo-width; width: $login-logo-width;

View File

@@ -29,6 +29,7 @@ import { RoleDirective } from '../shared/roles/role.directive';
import { RoleService } from '../core/roles/role.service'; import { RoleService } from '../core/roles/role.service';
import { MockRoleService } from '../shared/mocks/mock-role-service'; import { MockRoleService } from '../shared/mocks/mock-role-service';
import { SearchFixedFilterService } from '../+search-page/search-filters/search-filter/search-fixed-filter.service'; import { SearchFixedFilterService } from '../+search-page/search-filters/search-filter/search-fixed-filter.service';
import { createSuccessfulRemoteDataObject$ } from '../shared/testing/utils';
describe('MyDSpacePageComponent', () => { describe('MyDSpacePageComponent', () => {
let comp: MyDSpacePageComponent; let comp: MyDSpacePageComponent;
@@ -46,7 +47,7 @@ describe('MyDSpacePageComponent', () => {
pagination.currentPage = 1; pagination.currentPage = 1;
pagination.pageSize = 10; pagination.pageSize = 10;
const sort: SortOptions = new SortOptions('score', SortDirection.DESC); const sort: SortOptions = new SortOptions('score', SortDirection.DESC);
const mockResults = observableOf(new RemoteData(false, false, true, null, ['test', 'data'])); const mockResults = createSuccessfulRemoteDataObject$(['test', 'data']);
const searchServiceStub = jasmine.createSpyObj('SearchService', { const searchServiceStub = jasmine.createSpyObj('SearchService', {
search: mockResults, search: mockResults,
getSearchLink: '/mydspace', getSearchLink: '/mydspace',

View File

@@ -1,10 +1,12 @@
import { autoserialize, autoserializeAs } from 'cerialize'; import { autoserialize, inheritSerialization } from 'cerialize';
import { MetadataMap } from '../core/shared/metadata.models'; import { MetadataMap } from '../core/shared/metadata.models';
import { ListableObject } from '../shared/object-collection/shared/listable-object.model'; import { ListableObject } from '../shared/object-collection/shared/listable-object.model';
import { NormalizedObject } from '../core/cache/models/normalized-object.model';
/** /**
* Represents a normalized version of a search result object of a certain DSpaceObject * Represents a normalized version of a search result object of a certain DSpaceObject
*/ */
@inheritSerialization(NormalizedObject)
export class NormalizedSearchResult implements ListableObject { export class NormalizedSearchResult implements ListableObject {
/** /**
* The UUID of the DSpaceObject that was found * The UUID of the DSpaceObject that was found

View File

@@ -1,5 +1,3 @@
@import '../../../../../styles/variables.scss';
@import '../../../../../styles/mixins.scss';
.filters { .filters {
.toggle-more-filters a { .toggle-more-filters a {

View File

@@ -1,9 +1,9 @@
<a *ngIf="isVisible | async" class="d-flex flex-row" <a *ngIf="isVisible | async" class="d-flex flex-row"
[routerLink]="[getSearchLink()]" [routerLink]="[getSearchLink()]"
[queryParams]="addQueryParams" queryParamsHandling="merge"> [queryParams]="addQueryParams" queryParamsHandling="merge">
<input type="checkbox" [checked]="false" class="my-1 align-self-stretch"/> <input type="checkbox" [checked]="false" class="my-1 align-self-stretch"/>
<span class="filter-value px-1">{{filterValue.value}}</span> <span class="filter-value px-1">{{filterValue.value}}</span>
<span class="float-right filter-value-count ml-auto"> <span class="float-right filter-value-count ml-auto">
<span class="badge badge-secondary badge-pill">{{filterValue.count}}</span> <span class="badge badge-secondary badge-pill">{{filterValue.count}}</span>
</span> </span>
</a> </a>

View File

@@ -1,5 +1,3 @@
@import '../../../../../../styles/variables.scss';
a { a {
color: $body-color; color: $body-color;
&:hover, &focus { &:hover, &focus {

View File

@@ -1,8 +1,8 @@
<a *ngIf="isVisible | async" class="d-flex flex-row" <a *ngIf="isVisible | async" class="d-flex flex-row"
[routerLink]="[getSearchLink()]" [routerLink]="[getSearchLink()]"
[queryParams]="changeQueryParams" queryParamsHandling="merge"> [queryParams]="changeQueryParams" queryParamsHandling="merge">
<span class="filter-value px-1">{{filterValue.label}}</span> <span class="filter-value px-1">{{filterValue.label}}</span>
<span class="float-right filter-value-count ml-auto"> <span class="float-right filter-value-count ml-auto">
<span class="badge badge-secondary badge-pill">{{filterValue.count}}</span> <span class="badge badge-secondary badge-pill">{{filterValue.count}}</span>
</span> </span>
</a> </a>

View File

@@ -1,5 +1,3 @@
@import '../../../../../../styles/variables.scss';
a { a {
color: $link-color; color: $link-color;
&:hover { &:hover {

View File

@@ -18,6 +18,7 @@ const rangeDelimiter = '-';
@Component({ @Component({
selector: 'ds-search-facet-range-option', selector: 'ds-search-facet-range-option',
styleUrls: ['./search-facet-range-option.component.scss'], styleUrls: ['./search-facet-range-option.component.scss'],
// templateUrl: './search-facet-range-option.component.html',
templateUrl: './search-facet-range-option.component.html', templateUrl: './search-facet-range-option.component.html',
}) })

View File

@@ -1,5 +1,3 @@
@import '../../../../../../styles/variables.scss';
a { a {
color: $body-color; color: $body-color;
&:hover, &focus { &:hover, &focus {

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