mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-19 07:53:02 +00:00
Merge branch 'master' into object-factory-refactoring
Conflicts: src/app/+item-page/simple/item-types/shared/item.component.spec.ts src/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.spec.ts src/app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.spec.ts src/app/entity-groups/journal-entities/item-pages/journal/journal.component.spec.ts src/app/entity-groups/research-entities/item-pages/orgunit/orgunit.component.spec.ts src/app/entity-groups/research-entities/item-pages/person/person.component.spec.ts src/app/entity-groups/research-entities/item-pages/project/project.component.spec.ts src/app/submission/form/collection/submission-form-collection.component.spec.ts
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -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
|
||||||
|
|
||||||
|
@@ -18,9 +18,6 @@ cache:
|
|||||||
|
|
||||||
bundler_args: --retry 5
|
bundler_args: --retry 5
|
||||||
|
|
||||||
before_install:
|
|
||||||
- travis_retry yarn run global
|
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- travis_retry yarn install
|
- travis_retry yarn install
|
||||||
|
|
||||||
|
@@ -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',
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
22
package.json
22
package.json
@@ -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",
|
||||||
@@ -94,6 +96,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",
|
||||||
@@ -121,6 +124,7 @@
|
|||||||
"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 +167,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",
|
||||||
@@ -213,7 +218,7 @@
|
|||||||
"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",
|
||||||
@@ -221,9 +226,10 @@
|
|||||||
"typedoc": "^0.9.0",
|
"typedoc": "^0.9.0",
|
||||||
"typescript": "^2.9.1",
|
"typescript": "^2.9.1",
|
||||||
"webpack": "^4.17.1",
|
"webpack": "^4.17.1",
|
||||||
"webpack-bundle-analyzer": "^2.13.1",
|
"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"
|
||||||
}
|
}
|
||||||
|
@@ -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": {
|
||||||
@@ -302,6 +312,12 @@
|
|||||||
},
|
},
|
||||||
"listelement": {
|
"listelement": {
|
||||||
"badge": "Person"
|
"badge": "Person"
|
||||||
|
},
|
||||||
|
"search": {
|
||||||
|
"title": "DSpace Angular :: Person Search",
|
||||||
|
"results": {
|
||||||
|
"head": "Person Search Results"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"project": {
|
"project": {
|
||||||
@@ -342,6 +358,12 @@
|
|||||||
},
|
},
|
||||||
"listelement": {
|
"listelement": {
|
||||||
"badge": "Journal"
|
"badge": "Journal"
|
||||||
|
},
|
||||||
|
"search": {
|
||||||
|
"title": "DSpace Angular :: Journal Search",
|
||||||
|
"results": {
|
||||||
|
"head": "Journal Search Results"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"journalvolume": {
|
"journalvolume": {
|
||||||
@@ -374,10 +396,19 @@
|
|||||||
"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"
|
||||||
|
},
|
||||||
|
"search": {
|
||||||
|
"title": "DSpace Angular :: Publication Search",
|
||||||
|
"results": {
|
||||||
|
"head": "Publication Search Results"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nav": {
|
"nav": {
|
||||||
@@ -481,24 +512,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"search": {
|
"search": {
|
||||||
"journal": {
|
|
||||||
"title": "DSpace Angular :: Journal Search",
|
|
||||||
"results": {
|
|
||||||
"head": "Journal Search Results"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"person": {
|
|
||||||
"title": "DSpace Angular :: Person Search",
|
|
||||||
"results": {
|
|
||||||
"head": "Person Search Results"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"publication": {
|
|
||||||
"title": "DSpace Angular :: Publication Search",
|
|
||||||
"results": {
|
|
||||||
"head": "Publication Search Results"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"title": "DSpace Angular :: Search",
|
"title": "DSpace Angular :: Search",
|
||||||
"description": "",
|
"description": "",
|
||||||
"form": {
|
"form": {
|
||||||
@@ -597,6 +610,46 @@
|
|||||||
"objectpeople": {
|
"objectpeople": {
|
||||||
"placeholder": "People",
|
"placeholder": "People",
|
||||||
"head": "People"
|
"head": "People"
|
||||||
|
},
|
||||||
|
"jobTitle": {
|
||||||
|
"placeholder": "Job Title",
|
||||||
|
"head": "Job Title"
|
||||||
|
},
|
||||||
|
"knowsLanguage": {
|
||||||
|
"placeholder": "Known language",
|
||||||
|
"head": "Known language"
|
||||||
|
},
|
||||||
|
"birthDate": {
|
||||||
|
"placeholder": "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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -769,7 +822,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
BIN
resources/images/banner.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 MiB |
37
resources/images/dspace-logo-monochrome.svg
Normal file
37
resources/images/dspace-logo-monochrome.svg
Normal 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
22
scripts/sync-build-dir.js
Normal 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);
|
@@ -1,5 +1,3 @@
|
|||||||
@import '../../../../styles/variables.scss';
|
|
||||||
|
|
||||||
.selectable-row:hover {
|
.selectable-row:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,3 @@
|
|||||||
@import '../../../../styles/variables.scss';
|
|
||||||
|
|
||||||
.selectable-row:hover {
|
.selectable-row:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
@@ -1 +0,0 @@
|
|||||||
@import '../../../../styles/variables.scss';
|
|
@@ -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'),
|
||||||
|
@@ -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;
|
||||||
|
@@ -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;
|
||||||
|
@@ -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 = [];
|
||||||
|
@@ -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)? '"' + value + '"': ''} }}"
|
title="{{'browse.title' | translate:{collection: (parent$ | async)?.payload?.name || '', field: 'browse.metadata.' + browseId | translate, value: (value)? '"' + value + '"': ''} }}"
|
||||||
[objects$]="(items$ !== undefined)? items$ : browseEntries$"
|
[objects$]="(items$ !== undefined)? items$ : browseEntries$"
|
||||||
[paginationConfig]="paginationConfig"
|
[paginationConfig]="paginationConfig"
|
||||||
[sortConfig]="sortConfig"
|
[sortConfig]="sortConfig"
|
||||||
|
@@ -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 {
|
||||||
|
@@ -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);
|
||||||
|
});
|
||||||
|
});
|
@@ -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;
|
||||||
|
}
|
@@ -0,0 +1 @@
|
|||||||
|
<ng-container *ngComponentOutlet="browseByComponent | async"></ng-container>
|
@@ -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 };
|
||||||
|
}
|
@@ -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))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -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();
|
||||||
|
@@ -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,
|
||||||
|
@@ -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,
|
||||||
|
@@ -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' } }
|
|
||||||
])
|
])
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
@@ -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 {
|
||||||
|
@@ -1 +0,0 @@
|
|||||||
@import '../../styles/variables.scss';
|
|
||||||
|
@@ -1 +0,0 @@
|
|||||||
@import '../../styles/variables.scss';
|
|
||||||
|
@@ -1 +0,0 @@
|
|||||||
@import '../../../styles/variables.scss';
|
|
||||||
|
@@ -1 +0,0 @@
|
|||||||
@import '../../../styles/variables.scss';
|
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
@@ -1 +1,2 @@
|
|||||||
@import '../../styles/variables.scss';
|
:host {
|
||||||
|
}
|
@@ -1,5 +1,3 @@
|
|||||||
@import '../../../styles/variables.scss';
|
|
||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
min-width: $edit-item-button-min-width;
|
min-width: $edit-item-button-min-width;
|
||||||
}
|
}
|
||||||
|
@@ -33,6 +33,7 @@ const ITEM_EDIT_DELETE_PATH = 'delete';
|
|||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
redirectTo: 'status',
|
redirectTo: 'status',
|
||||||
|
pathMatch: 'full'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'status',
|
path: 'status',
|
||||||
|
@@ -1 +0,0 @@
|
|||||||
@import '../../../../styles/variables.scss';
|
|
@@ -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;
|
||||||
|
@@ -1,5 +1,3 @@
|
|||||||
@import '../../../../styles/variables.scss';
|
|
||||||
|
|
||||||
.button-row {
|
.button-row {
|
||||||
.btn {
|
.btn {
|
||||||
margin-right: 0.5 * $spacer;
|
margin-right: 0.5 * $spacer;
|
||||||
|
@@ -1,5 +1,3 @@
|
|||||||
@import '../../../../styles/variables.scss';
|
|
||||||
|
|
||||||
:host {
|
:host {
|
||||||
.simple-view-element {
|
.simple-view-element {
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
|
@@ -1 +0,0 @@
|
|||||||
@import '../../../../styles/variables.scss';
|
|
||||||
|
@@ -1 +0,0 @@
|
|||||||
@import '../../../../styles/variables.scss';
|
|
||||||
|
@@ -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;
|
||||||
|
@@ -1,5 +1,3 @@
|
|||||||
@import '../../../styles/variables.scss';
|
|
||||||
|
|
||||||
:host {
|
:host {
|
||||||
div.simple-view-link {
|
div.simple-view-link {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
@@ -20,16 +20,12 @@ import { FullFileSectionComponent } from './full/field-components/file-section/f
|
|||||||
import { RelatedItemsComponent } from './simple/related-items/related-items-component';
|
import { RelatedItemsComponent } from './simple/related-items/related-items-component';
|
||||||
import { SearchPageModule } from '../+search-page/search-page.module';
|
import { SearchPageModule } from '../+search-page/search-page.module';
|
||||||
import { PublicationComponent } from './simple/item-types/publication/publication.component';
|
import { PublicationComponent } from './simple/item-types/publication/publication.component';
|
||||||
import { PersonComponent } from './simple/item-types/person/person.component';
|
|
||||||
import { OrgunitComponent } from './simple/item-types/orgunit/orgunit.component';
|
|
||||||
import { ProjectComponent } from './simple/item-types/project/project.component';
|
|
||||||
import { JournalComponent } from './simple/item-types/journal/journal.component';
|
|
||||||
import { JournalVolumeComponent } from './simple/item-types/journal-volume/journal-volume.component';
|
|
||||||
import { JournalIssueComponent } from './simple/item-types/journal-issue/journal-issue.component';
|
|
||||||
import { ItemComponent } from './simple/item-types/shared/item.component';
|
import { ItemComponent } from './simple/item-types/shared/item.component';
|
||||||
import { EditItemPageModule } from './edit-item-page/edit-item-page.module';
|
import { EditItemPageModule } from './edit-item-page/edit-item-page.module';
|
||||||
import { MetadataRepresentationListComponent } from './simple/metadata-representation-list/metadata-representation-list.component';
|
import { MetadataRepresentationListComponent } from './simple/metadata-representation-list/metadata-representation-list.component';
|
||||||
import { RelatedEntitiesSearchComponent } from './simple/related-entities/related-entities-search/related-entities-search.component';
|
import { RelatedEntitiesSearchComponent } from './simple/related-entities/related-entities-search/related-entities-search.component';
|
||||||
|
import { MetadataValuesComponent } from './field-components/metadata-values/metadata-values.component';
|
||||||
|
import { MetadataFieldWrapperComponent } from './field-components/metadata-field-wrapper/metadata-field-wrapper.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -53,26 +49,23 @@ import { RelatedEntitiesSearchComponent } from './simple/related-entities/relate
|
|||||||
CollectionsComponent,
|
CollectionsComponent,
|
||||||
FullFileSectionComponent,
|
FullFileSectionComponent,
|
||||||
PublicationComponent,
|
PublicationComponent,
|
||||||
ProjectComponent,
|
|
||||||
OrgunitComponent,
|
|
||||||
PersonComponent,
|
|
||||||
RelatedItemsComponent,
|
RelatedItemsComponent,
|
||||||
ItemComponent,
|
ItemComponent,
|
||||||
GenericItemPageFieldComponent,
|
GenericItemPageFieldComponent,
|
||||||
JournalComponent,
|
|
||||||
JournalIssueComponent,
|
|
||||||
JournalVolumeComponent,
|
|
||||||
MetadataRepresentationListComponent,
|
MetadataRepresentationListComponent,
|
||||||
RelatedEntitiesSearchComponent
|
RelatedEntitiesSearchComponent
|
||||||
],
|
],
|
||||||
|
exports: [
|
||||||
|
ItemComponent,
|
||||||
|
MetadataValuesComponent,
|
||||||
|
MetadataFieldWrapperComponent,
|
||||||
|
GenericItemPageFieldComponent,
|
||||||
|
RelatedEntitiesSearchComponent,
|
||||||
|
RelatedItemsComponent,
|
||||||
|
MetadataRepresentationListComponent
|
||||||
|
],
|
||||||
entryComponents: [
|
entryComponents: [
|
||||||
PublicationComponent,
|
PublicationComponent
|
||||||
ProjectComponent,
|
|
||||||
OrgunitComponent,
|
|
||||||
PersonComponent,
|
|
||||||
JournalComponent,
|
|
||||||
JournalIssueComponent,
|
|
||||||
JournalVolumeComponent
|
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class ItemPageModule {
|
export class ItemPageModule {
|
||||||
|
@@ -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]="','"
|
||||||
|
@@ -1,12 +1,10 @@
|
|||||||
import { ChangeDetectionStrategy, Component, Inject, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { ItemDataService } from '../../../../core/data/item-data.service';
|
|
||||||
import { Item } from '../../../../core/shared/item.model';
|
import { Item } from '../../../../core/shared/item.model';
|
||||||
import {
|
import {
|
||||||
DEFAULT_ITEM_TYPE, ItemViewMode,
|
DEFAULT_ITEM_TYPE, ItemViewMode,
|
||||||
rendersItemType
|
rendersItemType
|
||||||
} from '../../../../shared/items/item-type-decorator';
|
} from '../../../../shared/items/item-type-decorator';
|
||||||
import { ITEM } from '../../../../shared/items/switcher/item-type-switcher.component';
|
|
||||||
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 { filterRelationsByTypeLabel, relationsToItems } from '../shared/item-relationships-utils';
|
||||||
@@ -40,33 +38,26 @@ export class PublicationComponent extends ItemComponent implements OnInit {
|
|||||||
*/
|
*/
|
||||||
journalIssues$: Observable<Item[]>;
|
journalIssues$: Observable<Item[]>;
|
||||||
|
|
||||||
constructor(
|
|
||||||
@Inject(ITEM) public item: Item,
|
|
||||||
private ids: ItemDataService
|
|
||||||
) {
|
|
||||||
super(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
super.ngOnInit();
|
super.ngOnInit();
|
||||||
|
|
||||||
if (this.resolvedRelsAndTypes$) {
|
if (this.resolvedRelsAndTypes$) {
|
||||||
|
|
||||||
this.authors$ = this.buildRepresentations('Person', 'dc.contributor.author', this.ids);
|
this.authors$ = this.buildRepresentations('Person', 'dc.contributor.author');
|
||||||
|
|
||||||
this.projects$ = this.resolvedRelsAndTypes$.pipe(
|
this.projects$ = this.resolvedRelsAndTypes$.pipe(
|
||||||
filterRelationsByTypeLabel('isProjectOfPublication'),
|
filterRelationsByTypeLabel('isProjectOfPublication'),
|
||||||
relationsToItems(this.item.id, this.ids)
|
relationsToItems(this.item.id)
|
||||||
);
|
);
|
||||||
|
|
||||||
this.orgUnits$ = this.resolvedRelsAndTypes$.pipe(
|
this.orgUnits$ = this.resolvedRelsAndTypes$.pipe(
|
||||||
filterRelationsByTypeLabel('isOrgUnitOfPublication'),
|
filterRelationsByTypeLabel('isOrgUnitOfPublication'),
|
||||||
relationsToItems(this.item.id, this.ids)
|
relationsToItems(this.item.id)
|
||||||
);
|
);
|
||||||
|
|
||||||
this.journalIssues$ = this.resolvedRelsAndTypes$.pipe(
|
this.journalIssues$ = this.resolvedRelsAndTypes$.pipe(
|
||||||
filterRelationsByTypeLabel('isJournalIssueOfPublication'),
|
filterRelationsByTypeLabel('isJournalIssueOfPublication'),
|
||||||
relationsToItems(this.item.id, this.ids)
|
relationsToItems(this.item.id)
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -8,7 +8,7 @@ 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 } from 'rxjs/operators';
|
||||||
import { of as observableOf, zip as observableZip } 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';
|
import { RemoteData } from '../../../../core/data/remote-data';
|
||||||
@@ -60,27 +60,26 @@ export const filterRelationsByTypeLabel = (label: string) =>
|
|||||||
/**
|
/**
|
||||||
* 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
|
||||||
* @param {ItemDataService} ids The ItemDataService to fetch items from the REST API
|
|
||||||
* @returns {(source: Observable<Relationship[]>) => Observable<Item[]>}
|
* @returns {(source: Observable<Relationship[]>) => Observable<Item[]>}
|
||||||
*/
|
*/
|
||||||
export const relationsToItems = (thisId: string, ids: ItemDataService) =>
|
export const relationsToItems = (thisId: string) =>
|
||||||
(source: Observable<Relationship[]>): Observable<Item[]> =>
|
(source: Observable<Relationship[]>): Observable<Item[]> =>
|
||||||
source.pipe(
|
source.pipe(
|
||||||
flatMap((rels: Relationship[]) =>
|
flatMap((rels: Relationship[]) =>
|
||||||
observableZip(
|
observableZip(
|
||||||
...rels.map((rel: Relationship) => {
|
...rels.map((rel: Relationship) => observableCombineLatest(rel.leftItem, rel.rightItem))
|
||||||
let queryId = rel.leftId;
|
|
||||||
if (rel.leftId === thisId) {
|
|
||||||
queryId = rel.rightId;
|
|
||||||
}
|
|
||||||
return ids.findById(queryId);
|
|
||||||
})
|
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
map((arr: Array<RemoteData<Item>>) =>
|
map((arr) =>
|
||||||
arr
|
arr
|
||||||
.filter((d: RemoteData<Item>) => d.hasSucceeded)
|
.filter(([leftItem, rightItem]) => leftItem.hasSucceeded && rightItem.hasSucceeded)
|
||||||
.map((d: RemoteData<Item>) => d.payload)),
|
.map(([leftItem, rightItem]) => {
|
||||||
|
if (leftItem.payload.id === thisId) {
|
||||||
|
return rightItem.payload;
|
||||||
|
} else if (rightItem.payload.id === thisId) {
|
||||||
|
return leftItem.payload;
|
||||||
|
}
|
||||||
|
})),
|
||||||
distinctUntilChanged(compareArraysUsingIds()),
|
distinctUntilChanged(compareArraysUsingIds()),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -103,13 +102,15 @@ export const relationsToRepresentations = (parentId: string, itemType: string, m
|
|||||||
const matchingRels = rels.filter((rel: Relationship) => ('' + rel.id) === metadatum.virtualValue);
|
const matchingRels = rels.filter((rel: Relationship) => ('' + rel.id) === metadatum.virtualValue);
|
||||||
if (matchingRels.length > 0) {
|
if (matchingRels.length > 0) {
|
||||||
const matchingRel = matchingRels[0];
|
const matchingRel = matchingRels[0];
|
||||||
let queryId = matchingRel.leftId;
|
return observableCombineLatest(matchingRel.leftItem, matchingRel.rightItem).pipe(
|
||||||
if (matchingRel.leftId === parentId) {
|
map(([leftItem, rightItem]) => {
|
||||||
queryId = matchingRel.rightId;
|
if (leftItem.payload.id === parentId) {
|
||||||
}
|
return rightItem.payload;
|
||||||
return ids.findById(queryId).pipe(
|
} else if (rightItem.payload.id === parentId) {
|
||||||
getSucceededRemoteData(),
|
return leftItem.payload;
|
||||||
map((d: RemoteData<Item>) => Object.assign(new ItemMetadataRepresentation(), d.payload))
|
}
|
||||||
|
}),
|
||||||
|
map((item: Item) => Object.assign(new ItemMetadataRepresentation(), item))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@@ -320,20 +320,31 @@ describe('ItemComponent', () => {
|
|||||||
let fixture: ComponentFixture<ItemComponent>;
|
let fixture: ComponentFixture<ItemComponent>;
|
||||||
|
|
||||||
const metadataField = 'dc.contributor.author';
|
const metadataField = 'dc.contributor.author';
|
||||||
|
const relatedItem = Object.assign(new Item(), {
|
||||||
|
id: '2',
|
||||||
|
metadata: Object.assign(new MetadataMap(), {
|
||||||
|
'dc.title': [
|
||||||
|
{
|
||||||
|
language: 'en_US',
|
||||||
|
value: 'related item'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
});
|
||||||
const mockItem = Object.assign(new Item(), {
|
const mockItem = Object.assign(new Item(), {
|
||||||
id: '1',
|
id: '1',
|
||||||
uuid: '1',
|
uuid: '1',
|
||||||
metadata: new MetadataMap(),
|
metadata: new MetadataMap()
|
||||||
relationships: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [
|
|
||||||
Object.assign(new Relationship(), {
|
|
||||||
uuid: '123',
|
|
||||||
id: '123',
|
|
||||||
leftId: '1',
|
|
||||||
rightId: '2',
|
|
||||||
relationshipType: createSuccessfulRemoteDataObject$(new RelationshipType())
|
|
||||||
})
|
|
||||||
]))
|
|
||||||
});
|
});
|
||||||
|
mockItem.relationships = createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [
|
||||||
|
Object.assign(new Relationship(), {
|
||||||
|
uuid: '123',
|
||||||
|
id: '123',
|
||||||
|
leftItem: createSuccessfulRemoteDataObject$(mockItem),
|
||||||
|
rightItem: createSuccessfulRemoteDataObject$(relatedItem),
|
||||||
|
relationshipType: createSuccessfulRemoteDataObject$new RelationshipType())
|
||||||
|
})
|
||||||
|
]));
|
||||||
mockItem.metadata[metadataField] = [
|
mockItem.metadata[metadataField] = [
|
||||||
{
|
{
|
||||||
value: 'Second value',
|
value: 'Second value',
|
||||||
@@ -354,17 +365,6 @@ describe('ItemComponent', () => {
|
|||||||
authority: '123'
|
authority: '123'
|
||||||
}
|
}
|
||||||
] as MetadataValue[];
|
] as MetadataValue[];
|
||||||
const relatedItem = Object.assign(new Item(), {
|
|
||||||
id: '2',
|
|
||||||
metadata: Object.assign(new MetadataMap(), {
|
|
||||||
'dc.title': [
|
|
||||||
{
|
|
||||||
language: 'en_US',
|
|
||||||
value: 'related item'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
});
|
|
||||||
const mockItemDataService = Object.assign({
|
const mockItemDataService = Object.assign({
|
||||||
findById: (id) => {
|
findById: (id) => {
|
||||||
if (id === relatedItem.id) {
|
if (id === relatedItem.id) {
|
||||||
@@ -398,7 +398,7 @@ describe('ItemComponent', () => {
|
|||||||
fixture = TestBed.createComponent(ItemComponent);
|
fixture = TestBed.createComponent(ItemComponent);
|
||||||
comp = fixture.componentInstance;
|
comp = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
representations = comp.buildRepresentations('bogus', metadataField, mockItemDataService);
|
representations = comp.buildRepresentations('bogus', metadataField);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should contain exactly 4 metadata-representations', () => {
|
it('should contain exactly 4 metadata-representations', () => {
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import { Component, Inject, OnInit } from '@angular/core';
|
import { Component, Inject, OnInit } from '@angular/core';
|
||||||
import { combineLatest as observableCombineLatest, Observable, zip as observableZip } from 'rxjs';
|
import { Observable , zip as observableZip, combineLatest as observableCombineLatest } from 'rxjs';
|
||||||
import { distinctUntilChanged, filter, flatMap, map } from 'rxjs/operators';
|
import { distinctUntilChanged, filter, flatMap, map } from 'rxjs/operators';
|
||||||
import { ItemDataService } from '../../../../core/data/item-data.service';
|
import { ItemDataService } from '../../../../core/data/item-data.service';
|
||||||
import { PaginatedList } from '../../../../core/data/paginated-list';
|
import { PaginatedList } from '../../../../core/data/paginated-list';
|
||||||
@@ -7,10 +7,52 @@ import { RemoteData } from '../../../../core/data/remote-data';
|
|||||||
import { RelationshipType } from '../../../../core/shared/item-relationships/relationship-type.model';
|
import { RelationshipType } from '../../../../core/shared/item-relationships/relationship-type.model';
|
||||||
import { Relationship } from '../../../../core/shared/item-relationships/relationship.model';
|
import { Relationship } from '../../../../core/shared/item-relationships/relationship.model';
|
||||||
import { Item } from '../../../../core/shared/item.model';
|
import { Item } from '../../../../core/shared/item.model';
|
||||||
import { MetadataRepresentation } from '../../../../core/shared/metadata-representation/metadata-representation.model';
|
|
||||||
import { getRemoteDataPayload, getSucceededRemoteData } from '../../../../core/shared/operators';
|
import { getRemoteDataPayload, getSucceededRemoteData } from '../../../../core/shared/operators';
|
||||||
import { ITEM } from '../../../../shared/items/switcher/item-type-switcher.component';
|
import { ITEM } from '../../../../shared/items/switcher/item-type-switcher.component';
|
||||||
import { compareArraysUsingIds, relationsToRepresentations } from './item-relationships-utils';
|
import { MetadataRepresentation } from '../../../../core/shared/metadata-representation/metadata-representation.model';
|
||||||
|
import { ItemMetadataRepresentation } from '../../../../core/shared/metadata-representation/item/item-metadata-representation.model';
|
||||||
|
import { MetadatumRepresentation } from '../../../../core/shared/metadata-representation/metadatum/metadatum-representation.model';
|
||||||
|
import { of } from 'rxjs/internal/observable/of';
|
||||||
|
import { MetadataValue } from '../../../../core/shared/metadata.models';
|
||||||
|
import { compareArraysUsingIds } from './item-relationships-utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Operator for turning a list of relationships into a list of metadatarepresentations given the original metadata
|
||||||
|
* @param thisId The id of the parent item
|
||||||
|
* @param itemType The type of relation this list resembles (for creating representations)
|
||||||
|
* @param metadata The list of original Metadatum objects
|
||||||
|
*/
|
||||||
|
export const relationsToRepresentations = (thisId: string, itemType: string, metadata: MetadataValue[]) =>
|
||||||
|
(source: Observable<Relationship[]>): Observable<MetadataRepresentation[]> =>
|
||||||
|
source.pipe(
|
||||||
|
flatMap((rels: Relationship[]) =>
|
||||||
|
observableZip(
|
||||||
|
...metadata
|
||||||
|
.map((metadatum: any) => Object.assign(new MetadataValue(), metadatum))
|
||||||
|
.map((metadatum: MetadataValue) => {
|
||||||
|
if (metadatum.isVirtual) {
|
||||||
|
const matchingRels = rels.filter((rel: Relationship) => ('' + rel.id) === metadatum.virtualValue);
|
||||||
|
if (matchingRels.length > 0) {
|
||||||
|
const matchingRel = matchingRels[0];
|
||||||
|
return observableCombineLatest(matchingRel.leftItem, matchingRel.rightItem).pipe(
|
||||||
|
filter(([leftItem, rightItem]) => leftItem.hasSucceeded && rightItem.hasSucceeded),
|
||||||
|
map(([leftItem, rightItem]) => {
|
||||||
|
if (leftItem.payload.id === thisId) {
|
||||||
|
return rightItem.payload;
|
||||||
|
} else if (rightItem.payload.id === thisId) {
|
||||||
|
return leftItem.payload;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
map((item: Item) => Object.assign(new ItemMetadataRepresentation(), item))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return of(Object.assign(new MetadatumRepresentation(itemType), metadatum));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-item',
|
selector: 'ds-item',
|
||||||
@@ -60,9 +102,8 @@ export class ItemComponent implements OnInit {
|
|||||||
* certain type.
|
* certain type.
|
||||||
* @param itemType The type of item we're building representations of. Used for matching templates.
|
* @param itemType The type of item we're building representations of. Used for matching templates.
|
||||||
* @param metadataField The metadata field that resembles the item type.
|
* @param metadataField The metadata field that resembles the item type.
|
||||||
* @param itemDataService ItemDataService to turn relations into items.
|
|
||||||
*/
|
*/
|
||||||
buildRepresentations(itemType: string, metadataField: string, itemDataService: ItemDataService): Observable<MetadataRepresentation[]> {
|
buildRepresentations(itemType: string, metadataField: string): Observable<MetadataRepresentation[]> {
|
||||||
const metadata = this.item.findMetadataSortedByPlace(metadataField);
|
const metadata = this.item.findMetadataSortedByPlace(metadataField);
|
||||||
const relsCurrentPage$ = this.item.relationships.pipe(
|
const relsCurrentPage$ = this.item.relationships.pipe(
|
||||||
getSucceededRemoteData(),
|
getSucceededRemoteData(),
|
||||||
@@ -72,7 +113,7 @@ export class ItemComponent implements OnInit {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return relsCurrentPage$.pipe(
|
return relsCurrentPage$.pipe(
|
||||||
relationsToRepresentations(this.item.id, itemType, metadata, itemDataService)
|
relationsToRepresentations(this.item.id, itemType, metadata)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
|
@@ -18,20 +18,4 @@ describe('FilteredSearchPageComponent', () => {
|
|||||||
searchConfigService = (comp as any).searchConfigService;
|
searchConfigService = (comp as any).searchConfigService;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when fixedFilterQuery is defined', () => {
|
|
||||||
const fixedFilterQuery = 'fixedFilterQuery';
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
spyOn(searchConfigService, 'updateFixedFilter').and.callThrough();
|
|
||||||
comp.fixedFilterQuery = fixedFilterQuery;
|
|
||||||
comp.ngOnInit();
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should update the paginated search options', () => {
|
|
||||||
expect(searchConfigService.updateFixedFilter).toHaveBeenCalledWith(fixedFilterQuery);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@@ -2,20 +2,22 @@ import { HostWindowService } from '../shared/host-window.service';
|
|||||||
import { SearchService } from './search-service/search.service';
|
import { SearchService } from './search-service/search.service';
|
||||||
import { SearchSidebarService } from './search-sidebar/search-sidebar.service';
|
import { SearchSidebarService } from './search-sidebar/search-sidebar.service';
|
||||||
import { SearchPageComponent } from './search-page.component';
|
import { SearchPageComponent } from './search-page.component';
|
||||||
import { ChangeDetectionStrategy, Component, Inject, Input } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, Inject, Input, OnInit } from '@angular/core';
|
||||||
import { pushInOut } from '../shared/animations/push';
|
import { pushInOut } from '../shared/animations/push';
|
||||||
import { RouteService } from '../shared/services/route.service';
|
import { RouteService } from '../shared/services/route.service';
|
||||||
import { SearchConfigurationService } from './search-service/search-configuration.service';
|
import { SearchConfigurationService } from './search-service/search-configuration.service';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { PaginatedSearchOptions } from './paginated-search-options.model';
|
import { PaginatedSearchOptions } from './paginated-search-options.model';
|
||||||
import { SEARCH_CONFIG_SERVICE } from '../+my-dspace-page/my-dspace-page.component';
|
import { SEARCH_CONFIG_SERVICE } from '../+my-dspace-page/my-dspace-page.component';
|
||||||
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This component renders a simple item page.
|
* This component renders a simple item page.
|
||||||
* The route parameter 'id' is used to request the item it represents.
|
* The route parameter 'id' is used to request the item it represents.
|
||||||
* All fields of the item that should be displayed, are defined in its template.
|
* All fields of the item that should be displayed, are defined in its template.
|
||||||
*/
|
*/
|
||||||
@Component({selector: 'ds-filtered-search-page',
|
@Component({
|
||||||
|
selector: 'ds-filtered-search-page',
|
||||||
styleUrls: ['./search-page.component.scss'],
|
styleUrls: ['./search-page.component.scss'],
|
||||||
templateUrl: './search-page.component.html',
|
templateUrl: './search-page.component.html',
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
@@ -28,8 +30,7 @@ import { SEARCH_CONFIG_SERVICE } from '../+my-dspace-page/my-dspace-page.compone
|
|||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
export class FilteredSearchPageComponent extends SearchPageComponent {
|
export class FilteredSearchPageComponent extends SearchPageComponent implements OnInit {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The actual query for the fixed filter.
|
* The actual query for the fixed filter.
|
||||||
* If empty, the query will be determined by the route parameter called 'filter'
|
* If empty, the query will be determined by the route parameter called 'filter'
|
||||||
@@ -44,6 +45,17 @@ export class FilteredSearchPageComponent extends SearchPageComponent {
|
|||||||
super(service, sidebarService, windowService, searchConfigService, routeService);
|
super(service, sidebarService, windowService, searchConfigService, routeService);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listening to changes in the paginated search options
|
||||||
|
* If something changes, update the search results
|
||||||
|
*
|
||||||
|
* Listen to changes in the scope
|
||||||
|
* If something changes, update the list of scopes for the dropdown
|
||||||
|
*/
|
||||||
|
ngOnInit(): void {
|
||||||
|
super.ngOnInit();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the current paginated search options after updating the fixed filter using the fixedFilterQuery input
|
* Get the current paginated search options after updating the fixed filter using the fixedFilterQuery input
|
||||||
* This is to make sure the fixed filter is included in the paginated search options, as it is not part of any
|
* This is to make sure the fixed filter is included in the paginated search options, as it is not part of any
|
||||||
@@ -51,8 +63,11 @@ export class FilteredSearchPageComponent extends SearchPageComponent {
|
|||||||
* @returns {Observable<PaginatedSearchOptions>}
|
* @returns {Observable<PaginatedSearchOptions>}
|
||||||
*/
|
*/
|
||||||
protected getSearchOptions(): Observable<PaginatedSearchOptions> {
|
protected getSearchOptions(): Observable<PaginatedSearchOptions> {
|
||||||
this.searchConfigService.updateFixedFilter(this.fixedFilterQuery);
|
return this.searchConfigService.paginatedSearchOptions.pipe(
|
||||||
return this.searchConfigService.paginatedSearchOptions;
|
map((options: PaginatedSearchOptions) => {
|
||||||
|
const filter = this.fixedFilterQuery || options.fixedFilter;
|
||||||
|
return Object.assign(options, { fixedFilter: filter });
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -4,10 +4,8 @@ import { Observable } from 'rxjs';
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
/**
|
/**
|
||||||
* Assemble the correct i18n key for the filtered search page's title depending on the current route's filter parameter
|
* Assemble the correct i18n key for the filtered search page's title depending on the current route's filter parameter.
|
||||||
* and title data.
|
* The format of the key will be "{filter}.search.title" with:
|
||||||
* The format of the key will be "{title}{filter}.title" with:
|
|
||||||
* - title: The prefix of the key stored in route.data
|
|
||||||
* - filter: The current filter stored in route.params
|
* - filter: The current filter stored in route.params
|
||||||
*/
|
*/
|
||||||
export class FilteredSearchPageGuard implements CanActivate {
|
export class FilteredSearchPageGuard implements CanActivate {
|
||||||
@@ -16,7 +14,7 @@ export class FilteredSearchPageGuard implements CanActivate {
|
|||||||
state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
|
state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
|
||||||
const filter = route.params.filter;
|
const filter = route.params.filter;
|
||||||
|
|
||||||
const newTitle = route.data.title + filter + '.title';
|
const newTitle = filter + '.search.title';
|
||||||
|
|
||||||
route.data = { title: newTitle };
|
route.data = { title: newTitle };
|
||||||
return true;
|
return true;
|
||||||
|
@@ -1,5 +1,3 @@
|
|||||||
@import '../../../../../styles/variables.scss';
|
|
||||||
@import '../../../../../styles/mixins.scss';
|
|
||||||
|
|
||||||
.filters {
|
.filters {
|
||||||
.toggle-more-filters a {
|
.toggle-more-filters a {
|
||||||
|
@@ -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>
|
@@ -1,5 +1,3 @@
|
|||||||
@import '../../../../../../styles/variables.scss';
|
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: $body-color;
|
color: $body-color;
|
||||||
&:hover, &focus {
|
&:hover, &focus {
|
||||||
|
@@ -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>
|
||||||
|
@@ -1,5 +1,3 @@
|
|||||||
@import '../../../../../../styles/variables.scss';
|
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: $link-color;
|
color: $link-color;
|
||||||
&:hover {
|
&:hover {
|
||||||
|
@@ -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',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@@ -1,5 +1,3 @@
|
|||||||
@import '../../../../../../styles/variables.scss';
|
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: $body-color;
|
color: $body-color;
|
||||||
&:hover, &focus {
|
&:hover, &focus {
|
||||||
|
@@ -1,12 +1,12 @@
|
|||||||
import {
|
import {
|
||||||
combineLatest as observableCombineLatest,
|
|
||||||
of as observableOf,
|
|
||||||
BehaviorSubject,
|
BehaviorSubject,
|
||||||
|
combineLatest as observableCombineLatest,
|
||||||
Observable,
|
Observable,
|
||||||
|
of as observableOf,
|
||||||
Subject,
|
Subject,
|
||||||
Subscription
|
Subscription
|
||||||
} from 'rxjs';
|
} from 'rxjs';
|
||||||
import { switchMap, distinctUntilChanged, map, take, flatMap, tap } from 'rxjs/operators';
|
import { distinctUntilChanged, map, switchMap, take, tap } from 'rxjs/operators';
|
||||||
import { animate, state, style, transition, trigger } from '@angular/animations';
|
import { animate, state, style, transition, trigger } from '@angular/animations';
|
||||||
import { Component, Inject, OnDestroy, OnInit } from '@angular/core';
|
import { Component, Inject, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
@@ -137,7 +137,7 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy {
|
|||||||
this.selectedValues$ = this.filterService.getSelectedValuesForFilter(this.filterConfig).pipe(
|
this.selectedValues$ = this.filterService.getSelectedValuesForFilter(this.filterConfig).pipe(
|
||||||
map((selectedValues) => {
|
map((selectedValues) => {
|
||||||
return selectedValues.map((value: string) => {
|
return selectedValues.map((value: string) => {
|
||||||
const fValue = [].concat(...rd.payload.map((page) => page.page)).find((facetValue: FacetValue) => facetValue.value === value);
|
const fValue = [].concat(...rd.payload.map((page) => page.page)).find((facetValue: FacetValue) => this.getFacetValue(facetValue) === value);
|
||||||
if (hasValue(fValue)) {
|
if (hasValue(fValue)) {
|
||||||
return fValue;
|
return fValue;
|
||||||
}
|
}
|
||||||
|
@@ -1,13 +1,10 @@
|
|||||||
@import '../../../../styles/variables.scss';
|
|
||||||
@import '../../../../styles/mixins.scss';
|
|
||||||
|
|
||||||
:host .facet-filter {
|
:host .facet-filter {
|
||||||
border: 1px solid map-get($theme-colors, light);
|
border: 1px solid map-get($theme-colors, light);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
.search-filter-wrapper.closed {
|
.search-filter-wrapper.closed {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.filter-toggle {
|
.filter-toggle {
|
||||||
line-height: $line-height-base;
|
line-height: $line-height-base;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,7 +17,7 @@ describe('SearchFixedFilterService', () => {
|
|||||||
configure: () => {},
|
configure: () => {},
|
||||||
/* tslint:enable:no-empty */
|
/* tslint:enable:no-empty */
|
||||||
generateRequestId: () => 'fake-id',
|
generateRequestId: () => 'fake-id',
|
||||||
getByUUID: () => observableOf(Object.assign(new RequestEntry(), {
|
getByHref: () => observableOf(Object.assign(new RequestEntry(), {
|
||||||
response: new FilteredDiscoveryQueryResponse(filterQuery, 200, 'OK')
|
response: new FilteredDiscoveryQueryResponse(filterQuery, 200, 'OK')
|
||||||
}))
|
}))
|
||||||
}) as RequestService;
|
}) as RequestService;
|
||||||
@@ -56,5 +56,4 @@ describe('SearchFixedFilterService', () => {
|
|||||||
expect(query).toContain(itemUUID);
|
expect(query).toContain(itemUUID);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { flatMap, map } from 'rxjs/operators';
|
import { flatMap, map, switchMap, tap } from 'rxjs/operators';
|
||||||
import { Observable , of as observableOf } from 'rxjs';
|
import { Observable, of as observableOf } from 'rxjs';
|
||||||
import { HALEndpointService } from '../../../core/shared/hal-endpoint.service';
|
import { HALEndpointService } from '../../../core/shared/hal-endpoint.service';
|
||||||
import { GetRequest, RestRequest } from '../../../core/data/request.models';
|
import { GetRequest, RestRequest } from '../../../core/data/request.models';
|
||||||
import { RequestService } from '../../../core/data/request.service';
|
import { RequestService } from '../../../core/data/request.service';
|
||||||
@@ -33,7 +33,7 @@ export class SearchFixedFilterService {
|
|||||||
getQueryByFilterName(filterName: string): Observable<string> {
|
getQueryByFilterName(filterName: string): Observable<string> {
|
||||||
if (hasValue(filterName)) {
|
if (hasValue(filterName)) {
|
||||||
const requestUuid = this.requestService.generateRequestId();
|
const requestUuid = this.requestService.generateRequestId();
|
||||||
this.halService.getEndpoint(this.queryByFilterPath).pipe(
|
const requestObs = this.halService.getEndpoint(this.queryByFilterPath).pipe(
|
||||||
map((url: string) => {
|
map((url: string) => {
|
||||||
url += ('/' + filterName);
|
url += ('/' + filterName);
|
||||||
const request = new GetRequest(requestUuid, url);
|
const request = new GetRequest(requestUuid, url);
|
||||||
@@ -44,10 +44,12 @@ export class SearchFixedFilterService {
|
|||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
configureRequest(this.requestService)
|
configureRequest(this.requestService)
|
||||||
).subscribe();
|
);
|
||||||
|
|
||||||
// get search results from response cache
|
const requestEntryObs = requestObs.pipe(
|
||||||
const filterQuery: Observable<string> = this.requestService.getByUUID(requestUuid).pipe(
|
switchMap((request: RestRequest) => this.requestService.getByHref(request.href)),
|
||||||
|
);
|
||||||
|
const filterQuery = requestEntryObs.pipe(
|
||||||
getResponseFromEntry(),
|
getResponseFromEntry(),
|
||||||
map((response: FilteredDiscoveryQueryResponse) =>
|
map((response: FilteredDiscoveryQueryResponse) =>
|
||||||
response.filterQuery
|
response.filterQuery
|
||||||
@@ -75,5 +77,4 @@ export class SearchFixedFilterService {
|
|||||||
getFilterByRelation(relationType: string, itemUUID: string): string {
|
getFilterByRelation(relationType: string, itemUUID: string): string {
|
||||||
return `f.${relationType}=${itemUUID}`;
|
return `f.${relationType}=${itemUUID}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,3 @@
|
|||||||
@import '../../../../../styles/variables.scss';
|
|
||||||
@import '../../../../../styles/mixins.scss';
|
|
||||||
|
|
||||||
.filters {
|
.filters {
|
||||||
.toggle-more-filters a {
|
.toggle-more-filters a {
|
||||||
color: $link-color;
|
color: $link-color;
|
||||||
|
@@ -1,14 +1,10 @@
|
|||||||
@import '../../../../../styles/variables.scss';
|
|
||||||
@import '../../../../../styles/mixins.scss';
|
|
||||||
|
|
||||||
|
|
||||||
.filters {
|
.filters {
|
||||||
.toggle-more-filters a {
|
.toggle-more-filters a {
|
||||||
color: $link-color;
|
color: $link-color;
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$slider-handle-width: 18px;
|
$slider-handle-width: 18px;
|
||||||
::ng-deep
|
::ng-deep
|
||||||
|
@@ -1,5 +1,3 @@
|
|||||||
@import '../../../../../styles/variables.scss';
|
|
||||||
@import '../../../../../styles/mixins.scss';
|
|
||||||
|
|
||||||
.filters {
|
.filters {
|
||||||
.toggle-more-filters a {
|
.toggle-more-filters a {
|
||||||
|
@@ -1,2 +0,0 @@
|
|||||||
@import '../../../styles/variables.scss';
|
|
||||||
@import '../../../styles/mixins.scss';
|
|
@@ -9,7 +9,7 @@ import { FilteredSearchPageGuard } from './filtered-search-page.guard';
|
|||||||
imports: [
|
imports: [
|
||||||
RouterModule.forChild([
|
RouterModule.forChild([
|
||||||
{ path: '', component: SearchPageComponent, data: { title: 'search.title' } },
|
{ path: '', component: SearchPageComponent, data: { title: 'search.title' } },
|
||||||
{ path: ':filter', component: FilteredSearchPageComponent, canActivate: [FilteredSearchPageGuard], data: { title: 'search.' }}
|
{ path: ':filter', component: FilteredSearchPageComponent, canActivate: [FilteredSearchPageGuard]}
|
||||||
])
|
])
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
<div class="search-page row">
|
<div class="search-page row">
|
||||||
<ds-search-sidebar *ngIf="!(isXsOrSm$ | async)" class="col-{{sideBarWidth}} sidebar-md-sticky"
|
<ds-search-sidebar *ngIf="!(isXsOrSm$ | async)" class="col-{{sideBarWidth}} sidebar-md-sticky"
|
||||||
id="search-sidebar"
|
id="search-sidebar"
|
||||||
[resultCount]="(resultsRD$ | async)?.payload.totalElements" [inPlaceSearch]="inPlaceSearch"></ds-search-sidebar>
|
[resultCount]="(resultsRD$ | async)?.payload?.totalElements" [inPlaceSearch]="inPlaceSearch"></ds-search-sidebar>
|
||||||
<div class="col-12 col-md-{{12 - sideBarWidth}}">
|
<div class="col-12 col-md-{{12 - sideBarWidth}}">
|
||||||
<ds-search-form *ngIf="searchEnabled" id="search-form"
|
<ds-search-form *ngIf="searchEnabled" id="search-form"
|
||||||
[query]="(searchOptions$ | async)?.query"
|
[query]="(searchOptions$ | async)?.query"
|
||||||
|
@@ -1,5 +1,3 @@
|
|||||||
@import '../../styles/variables.scss';
|
|
||||||
@import '../../styles/mixins.scss';
|
|
||||||
|
|
||||||
@include media-breakpoint-down(md) {
|
@include media-breakpoint-down(md) {
|
||||||
.container {
|
.container {
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import { ChangeDetectionStrategy, Component, Inject, Input, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, Inject, Input, OnInit } from '@angular/core';
|
||||||
import { Observable , Subscription , BehaviorSubject } from 'rxjs';
|
import { BehaviorSubject, Observable, of as observableOf, Subscription } from 'rxjs';
|
||||||
import { switchMap, } from 'rxjs/operators';
|
import { startWith, switchMap, } from 'rxjs/operators';
|
||||||
import { PaginatedList } from '../core/data/paginated-list';
|
import { PaginatedList } from '../core/data/paginated-list';
|
||||||
import { RemoteData } from '../core/data/remote-data';
|
import { RemoteData } from '../core/data/remote-data';
|
||||||
import { DSpaceObject } from '../core/shared/dspace-object.model';
|
import { DSpaceObject } from '../core/shared/dspace-object.model';
|
||||||
@@ -43,7 +43,6 @@ export const SEARCH_ROUTE = '/search';
|
|||||||
* It renders search results depending on the current search options
|
* It renders search results depending on the current search options
|
||||||
*/
|
*/
|
||||||
export class SearchPageComponent implements OnInit {
|
export class SearchPageComponent implements OnInit {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current search results
|
* The current search results
|
||||||
*/
|
*/
|
||||||
@@ -110,7 +109,7 @@ export class SearchPageComponent implements OnInit {
|
|||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.searchOptions$ = this.getSearchOptions();
|
this.searchOptions$ = this.getSearchOptions();
|
||||||
this.sub = this.searchOptions$.pipe(
|
this.sub = this.searchOptions$.pipe(
|
||||||
switchMap((options) => this.service.search(options).pipe(getSucceededRemoteData())))
|
switchMap((options) => this.service.search(options).pipe(getSucceededRemoteData(), startWith(observableOf(undefined)))))
|
||||||
.subscribe((results) => {
|
.subscribe((results) => {
|
||||||
this.resultsRD$.next(results);
|
this.resultsRD$.next(results);
|
||||||
});
|
});
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
[objects]="searchResults"
|
[objects]="searchResults"
|
||||||
[hideGear]="true">
|
[hideGear]="true">
|
||||||
</ds-viewable-collection></div>
|
</ds-viewable-collection></div>
|
||||||
<ds-loading *ngIf="!searchResults || searchResults?.isLoading" message="{{'loading.search-results' | translate}}"></ds-loading>
|
<ds-loading *ngIf="hasNoValue(searchResults) || hasNoValue(searchResults.payload) || searchResults.isLoading" message="{{'loading.search-results' | translate}}"></ds-loading>
|
||||||
<ds-error *ngIf="searchResults?.hasFailed && (!searchResults?.error || searchResults?.error?.statusCode != 400)" message="{{'error.search-results' | translate}}"></ds-error>
|
<ds-error *ngIf="searchResults?.hasFailed && (!searchResults?.error || searchResults?.error?.statusCode != 400)" message="{{'error.search-results' | translate}}"></ds-error>
|
||||||
<div *ngIf="searchResults?.payload?.page.length == 0 || searchResults?.error?.statusCode == 400">
|
<div *ngIf="searchResults?.payload?.page.length == 0 || searchResults?.error?.statusCode == 400">
|
||||||
{{ 'search.results.no-results' | translate }}
|
{{ 'search.results.no-results' | translate }}
|
||||||
|
@@ -6,7 +6,7 @@ import { SetViewMode } from '../../shared/view-mode';
|
|||||||
import { SearchOptions } from '../search-options.model';
|
import { SearchOptions } from '../search-options.model';
|
||||||
import { SearchResult } from '../search-result.model';
|
import { SearchResult } from '../search-result.model';
|
||||||
import { PaginatedList } from '../../core/data/paginated-list';
|
import { PaginatedList } from '../../core/data/paginated-list';
|
||||||
import { isNotEmpty } from '../../shared/empty.util';
|
import { hasNoValue, isNotEmpty } from '../../shared/empty.util';
|
||||||
import { SortOptions } from '../../core/cache/models/sort-options.model';
|
import { SortOptions } from '../../core/cache/models/sort-options.model';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -22,6 +22,8 @@ import { SortOptions } from '../../core/cache/models/sort-options.model';
|
|||||||
* Component that represents all results from a search
|
* Component that represents all results from a search
|
||||||
*/
|
*/
|
||||||
export class SearchResultsComponent {
|
export class SearchResultsComponent {
|
||||||
|
hasNoValue = hasNoValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The actual search result objects
|
* The actual search result objects
|
||||||
*/
|
*/
|
||||||
@@ -60,7 +62,7 @@ export class SearchResultsComponent {
|
|||||||
*/
|
*/
|
||||||
getTitleKey() {
|
getTitleKey() {
|
||||||
if (isNotEmpty(this.fixedFilter)) {
|
if (isNotEmpty(this.fixedFilter)) {
|
||||||
return 'search.' + this.fixedFilter + '.results.head'
|
return this.fixedFilter + '.search.results.head'
|
||||||
} else {
|
} else {
|
||||||
return 'search.results.head';
|
return 'search.results.head';
|
||||||
}
|
}
|
||||||
|
@@ -171,20 +171,4 @@ describe('SearchConfigurationService', () => {
|
|||||||
expect((service as any).routeService.getRouteParameterValue).toHaveBeenCalledWith('filter');
|
expect((service as any).routeService.getRouteParameterValue).toHaveBeenCalledWith('filter');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when updateFixedFilter is called', () => {
|
|
||||||
const filter = 'filter';
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
service.updateFixedFilter(filter);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should update the paginated search options with the correct fixed filter', () => {
|
|
||||||
expect(service.paginatedSearchOptions.getValue().fixedFilter).toEqual(filter);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should update the search options with the correct fixed filter', () => {
|
|
||||||
expect(service.searchOptions.getValue().fixedFilter).toEqual(filter);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
@@ -9,7 +9,7 @@ import {
|
|||||||
of as observableOf,
|
of as observableOf,
|
||||||
Subscription
|
Subscription
|
||||||
} from 'rxjs';
|
} from 'rxjs';
|
||||||
import { filter, flatMap, map } from 'rxjs/operators';
|
import { filter, flatMap, map, switchMap, tap } from 'rxjs/operators';
|
||||||
import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model';
|
import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model';
|
||||||
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
|
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
|
||||||
import { SearchOptions } from '../search-options.model';
|
import { SearchOptions } from '../search-options.model';
|
||||||
@@ -45,7 +45,7 @@ export class SearchConfigurationService implements OnDestroy {
|
|||||||
/**
|
/**
|
||||||
* Default configuration parameter setting
|
* Default configuration parameter setting
|
||||||
*/
|
*/
|
||||||
protected defaultConfiguration = 'default';
|
protected defaultConfiguration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default scope setting
|
* Default scope setting
|
||||||
@@ -100,10 +100,8 @@ export class SearchConfigurationService implements OnDestroy {
|
|||||||
const defs = defRD.payload;
|
const defs = defRD.payload;
|
||||||
this.paginatedSearchOptions = new BehaviorSubject<PaginatedSearchOptions>(defs);
|
this.paginatedSearchOptions = new BehaviorSubject<PaginatedSearchOptions>(defs);
|
||||||
this.searchOptions = new BehaviorSubject<SearchOptions>(defs);
|
this.searchOptions = new BehaviorSubject<SearchOptions>(defs);
|
||||||
|
|
||||||
this.subs.push(this.subscribeToSearchOptions(defs));
|
this.subs.push(this.subscribeToSearchOptions(defs));
|
||||||
this.subs.push(this.subscribeToPaginatedSearchOptions(defs));
|
this.subs.push(this.subscribeToPaginatedSearchOptions(defs));
|
||||||
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -207,7 +205,7 @@ export class SearchConfigurationService implements OnDestroy {
|
|||||||
*/
|
*/
|
||||||
getCurrentFixedFilter(): Observable<string> {
|
getCurrentFixedFilter(): Observable<string> {
|
||||||
return this.routeService.getRouteParameterValue('filter').pipe(
|
return this.routeService.getRouteParameterValue('filter').pipe(
|
||||||
flatMap((f) => this.fixedFilterService.getQueryByFilterName(f))
|
switchMap((f) => this.fixedFilterService.getQueryByFilterName(f))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -358,21 +356,7 @@ export class SearchConfigurationService implements OnDestroy {
|
|||||||
isNotEmptyOperator(),
|
isNotEmptyOperator(),
|
||||||
map((fixedFilter) => {
|
map((fixedFilter) => {
|
||||||
return { fixedFilter }
|
return { fixedFilter }
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the fixed filter in paginated and non-paginated search options with a given value
|
|
||||||
* @param {string} fixedFilter
|
|
||||||
*/
|
|
||||||
public updateFixedFilter(fixedFilter: string) {
|
|
||||||
const currentPaginatedValue: PaginatedSearchOptions = this.paginatedSearchOptions.getValue();
|
|
||||||
const updatedPaginatedValue: PaginatedSearchOptions = Object.assign(currentPaginatedValue, { fixedFilter: fixedFilter });
|
|
||||||
this.paginatedSearchOptions.next(updatedPaginatedValue);
|
|
||||||
|
|
||||||
const currentValue: SearchOptions = this.searchOptions.getValue();
|
|
||||||
const updatedValue: SearchOptions = Object.assign(currentValue, { fixedFilter: fixedFilter });
|
|
||||||
this.searchOptions.next(updatedValue);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,3 @@
|
|||||||
@import '../../../styles/variables.scss';
|
|
||||||
|
|
||||||
.setting-option {
|
.setting-option {
|
||||||
border: 1px solid map-get($theme-colors, light);
|
border: 1px solid map-get($theme-colors, light);
|
||||||
}
|
}
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
<div id="search-sidebar-content">
|
<div id="search-sidebar-content">
|
||||||
<ds-view-mode-switch [viewModeList]="viewModeList" class="d-none d-md-block"></ds-view-mode-switch>
|
<ds-view-mode-switch [viewModeList]="viewModeList" class="d-none d-md-block"></ds-view-mode-switch>
|
||||||
<div class="sidebar-content">
|
<div class="sidebar-content">
|
||||||
<ds-search-switch-configuration *ngIf="configurationList" [configurationList]="configurationList"></ds-search-switch-configuration>
|
<ds-search-switch-configuration [inPlaceSearch]="inPlaceSearch" *ngIf="configurationList" [configurationList]="configurationList"></ds-search-switch-configuration>
|
||||||
<ds-search-filters [inPlaceSearch]="inPlaceSearch"></ds-search-filters>
|
<ds-search-filters [inPlaceSearch]="inPlaceSearch"></ds-search-filters>
|
||||||
<ds-search-settings [inPlaceSearch]="inPlaceSearch"></ds-search-settings>
|
<ds-search-settings [inPlaceSearch]="inPlaceSearch"></ds-search-settings>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,6 +1,3 @@
|
|||||||
@import '../../../styles/variables.scss';
|
|
||||||
@import '../../../styles/mixins.scss';
|
|
||||||
|
|
||||||
:host {
|
:host {
|
||||||
.results {
|
.results {
|
||||||
line-height: $button-height;
|
line-height: $button-height;
|
||||||
|
@@ -94,7 +94,7 @@ describe('SearchSwitchConfigurationComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should navigate to the route when selecting an option', () => {
|
it('should navigate to the route when selecting an option', () => {
|
||||||
(comp as any).searchService.getSearchLink.and.returnValue(MYDSPACE_ROUTE);
|
spyOn((comp as any), 'getSearchLinkParts').and.returnValue([MYDSPACE_ROUTE]);
|
||||||
comp.selectedOption = MyDSpaceConfigurationValueType.Workflow;
|
comp.selectedOption = MyDSpaceConfigurationValueType.Workflow;
|
||||||
const navigationExtras: NavigationExtras = {
|
const navigationExtras: NavigationExtras = {
|
||||||
queryParams: {configuration: MyDSpaceConfigurationValueType.Workflow},
|
queryParams: {configuration: MyDSpaceConfigurationValueType.Workflow},
|
||||||
|
@@ -20,6 +20,10 @@ import { SearchService } from '../search-service/search.service';
|
|||||||
*/
|
*/
|
||||||
export class SearchSwitchConfigurationComponent implements OnDestroy, OnInit {
|
export class SearchSwitchConfigurationComponent implements OnDestroy, OnInit {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True when the search component should show results on the current page
|
||||||
|
*/
|
||||||
|
@Input() inPlaceSearch;
|
||||||
/**
|
/**
|
||||||
* The list of available configuration options
|
* The list of available configuration options
|
||||||
*/
|
*/
|
||||||
@@ -56,7 +60,7 @@ export class SearchSwitchConfigurationComponent implements OnDestroy, OnInit {
|
|||||||
queryParams: {configuration: this.selectedOption},
|
queryParams: {configuration: this.selectedOption},
|
||||||
};
|
};
|
||||||
|
|
||||||
this.router.navigate([this.searchService.getSearchLink()], navigationExtras);
|
this.router.navigate(this.getSearchLinkParts(), navigationExtras);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -77,4 +81,24 @@ export class SearchSwitchConfigurationComponent implements OnDestroy, OnInit {
|
|||||||
this.sub.unsubscribe();
|
this.sub.unsubscribe();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string} The base path to the search page, or the current page when inPlaceSearch is true
|
||||||
|
*/
|
||||||
|
public getSearchLink(): string {
|
||||||
|
if (this.inPlaceSearch) {
|
||||||
|
return './';
|
||||||
|
}
|
||||||
|
return this.searchService.getSearchLink();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string[]} The base path to the search page, or the current page when inPlaceSearch is true, split in separate pieces
|
||||||
|
*/
|
||||||
|
public getSearchLinkParts(): string[] {
|
||||||
|
if (this.searchService) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return this.getSearchLink().split('/');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -9,7 +9,6 @@
|
|||||||
<ds-notifications-board
|
<ds-notifications-board
|
||||||
[options]="config.notifications">
|
[options]="config.notifications">
|
||||||
</ds-notifications-board>
|
</ds-notifications-board>
|
||||||
|
|
||||||
<main class="main-content">
|
<main class="main-content">
|
||||||
<div class="container" *ngIf="isLoading">
|
<div class="container" *ngIf="isLoading">
|
||||||
<ds-loading message="{{'loading.default' | translate}}"></ds-loading>
|
<ds-loading message="{{'loading.default' | translate}}"></ds-loading>
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
@import '../styles/variables.scss';
|
|
||||||
@import '../styles/helpers/font_awesome_imports.scss';
|
@import '../styles/helpers/font_awesome_imports.scss';
|
||||||
@import '../../node_modules/bootstrap/scss/bootstrap.scss';
|
@import '../../node_modules/bootstrap/scss/bootstrap.scss';
|
||||||
@import '../../node_modules/nouislider/distribute/nouislider.min';
|
@import '../../node_modules/nouislider/distribute/nouislider.min';
|
||||||
@@ -48,4 +47,3 @@ ds-admin-sidebar {
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: $sidebar-z-index;
|
z-index: $sidebar-z-index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -28,10 +28,10 @@ import variables from '../styles/_exposed_variables.scss';
|
|||||||
import { CSSVariableService } from './shared/sass-helper/sass-helper.service';
|
import { CSSVariableService } from './shared/sass-helper/sass-helper.service';
|
||||||
import { MenuService } from './shared/menu/menu.service';
|
import { MenuService } from './shared/menu/menu.service';
|
||||||
import { MenuID } from './shared/menu/initial-menus-state';
|
import { MenuID } from './shared/menu/initial-menus-state';
|
||||||
import { Observable } from 'rxjs/internal/Observable';
|
import { combineLatest as combineLatestObservable, Observable, of } from 'rxjs';
|
||||||
import { slideSidebarPadding } from './shared/animations/slide';
|
import { slideSidebarPadding } from './shared/animations/slide';
|
||||||
import { combineLatest as combineLatestObservable } from 'rxjs';
|
|
||||||
import { HostWindowService } from './shared/host-window.service';
|
import { HostWindowService } from './shared/host-window.service';
|
||||||
|
import { Theme } from '../config/theme.inferface';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-app',
|
selector: 'ds-app',
|
||||||
@@ -47,6 +47,7 @@ export class AppComponent implements OnInit, AfterViewInit {
|
|||||||
slideSidebarOver: Observable<boolean>;
|
slideSidebarOver: Observable<boolean>;
|
||||||
collapsedSidebarWidth: Observable<string>;
|
collapsedSidebarWidth: Observable<string>;
|
||||||
totalSidebarWidth: Observable<string>;
|
totalSidebarWidth: Observable<string>;
|
||||||
|
theme: Observable<Theme> = of({} as any);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(GLOBAL_CONFIG) public config: GlobalConfig,
|
@Inject(GLOBAL_CONFIG) public config: GlobalConfig,
|
||||||
@@ -57,10 +58,9 @@ export class AppComponent implements OnInit, AfterViewInit {
|
|||||||
private angulartics2GoogleAnalytics: Angulartics2GoogleAnalytics,
|
private angulartics2GoogleAnalytics: Angulartics2GoogleAnalytics,
|
||||||
private authService: AuthService,
|
private authService: AuthService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private routeService: RouteService,
|
|
||||||
private cssService: CSSVariableService,
|
private cssService: CSSVariableService,
|
||||||
private menuService: MenuService,
|
private menuService: MenuService,
|
||||||
private windowService: HostWindowService
|
private windowService: HostWindowService,
|
||||||
) {
|
) {
|
||||||
// Load all the languages that are defined as active from the config file
|
// Load all the languages that are defined as active from the config file
|
||||||
translate.addLangs(config.languages.filter((LangConfig) => LangConfig.active === true).map((a) => a.code));
|
translate.addLangs(config.languages.filter((LangConfig) => LangConfig.active === true).map((a) => a.code));
|
||||||
@@ -77,16 +77,14 @@ export class AppComponent implements OnInit, AfterViewInit {
|
|||||||
|
|
||||||
metadata.listenForRouteChange();
|
metadata.listenForRouteChange();
|
||||||
|
|
||||||
routeService.saveRouting();
|
|
||||||
|
|
||||||
if (config.debug) {
|
if (config.debug) {
|
||||||
console.info(config);
|
console.info(config);
|
||||||
}
|
}
|
||||||
this.storeCSSVariables();
|
this.storeCSSVariables();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
|
||||||
const env: string = this.config.production ? 'Production' : 'Development';
|
const env: string = this.config.production ? 'Production' : 'Development';
|
||||||
const color: string = this.config.production ? 'red' : 'green';
|
const color: string = this.config.production ? 'red' : 'green';
|
||||||
console.info(`Environment: %c${env}`, `color: ${color}; font-weight: bold;`);
|
console.info(`Environment: %c${env}`, `color: ${color}; font-weight: bold;`);
|
||||||
|
@@ -37,6 +37,8 @@ import { AdminSidebarComponent } from './+admin/admin-sidebar/admin-sidebar.comp
|
|||||||
import { AdminSidebarSectionComponent } from './+admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component';
|
import { AdminSidebarSectionComponent } from './+admin/admin-sidebar/admin-sidebar-section/admin-sidebar-section.component';
|
||||||
import { ExpandableAdminSidebarSectionComponent } from './+admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component';
|
import { ExpandableAdminSidebarSectionComponent } from './+admin/admin-sidebar/expandable-admin-sidebar-section/expandable-admin-sidebar-section.component';
|
||||||
import { NavbarModule } from './navbar/navbar.module';
|
import { NavbarModule } from './navbar/navbar.module';
|
||||||
|
import { JournalEntitiesModule } from './entity-groups/journal-entities/journal-entities.module';
|
||||||
|
import { ResearchEntitiesModule } from './entity-groups/research-entities/research-entities.module';
|
||||||
|
|
||||||
export function getConfig() {
|
export function getConfig() {
|
||||||
return ENV_CONFIG;
|
return ENV_CONFIG;
|
||||||
@@ -66,6 +68,11 @@ const IMPORTS = [
|
|||||||
StoreRouterConnectingModule,
|
StoreRouterConnectingModule,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const ENTITY_IMPORTS = [
|
||||||
|
JournalEntitiesModule,
|
||||||
|
ResearchEntitiesModule
|
||||||
|
];
|
||||||
|
|
||||||
IMPORTS.push(
|
IMPORTS.push(
|
||||||
StoreDevtoolsModule.instrument({
|
StoreDevtoolsModule.instrument({
|
||||||
maxAge: 100,
|
maxAge: 100,
|
||||||
@@ -112,7 +119,8 @@ const EXPORTS = [
|
|||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
...IMPORTS
|
...IMPORTS,
|
||||||
|
...ENTITY_IMPORTS
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
...PROVIDERS
|
...PROVIDERS
|
||||||
|
@@ -21,16 +21,18 @@ export class NormalizedRelationship extends NormalizedObject<Relationship> {
|
|||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The identifier of the Item to the left side of this Relationship
|
* The item to the left of this relationship
|
||||||
*/
|
*/
|
||||||
@autoserialize
|
@autoserialize
|
||||||
leftId: string;
|
@relationship(ResourceType.Item, false)
|
||||||
|
leftItem: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The identifier of the Item to the right side of this Relationship
|
* The item to the right of this relationship
|
||||||
*/
|
*/
|
||||||
@autoserialize
|
@autoserialize
|
||||||
rightId: string;
|
@relationship(ResourceType.Item, false)
|
||||||
|
rightItem: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The place of the Item to the left side of this Relationship
|
* The place of the Item to the left side of this Relationship
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import { ObjectCacheEffects } from './cache/object-cache.effects';
|
import { ObjectCacheEffects } from './cache/object-cache.effects';
|
||||||
import { UUIDIndexEffects } from './index/index.effects';
|
import { UUIDIndexEffects } from './index/index.effects';
|
||||||
import { RequestEffects } from './data/request.effects';
|
import { RequestEffects } from './data/request.effects';
|
||||||
@@ -6,6 +5,7 @@ import { AuthEffects } from './auth/auth.effects';
|
|||||||
import { JsonPatchOperationsEffects } from './json-patch/json-patch-operations.effects';
|
import { JsonPatchOperationsEffects } from './json-patch/json-patch-operations.effects';
|
||||||
import { ServerSyncBufferEffects } from './cache/server-sync-buffer.effects';
|
import { ServerSyncBufferEffects } from './cache/server-sync-buffer.effects';
|
||||||
import { ObjectUpdatesEffects } from './data/object-updates/object-updates.effects';
|
import { ObjectUpdatesEffects } from './data/object-updates/object-updates.effects';
|
||||||
|
import { RouteEffects } from '../shared/services/route.effects';
|
||||||
|
|
||||||
export const coreEffects = [
|
export const coreEffects = [
|
||||||
RequestEffects,
|
RequestEffects,
|
||||||
@@ -14,5 +14,6 @@ export const coreEffects = [
|
|||||||
AuthEffects,
|
AuthEffects,
|
||||||
JsonPatchOperationsEffects,
|
JsonPatchOperationsEffects,
|
||||||
ServerSyncBufferEffects,
|
ServerSyncBufferEffects,
|
||||||
ObjectUpdatesEffects
|
ObjectUpdatesEffects,
|
||||||
|
RouteEffects
|
||||||
];
|
];
|
||||||
|
@@ -13,6 +13,7 @@ import {
|
|||||||
objectUpdatesReducer,
|
objectUpdatesReducer,
|
||||||
ObjectUpdatesState
|
ObjectUpdatesState
|
||||||
} from './data/object-updates/object-updates.reducer';
|
} from './data/object-updates/object-updates.reducer';
|
||||||
|
import { routeReducer, RouteState } from '../shared/services/route.reducer';
|
||||||
|
|
||||||
export interface CoreState {
|
export interface CoreState {
|
||||||
'cache/object': ObjectCacheState,
|
'cache/object': ObjectCacheState,
|
||||||
@@ -21,7 +22,8 @@ export interface CoreState {
|
|||||||
'data/request': RequestState,
|
'data/request': RequestState,
|
||||||
'index': MetaIndexState,
|
'index': MetaIndexState,
|
||||||
'auth': AuthState,
|
'auth': AuthState,
|
||||||
'json/patch': JsonPatchOperationsState
|
'json/patch': JsonPatchOperationsState,
|
||||||
|
'route': RouteState
|
||||||
}
|
}
|
||||||
|
|
||||||
export const coreReducers: ActionReducerMap<CoreState> = {
|
export const coreReducers: ActionReducerMap<CoreState> = {
|
||||||
@@ -31,5 +33,6 @@ export const coreReducers: ActionReducerMap<CoreState> = {
|
|||||||
'data/request': requestReducer,
|
'data/request': requestReducer,
|
||||||
'index': indexReducer,
|
'index': indexReducer,
|
||||||
'auth': authReducer,
|
'auth': authReducer,
|
||||||
'json/patch': jsonPatchOperationsReducer
|
'json/patch': jsonPatchOperationsReducer,
|
||||||
|
'route': routeReducer
|
||||||
};
|
};
|
||||||
|
@@ -89,7 +89,7 @@ describe('ComColDataService', () => {
|
|||||||
function initMockCommunityDataService(): CommunityDataService {
|
function initMockCommunityDataService(): CommunityDataService {
|
||||||
return jasmine.createSpyObj('responseCache', {
|
return jasmine.createSpyObj('responseCache', {
|
||||||
getEndpoint: hot('--a-', { a: communitiesEndpoint }),
|
getEndpoint: hot('--a-', { a: communitiesEndpoint }),
|
||||||
getIDHref: cold('b-', { b: communityEndpoint })
|
getIDHref: communityEndpoint
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -31,7 +31,7 @@ export abstract class ComColDataService<T extends CacheableObject> extends DataS
|
|||||||
return this.halService.getEndpoint(linkPath);
|
return this.halService.getEndpoint(linkPath);
|
||||||
} else {
|
} else {
|
||||||
const scopeCommunityHrefObs = this.cds.getEndpoint().pipe(
|
const scopeCommunityHrefObs = this.cds.getEndpoint().pipe(
|
||||||
mergeMap((endpoint: string) => this.cds.getIDHref(endpoint, options.scopeID)),
|
map((endpoint: string) => this.cds.getIDHref(endpoint, options.scopeID)),
|
||||||
filter((href: string) => isNotEmpty(href)),
|
filter((href: string) => isNotEmpty(href)),
|
||||||
take(1),
|
take(1),
|
||||||
tap((href: string) => {
|
tap((href: string) => {
|
||||||
|
@@ -14,7 +14,7 @@ export const IndexActionTypes = {
|
|||||||
|
|
||||||
/* tslint:disable:max-classes-per-file */
|
/* tslint:disable:max-classes-per-file */
|
||||||
/**
|
/**
|
||||||
* An ngrx action to add an value to the index
|
* An ngrx action to add a value to the index
|
||||||
*/
|
*/
|
||||||
export class AddToIndexAction implements Action {
|
export class AddToIndexAction implements Action {
|
||||||
type = IndexActionTypes.ADD;
|
type = IndexActionTypes.ADD;
|
||||||
@@ -40,7 +40,7 @@ export class AddToIndexAction implements Action {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An ngrx action to remove an value from the index
|
* An ngrx action to remove a value from the index
|
||||||
*/
|
*/
|
||||||
export class RemoveFromIndexByValueAction implements Action {
|
export class RemoveFromIndexByValueAction implements Action {
|
||||||
type = IndexActionTypes.REMOVE_BY_VALUE;
|
type = IndexActionTypes.REMOVE_BY_VALUE;
|
||||||
|
@@ -3,6 +3,7 @@ import { CacheableObject } from '../../cache/object-cache.reducer';
|
|||||||
import { RemoteData } from '../../data/remote-data';
|
import { RemoteData } from '../../data/remote-data';
|
||||||
import { ResourceType } from '../resource-type';
|
import { ResourceType } from '../resource-type';
|
||||||
import { RelationshipType } from './relationship-type.model';
|
import { RelationshipType } from './relationship-type.model';
|
||||||
|
import { Item } from '../item.model';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Describes a Relationship between two Items
|
* Describes a Relationship between two Items
|
||||||
@@ -26,14 +27,14 @@ export class Relationship implements CacheableObject {
|
|||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The identifier of the Item to the left side of this Relationship
|
* The item to the left of this relationship
|
||||||
*/
|
*/
|
||||||
leftId: string;
|
leftItem: Observable<RemoteData<Item>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The identifier of the Item to the right side of this Relationship
|
* The item to the right of this relationship
|
||||||
*/
|
*/
|
||||||
rightId: string;
|
rightItem: Observable<RemoteData<Item>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The place of the Item to the left side of this Relationship
|
* The place of the Item to the left side of this Relationship
|
||||||
|
@@ -4,14 +4,14 @@
|
|||||||
[innerHTML]="firstMetadataValue('dc.title')"></a>
|
[innerHTML]="firstMetadataValue('dc.title')"></a>
|
||||||
<span class="text-muted">
|
<span class="text-muted">
|
||||||
<ds-truncatable-part [id]="item.id" [minLines]="1">
|
<ds-truncatable-part [id]="item.id" [minLines]="1">
|
||||||
<span *ngIf="item.allMetadata(['journalvolume.identifier.volume']).length > 0"
|
<span *ngIf="item.allMetadata(['publicationvolume.volumeNumber']).length > 0"
|
||||||
class="item-list-journal-issues">
|
class="item-list-journal-issues">
|
||||||
<span *ngFor="let value of allMetadataValues(['journalvolume.identifier.volume']); let last=last;">
|
<span *ngFor="let value of allMetadataValues(['publicationvolume.volumeNumber']); let last=last;">
|
||||||
<span [innerHTML]="value"><span [innerHTML]="value"></span></span>
|
<span [innerHTML]="value"><span [innerHTML]="value"></span></span>
|
||||||
</span>
|
</span>
|
||||||
<span *ngIf="item.allMetadata(['journalissue.identifier.number']).length > 0"
|
<span *ngIf="item.allMetadata(['publicationissue.issueNumber']).length > 0"
|
||||||
class="item-list-journal-issue-numbers">
|
class="item-list-journal-issue-numbers">
|
||||||
<span *ngFor="let value of allMetadataValues(['journalissue.identifier.number']); let last=last;">
|
<span *ngFor="let value of allMetadataValues(['publicationissue.issueNumber']); let last=last;">
|
||||||
<span> - </span><span [innerHTML]="value"><span [innerHTML]="value"></span></span>
|
<span> - </span><span [innerHTML]="value"><span [innerHTML]="value"></span></span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
@@ -1,12 +1,12 @@
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
|
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
import { Item } from '../../../../../core/shared/item.model';
|
|
||||||
import { TruncatePipe } from '../../../../utils/truncate.pipe';
|
|
||||||
import { TruncatableService } from '../../../../truncatable/truncatable.service';
|
|
||||||
import { ITEM } from '../../../../items/switcher/item-type-switcher.component';
|
|
||||||
import { JournalIssueListElementComponent } from './journal-issue-list-element.component';
|
import { JournalIssueListElementComponent } from './journal-issue-list-element.component';
|
||||||
import { of as observableOf } from 'rxjs';
|
import { of as observableOf } from 'rxjs';
|
||||||
|
import { Item } from '../../../../core/shared/item.model';
|
||||||
|
import { TruncatePipe } from '../../../../shared/utils/truncate.pipe';
|
||||||
|
import { ITEM } from '../../../../shared/items/switcher/item-type-switcher.component';
|
||||||
|
import { TruncatableService } from '../../../../shared/truncatable/truncatable.service';
|
||||||
|
|
||||||
let journalIssueListElementComponent: JournalIssueListElementComponent;
|
let journalIssueListElementComponent: JournalIssueListElementComponent;
|
||||||
let fixture: ComponentFixture<JournalIssueListElementComponent>;
|
let fixture: ComponentFixture<JournalIssueListElementComponent>;
|
||||||
@@ -20,13 +20,13 @@ const mockItemWithMetadata: Item = Object.assign(new Item(), {
|
|||||||
value: 'This is just another title'
|
value: 'This is just another title'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
'journalvolume.identifier.volume': [
|
'publicationvolume.volumeNumber': [
|
||||||
{
|
{
|
||||||
language: 'en_US',
|
language: 'en_US',
|
||||||
value: '1234'
|
value: '1234'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
'journalissue.identifier.number': [
|
'publicationissue.issueNumber': [
|
||||||
{
|
{
|
||||||
language: 'en_US',
|
language: 'en_US',
|
||||||
value: '5678'
|
value: '5678'
|
@@ -1,6 +1,6 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { ItemViewMode, rendersItemType } from '../../../../items/item-type-decorator';
|
import { ItemViewMode, rendersItemType } from '../../../../shared/items/item-type-decorator';
|
||||||
import { TypedItemSearchResultListElementComponent } from '../typed-item-search-result-list-element.component';
|
import { TypedItemSearchResultListElementComponent } from '../../../../shared/object-list/item-list-element/item-types/typed-item-search-result-list-element.component';
|
||||||
|
|
||||||
@rendersItemType('JournalIssue', ItemViewMode.Element)
|
@rendersItemType('JournalIssue', ItemViewMode.Element)
|
||||||
@Component({
|
@Component({
|
@@ -10,9 +10,9 @@
|
|||||||
<span [innerHTML]="value"><span [innerHTML]="value"></span></span>
|
<span [innerHTML]="value"><span [innerHTML]="value"></span></span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<span *ngIf="item.allMetadata(['journalvolume.identifier.volume']).length > 0"
|
<span *ngIf="item.allMetadata(['publicationvolume.volumeNumber']).length > 0"
|
||||||
class="item-list-journal-volume-identifiers">
|
class="item-list-journal-volume-identifiers">
|
||||||
<span *ngFor="let value of allMetadataValues(['journalvolume.identifier.volume']); let last=last;">
|
<span *ngFor="let value of allMetadataValues(['publicationvolume.volumeNumber']); let last=last;">
|
||||||
<span> (</span><span [innerHTML]="value"><span [innerHTML]="value"></span></span><span>)</span>
|
<span> (</span><span [innerHTML]="value"><span [innerHTML]="value"></span></span><span>)</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user