Merge branch 'master' into w2p-62589_Item-mapper-update

Conflicts:
	resources/i18n/en.json
	src/app/+search-page/search-service/search.service.ts
	src/app/core/core.module.ts
This commit is contained in:
Kristof De Langhe
2019-08-12 15:23:43 +02:00
476 changed files with 6780 additions and 5048 deletions

2
.gitignore vendored
View File

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

View File

@@ -11,7 +11,7 @@ language: node_js
node_js: node_js:
- "8" - "8"
- "9" - "10"
cache: cache:
yarn: true yarn: true

View File

@@ -14,7 +14,7 @@ If you're looking for the 2016 Angular 2 DSpace UI prototype, you can find it [h
Quick start Quick start
----------- -----------
**Ensure you're running [Node](https://nodejs.org) >= `v8.0.x`, [npm](https://www.npmjs.com/) >= `v5.x` and [yarn](https://yarnpkg.com) >= `v1.x`** **Ensure you're running [Node](https://nodejs.org) `v8.0.x` or `v10.0.x`, [npm](https://www.npmjs.com/) >= `v5.x` and [yarn](https://yarnpkg.com) >= `v1.x`**
```bash ```bash
# clone the repo # clone the repo
@@ -65,7 +65,7 @@ Requirements
------------ ------------
- [Node.js](https://nodejs.org), [npm](https://www.npmjs.com/), and [yarn](https://yarnpkg.com) - [Node.js](https://nodejs.org), [npm](https://www.npmjs.com/), and [yarn](https://yarnpkg.com)
- Ensure you're running node >= `v8.x`, npm >= `v5.x` and yarn >= `v1.x` - Ensure you're running node `v8.x` or `v10.x`, npm >= `v5.x` and yarn >= `v1.x`
If you have [`nvm`](https://github.com/creationix/nvm#install-script) or [`nvm-windows`](https://github.com/coreybutler/nvm-windows) installed, which is highly recommended, you can run `nvm install --lts && nvm use` to install and start using the latest Node LTS. If you have [`nvm`](https://github.com/creationix/nvm#install-script) or [`nvm-windows`](https://github.com/coreybutler/nvm-windows) installed, which is highly recommended, you can run `nvm install --lts && nvm use` to install and start using the latest Node LTS.

View File

@@ -13,7 +13,7 @@ module.exports = {
host: 'dspace7.4science.cloud', host: 'dspace7.4science.cloud',
port: 443, port: 443,
// NOTE: Space is capitalized because 'namespace' is a reserved string in TypeScript // NOTE: Space is capitalized because 'namespace' is a reserved string in TypeScript
nameSpace: '/dspace-spring-rest/api' nameSpace: '/server/api'
}, },
// Caching settings // Caching settings
cache: { cache: {
@@ -149,11 +149,39 @@ module.exports = {
// Limit for years to display using jumps of five years (current year - fiveYearLimit) // Limit for years to display using jumps of five years (current year - fiveYearLimit)
fiveYearLimit: 30, fiveYearLimit: 30,
// The absolute lowest year to display in the dropdown (only used when no lowest date can be found for all items) // The absolute lowest year to display in the dropdown (only used when no lowest date can be found for all items)
defaultLowerLimit: 1900 defaultLowerLimit: 1900,
// List of all the active Browse-By types
// Adding a type will activate their Browse-By page and add them to the global navigation menu, as well as community and collection pages
// Allowed fields and their purpose:
// id: The browse id to use for fetching info from the rest api
// type: The type of Browse-By page to display
// metadataField: The metadata-field used to create starts-with options (only necessary when the type is set to 'date')
types: [
{
id: 'title',
type: 'title'
},
{
id: 'dateissued',
type: 'date',
metadataField: 'dc.date.issued'
},
{
id: 'author',
type: 'metadata'
},
{
id: 'subject',
type: 'metadata'
}
]
}, },
item: { item: {
edit: { edit: {
undoTimeout: 10000 // 10 seconds undoTimeout: 10000 // 10 seconds
} }
},
theme: {
name: 'default',
} }
}; };

View File

@@ -8,7 +8,7 @@
}, },
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"engines": { "engines": {
"node": ">=8.0.0" "node": "8.* || >= 10.*"
}, },
"scripts": { "scripts": {
"global": "npm install -g @angular/cli marked node-gyp nodemon node-nightly npm-check-updates npm-run-all rimraf typescript ts-node typedoc webpack webpack-bundle-analyzer pm2 rollup", "global": "npm install -g @angular/cli marked node-gyp nodemon node-nightly npm-check-updates npm-run-all rimraf typescript ts-node typedoc webpack webpack-bundle-analyzer pm2 rollup",
@@ -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",
@@ -49,7 +51,7 @@
"debug:server": "node-nightly --inspect --debug-brk dist/server.js", "debug:server": "node-nightly --inspect --debug-brk dist/server.js",
"debug:build": "node-nightly --inspect --debug-brk node_modules/webpack/bin/webpack.js --mode development", "debug:build": "node-nightly --inspect --debug-brk node_modules/webpack/bin/webpack.js --mode development",
"debug:build:prod": "node-nightly --inspect --debug-brk node_modules/webpack/bin/webpack.js --env.aot --env.client --env.server --mode production", "debug:build:prod": "node-nightly --inspect --debug-brk node_modules/webpack/bin/webpack.js --env.aot --env.client --env.server --mode production",
"ci": "yarn run lint && yarn run build:aot && yarn run test:headless && npm-run-all -p -r server e2e", "ci": "yarn run lint && yarn run build:aot && yarn run test:headless",
"protractor": "node node_modules/protractor/bin/protractor", "protractor": "node node_modules/protractor/bin/protractor",
"pree2e": "yarn run webdriver:update", "pree2e": "yarn run webdriver:update",
"e2e": "yarn run protractor", "e2e": "yarn run protractor",
@@ -60,7 +62,9 @@
"webdriver:update": "node node_modules/protractor/bin/webdriver-manager update --standalone --gecko false", "webdriver:update": "node node_modules/protractor/bin/webdriver-manager update --standalone --gecko false",
"lint": "tslint \"src/**/*.ts\" && tslint \"e2e/**/*.ts\"", "lint": "tslint \"src/**/*.ts\" && tslint \"e2e/**/*.ts\"",
"docs": "typedoc --options typedoc.json ./src/", "docs": "typedoc --options typedoc.json ./src/",
"coverage": "http-server -c-1 -o -p 9875 ./coverage" "coverage": "http-server -c-1 -o -p 9875 ./coverage",
"postinstall": "yarn run patch-protractor",
"patch-protractor": "ncp node_modules/webdriver-manager node_modules/protractor/node_modules/webdriver-manager"
}, },
"dependencies": { "dependencies": {
"@angular/animations": "^6.1.4", "@angular/animations": "^6.1.4",
@@ -94,6 +98,7 @@
"compression": "1.7.1", "compression": "1.7.1",
"cookie-parser": "1.4.3", "cookie-parser": "1.4.3",
"core-js": "^2.5.7", "core-js": "^2.5.7",
"debug-loader": "^0.0.1",
"express": "4.16.2", "express": "4.16.2",
"express-session": "1.15.6", "express-session": "1.15.6",
"fast-json-patch": "^2.0.7", "fast-json-patch": "^2.0.7",
@@ -117,10 +122,11 @@
"ngx-moment": "^3.1.0", "ngx-moment": "^3.1.0",
"ngx-pagination": "3.0.3", "ngx-pagination": "3.0.3",
"nouislider": "^11.0.0", "nouislider": "^11.0.0",
"pem": "1.12.3", "pem": "1.13.2",
"reflect-metadata": "0.1.12", "reflect-metadata": "0.1.12",
"rxjs": "6.2.2", "rxjs": "6.2.2",
"rxjs-spy": "^7.5.1", "rxjs-spy": "^7.5.1",
"sass-resources-loader": "^2.0.0",
"sortablejs": "1.7.0", "sortablejs": "1.7.0",
"text-mask-core": "5.0.1", "text-mask-core": "5.0.1",
"ts-loader": "^5.2.1", "ts-loader": "^5.2.1",
@@ -163,6 +169,7 @@
"codelyzer": "^4.4.4", "codelyzer": "^4.4.4",
"compression-webpack-plugin": "^1.1.6", "compression-webpack-plugin": "^1.1.6",
"copy-webpack-plugin": "^4.4.1", "copy-webpack-plugin": "^4.4.1",
"copyfiles": "^2.1.1",
"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",
@@ -185,8 +192,9 @@
"karma-remap-coverage": "^0.1.5", "karma-remap-coverage": "^0.1.5",
"karma-remap-istanbul": "0.6.0", "karma-remap-istanbul": "0.6.0",
"karma-sourcemap-loader": "0.3.7", "karma-sourcemap-loader": "0.3.7",
"karma-webdriver-launcher": "1.0.5", "karma-webdriver-launcher": "^1.0.7",
"karma-webpack": "3.0.0", "karma-webpack": "3.0.0",
"ncp": "^2.0.0",
"ngrx-store-freeze": "^0.2.4", "ngrx-store-freeze": "^0.2.4",
"node-sass": "^4.11.0", "node-sass": "^4.11.0",
"nodemon": "^1.15.0", "nodemon": "^1.15.0",
@@ -199,7 +207,7 @@
"postcss-loader": "^3.0.0", "postcss-loader": "^3.0.0",
"postcss-responsive-type": "1.0.0", "postcss-responsive-type": "1.0.0",
"postcss-smart-import": "0.7.6", "postcss-smart-import": "0.7.6",
"protractor": "^5.3.0", "protractor": "^5.4.2",
"protractor-istanbul-plugin": "2.0.0", "protractor-istanbul-plugin": "2.0.0",
"raw-loader": "0.5.1", "raw-loader": "0.5.1",
"resolve-url-loader": "^2.3.0", "resolve-url-loader": "^2.3.0",
@@ -213,17 +221,19 @@
"script-ext-html-webpack-plugin": "2.0.1", "script-ext-html-webpack-plugin": "2.0.1",
"source-map": "0.7.3", "source-map": "0.7.3",
"source-map-loader": "0.2.4", "source-map-loader": "0.2.4",
"string-replace-loader": "2.1.1", "string-replace-loader": "^2.1.1",
"to-string-loader": "1.1.5", "to-string-loader": "1.1.5",
"ts-helpers": "1.1.2", "ts-helpers": "1.1.2",
"ts-node": "4.1.0", "ts-node": "4.1.0",
"tslint": "5.11.0", "tslint": "5.11.0",
"typedoc": "^0.9.0", "typedoc": "^0.9.0",
"typescript": "^2.9.1", "typescript": "^2.9.1",
"webdriver-manager": "^12.1.6",
"webpack": "^4.17.1", "webpack": "^4.17.1",
"webpack-bundle-analyzer": "^3.3.2", "webpack-bundle-analyzer": "^3.3.2",
"webpack-dev-middleware": "3.2.0", "webpack-dev-middleware": "3.2.0",
"webpack-dev-server": "^3.1.5", "webpack-dev-server": "^3.1.11",
"webpack-import-glob-loader": "^1.6.3",
"webpack-merge": "4.1.4", "webpack-merge": "4.1.4",
"webpack-node-externals": "1.7.2" "webpack-node-externals": "1.7.2"
} }

View File

@@ -1,277 +1,149 @@
{ {
"footer": { "404.help": "Nepodařilo se najít stránku, kterou hledáte. Je možné, že stránka byla přesunuta nebo smazána. Pomocí tlačítka níže můžete přejít na domovskou stránku. ",
"copyright": "copyright © 2002-{{ year }}", "404.link.home-page": "Přejít na domovskou stránku",
"link.dspace": "software DSpace", "404.page-not-found": "stránka nenalezena",
"link.duraspace": "DuraSpace" "admin.registries.bitstream-formats.description": "Tento seznam formátů souborů poskytuje informace o známých formátech a o úrovni jejich podpory.",
}, "admin.registries.bitstream-formats.formats.no-items": "Žádné formáty souborů.",
"collection": { "admin.registries.bitstream-formats.formats.table.internal": "interní",
"page": { "admin.registries.bitstream-formats.formats.table.mimetype": "Typ MIME",
"news": "Novinky", "admin.registries.bitstream-formats.formats.table.name": "Název",
"license": "Licence", "admin.registries.bitstream-formats.formats.table.supportLevel.0": "Neznámá",
"browse": { "admin.registries.bitstream-formats.formats.table.supportLevel.1": "Známá",
"recent": { "admin.registries.bitstream-formats.formats.table.supportLevel.2": "Podpora",
"head": "Poslední příspěvky" "admin.registries.bitstream-formats.formats.table.supportLevel.head": "Úroveň podpory",
} "admin.registries.bitstream-formats.head": "Registr formátů souborů",
} "admin.registries.bitstream-formats.title": "DSpace Angular :: Registr formátů souborů",
} "admin.registries.metadata.description": "Registr metadat je seznam všech metadatových polí dostupných v repozitáři. Tyto pole mohou být rozdělena do více schémat. DSpace však vyžaduje použití schématu kvalifikový Dublin Core.",
}, "admin.registries.metadata.head": "Registr metadat",
"community": { "admin.registries.metadata.schemas.no-items": "Žádná schémata metadat.",
"page": { "admin.registries.metadata.schemas.table.id": "ID",
"news": "Novinky", "admin.registries.metadata.schemas.table.name": "Název",
"license": "Licence" "admin.registries.metadata.schemas.table.namespace": "Jmenný prostor",
}, "admin.registries.metadata.title": "DSpace Angular :: Registr metadat",
"sub-collection-list": { "admin.registries.schema.description": "Toto je schéma metadat pro „{{namespace}}“.",
"head": "Kolekce v této komunitě" "admin.registries.schema.fields.head": "Pole schématu metadat",
} "admin.registries.schema.fields.no-items": "Žádná metadatová pole.",
}, "admin.registries.schema.fields.table.field": "Pole",
"item": { "admin.registries.schema.fields.table.scopenote": "Poznámka o rozsahu",
"page": { "admin.registries.schema.head": "Metadata Schema",
"author": "Autor", "admin.registries.schema.title": "DSpace Angular :: Registr schémat metadat",
"abstract": "Abstract", "auth.errors.invalid-user": "Neplatná e-mailová adresa nebo heslo.",
"date": "Datum", "auth.messages.expired": "Vaše relace vypršela. Prosím, znova se přihlaste.",
"uri": "URI", "browse.title": "Prohlížíte {{ collection }} dle {{ field }} {{ value }}",
"files": "Soubory", "collection.page.browse.recent.head": "Poslední příspěvky",
"collections": "Kolekce", "collection.page.license": "Licence",
"filesection": { "collection.page.news": "Novinky",
"download": "Stáhnout", "community.page.license": "Licence",
"name": "Název:", "community.page.news": "Novinky",
"format": "Formát:", "community.sub-collection-list.head": "Kolekce v této komunitě",
"size": "Velikost:", "error.browse-by": "Chyba během stahování záznamů",
"description": "Popis:" "error.collection": "Chyba během stahování kolekce",
}, "error.community": "Chyba během stahování komunity",
"link": { "error.default": "Chyba",
"simple": "Minimální záznam", "error.item": "Chyba během stahování záznamu",
"full": "Úplný záznam" "error.objects": "Chyba během stahování objektů",
} "error.recent-submissions": "Chyba během stahování posledních příspěvků",
} "error.search-results": "Chyba během stahování výsledků hledání",
}, "error.sub-collections": "Chyba během stahování subkolekcí",
"nav": { "error.top-level-communities": "Chyba během stahování komunit nejvyšší úrovně",
"home": "Domů", "error.validation.license.notgranted": "Pro dokončení zaslání Musíte udělit licenci. Pokud v tuto chvíli tuto licenci nemůžete udělit, můžete svou práci uložit a později se k svému příspěveku vrátit nebo jej smazat.",
"login": "Přihlásit se", "error.validation.pattern": "Tento vstup je omezen dle vzoru: {{ pattern }}.",
"logout": "Odhlásit se" "footer.copyright": "copyright © 2002-{{ year }}",
}, "footer.link.dspace": "software DSpace",
"pagination": { "footer.link.duraspace": "DuraSpace",
"results-per-page": "Výsledků na stránku", "form.cancel": "Zrušit",
"sort-direction": "Seřazení", "form.first-name": "Křestní jméno",
"showing": { "form.group-collapse": "Sbalit",
"label": "Zobrazují se záznamy ", "form.group-collapse-help": "Kliknutím sem sbalíte",
"detail": "{{ range }} z {{ total }}" "form.group-expand": "Rozbalit",
} "form.group-expand-help": "Kliknutím sem rozbalíte a přidáte další prvky",
}, "form.last-name": "Příjmení",
"sorting": { "form.loading": "Načítá se...",
"score": { "form.no-results": "Nebyli nalezeny žádné výsledky",
"DESC": "Relevance" "form.no-value": "Nebyla zadána hodnota",
}, "form.remove": "Smazat",
"dc.title": { "form.search": "Hledat",
"ASC": "Název vzestupně", "form.submit": "Odeslat",
"DESC": "Název sestupně" "home.description": "",
} "home.title": "DSpace Angular :: Domů",
}, "home.top-level-communities.head": "Komunity v DSpace",
"title": "DSpace", "home.top-level-communities.help": "Vybráním komunity můžete prohlížet její kolekce.",
"404": { "item.page.abstract": "Abstract",
"help": "Nepodařilo se najít stránku, kterou hledáte. Je možné, že stránka byla přesunuta nebo smazána. Pomocí tlačítka níže můžete přejít na domovskou stránku. ", "item.page.author": "Autor",
"page-not-found": "stránka nenalezena", "item.page.collections": "Kolekce",
"link": { "item.page.date": "Datum",
"home-page": "Přejít na domovskou stránku" "item.page.files": "Soubory",
} "item.page.filesection.description": "Popis:",
}, "item.page.filesection.download": "Stáhnout",
"home": { "item.page.filesection.format": "Formát:",
"title": "DSpace Angular :: Domů", "item.page.filesection.name": "Název:",
"description": "", "item.page.filesection.size": "Velikost:",
"top-level-communities": { "item.page.link.full": "Úplný záznam",
"head": "Komunity v DSpace", "item.page.link.simple": "Minimální záznam",
"help": "Vybráním komunity můžete prohlížet její kolekce." "item.page.uri": "URI",
} "loading.browse-by": "Načítají se záznamy...",
}, "loading.collection": "Načítá se kolekce...",
"search": { "loading.community": "Načítá se komunita...",
"title": "DSpace Angular :: Hledat", "loading.default": "Načítá se...",
"description": "", "loading.item": "Načítá se záznam...",
"form": { "loading.objects": "Načítá se...",
"search": "Hledat", "loading.recent-submissions": "Načítají se poslední příspěvky...",
"search_dspace": "Hledat v DSpace" "loading.search-results": "Načítají se výsledky hledání...",
}, "loading.sub-collections": "Načítají se subkolekce...",
"results": { "loading.top-level-communities": "Načítají se komunity nejvyšší úrovně...",
"head": "Výsledky hledání", "login.form.email": "E-mailová adresa",
"no-results": "Nebyli nalezeny žádné výsledky" "login.form.forgot-password": "Zapomněli jste své heslo?",
}, "login.form.header": "Prosím, přihlaste se do DSpace",
"sidebar": { "login.form.new-user": "Nový uživatel? Zaregistrujte se kliknutím sem.",
"close": "Zpět na výsledky", "login.form.password": "Heslo",
"open": "Vyhledávací nástroje", "login.form.submit": "Přihlásit se",
"results": "výsledky", "login.title": "Přihlásit se",
"filters": { "logout.form.header": "Odhlásit se z DSpace",
"title": "Filtry" "logout.form.submit": "Odhlásit se",
}, "logout.title": "Odhlásit se",
"settings": { "nav.home": "Domů",
"title": "Nastavení", "nav.login": "Přihlásit se",
"sort-by": "Řadit dle", "nav.logout": "Odhlásit se",
"rpp": "Výsledků na stránku" "pagination.results-per-page": "Výsledků na stránku",
} "pagination.showing.detail": "{{ range }} z {{ total }}",
}, "pagination.showing.label": "Zobrazují se záznamy ",
"view-switch": { "pagination.sort-direction": "Seřazení",
"show-list": "Zobrazit seznam", "search.description": "",
"show-grid": "Zobrazit mřížku" "search.filters.applied.f.author": "Autor",
}, "search.filters.applied.f.dateIssued.max": "Do data",
"filters": { "search.filters.applied.f.dateIssued.min": "Od data",
"head": "Filtry", "search.filters.applied.f.has_content_in_original_bundle": "Má soubory",
"reset": "Obnovit filtry", "search.filters.applied.f.subject": "Předmět",
"applied": { "search.filters.filter.author.head": "Autor",
"f.author": "Autor", "search.filters.filter.author.placeholder": "Jméno autora",
"f.dateIssued.min": "Od data", "search.filters.filter.dateIssued.head": "Datum",
"f.dateIssued.max": "Do data", "search.filters.filter.dateIssued.max.placeholder": "Datum od",
"f.subject": "Předmět", "search.filters.filter.dateIssued.min.placeholder": "Datum do",
"f.has_content_in_original_bundle": "Má soubory" "search.filters.filter.has_content_in_original_bundle.head": "Má soubory",
}, "search.filters.filter.scope.head": "Rozsah",
"filter": { "search.filters.filter.scope.placeholder": "Filtr rozsahu",
"show-more": "Zobrazit více", "search.filters.filter.show-less": "Sbalit",
"show-less": "Sbalit", "search.filters.filter.show-more": "Zobrazit více",
"author": { "search.filters.filter.subject.head": "Předmět",
"placeholder": "Jméno autora", "search.filters.filter.subject.placeholder": "Předmět",
"head": "Autor" "search.filters.head": "Filtry",
}, "search.filters.reset": "Obnovit filtry",
"scope": { "search.form.search": "Hledat",
"placeholder": "Filtr rozsahu", "search.form.search_dspace": "Hledat v DSpace",
"head": "Rozsah" "search.results.head": "Výsledky hledání",
}, "search.results.no-results": "Nebyli nalezeny žádné výsledky",
"subject": { "search.sidebar.close": "Zpět na výsledky",
"placeholder": "Předmět", "search.sidebar.filters.title": "Filtry",
"head": "Předmět" "search.sidebar.open": "Vyhledávací nástroje",
}, "search.sidebar.results": "výsledky",
"dateIssued": { "search.sidebar.settings.rpp": "Výsledků na stránku",
"max": { "search.sidebar.settings.sort-by": "Řadit dle",
"placeholder": "Datum od" "search.sidebar.settings.title": "Nastavení",
}, "search.title": "DSpace Angular :: Hledat",
"min": { "search.view-switch.show-grid": "Zobrazit mřížku",
"placeholder": "Datum do" "search.view-switch.show-list": "Zobrazit seznam",
}, "sorting.dc.title.ASC": "Název vzestupně",
"head": "Datum" "sorting.dc.title.DESC": "Název sestupně",
}, "sorting.score.DESC": "Relevance",
"has_content_in_original_bundle": { "title": "DSpace"
"head": "Má soubory"
}
}
}
},
"browse": {
"title": "Prohlížíte {{ collection }} dle {{ field }} {{ value }}"
},
"admin": {
"registries": {
"metadata": {
"title": "DSpace Angular :: Registr metadat",
"head": "Registr metadat",
"description": "Registr metadat je seznam všech metadatových polí dostupných v repozitáři. Tyto pole mohou být rozdělena do více schémat. DSpace však vyžaduje použití schématu kvalifikový Dublin Core.",
"schemas": {
"table": {
"id": "ID",
"namespace": "Jmenný prostor",
"name": "Název"
},
"no-items": "Žádná schémata metadat."
}
},
"schema": {
"title": "DSpace Angular :: Registr schémat metadat",
"head": "Metadata Schema",
"description": "Toto je schéma metadat pro „{{namespace}}“.",
"fields": {
"head": "Pole schématu metadat",
"table": {
"field": "Pole",
"scopenote": "Poznámka o rozsahu"
},
"no-items": "Žádná metadatová pole."
}
},
"bitstream-formats": {
"title": "DSpace Angular :: Registr formátů souborů",
"head": "Registr formátů souborů",
"description": "Tento seznam formátů souborů poskytuje informace o známých formátech a o úrovni jejich podpory.",
"formats": {
"table": {
"name": "Název",
"mimetype": "Typ MIME",
"supportLevel": {
"head": "Úroveň podpory",
"0": "Neznámá",
"1": "Známá",
"2": "Podpora"
},
"internal": "interní"
},
"no-items": "Žádné formáty souborů."
}
}
}
},
"loading": {
"default": "Načítá se...",
"top-level-communities": "Načítají se komunity nejvyšší úrovně...",
"community": "Načítá se komunita...",
"collection": "Načítá se kolekce...",
"sub-collections": "Načítají se subkolekce...",
"recent-submissions": "Načítají se poslední příspěvky...",
"item": "Načítá se záznam...",
"objects": "Načítá se...",
"search-results": "Načítají se výsledky hledání...",
"browse-by": "Načítají se záznamy..."
},
"error": {
"default": "Chyba",
"top-level-communities": "Chyba během stahování komunit nejvyšší úrovně",
"community": "Chyba během stahování komunity",
"collection": "Chyba během stahování kolekce",
"sub-collections": "Chyba během stahování subkolekcí",
"recent-submissions": "Chyba během stahování posledních příspěvků",
"item": "Chyba během stahování záznamu",
"objects": "Chyba během stahování objektů",
"search-results": "Chyba během stahování výsledků hledání",
"browse-by": "Chyba během stahování záznamů",
"validation": {
"pattern": "Tento vstup je omezen dle vzoru: {{ pattern }}.",
"license": {
"notgranted": "Pro dokončení zaslání Musíte udělit licenci. Pokud v tuto chvíli tuto licenci nemůžete udělit, můžete svou práci uložit a později se k svému příspěveku vrátit nebo jej smazat."
}
}
},
"form": {
"submit": "Odeslat",
"cancel": "Zrušit",
"search": "Hledat",
"remove": "Smazat",
"first-name": "Křestní jméno",
"last-name": "Příjmení",
"loading": "Načítá se...",
"no-results": "Nebyli nalezeny žádné výsledky",
"no-value": "Nebyla zadána hodnota",
"group-collapse": "Sbalit",
"group-expand": "Rozbalit",
"group-collapse-help": "Kliknutím sem sbalíte",
"group-expand-help": "Kliknutím sem rozbalíte a přidáte další prvky"
},
"login": {
"title": "Přihlásit se",
"form": {
"header": "Prosím, přihlaste se do DSpace",
"email": "E-mailová adresa",
"forgot-password": "Zapomněli jste své heslo?",
"new-user": "Nový uživatel? Zaregistrujte se kliknutím sem.",
"password": "Heslo",
"submit": "Přihlásit se"
}
},
"logout": {
"title": "Odhlásit se",
"form": {
"header": "Odhlásit se z DSpace",
"submit": "Odhlásit se"
}
},
"auth": {
"messages": {
"expired": "Vaše relace vypršela. Prosím, znova se přihlaste."
},
"errors": {
"invalid-user": "Neplatná e-mailová adresa nebo heslo."
}
}
} }

View File

@@ -1,277 +1,149 @@
{ {
"footer": { "404.help": "Die Seite, die Sie aufrufen wollten, konnte nicht gefunden werden. Sie könnte verschoben oder gelöscht worden sein. Mit dem Link unten kommen Sie zurück zur Startseite. ",
"copyright": "Copyright © 2002-{{ year }}", "404.link.home-page": "Zurück zur Startseite",
"link.dspace": "DSpace Software", "404.page-not-found": "Seite nicht gefunden",
"link.duraspace": "DuraSpace" "admin.registries.bitstream-formats.description": "Diese Liste enhtält die in diesem Repositorium zulässigen Dateiformate und den jeweiligen Unterstützungsgrad.",
}, "admin.registries.bitstream-formats.formats.no-items": "Es gibt keine Formate in dieser Referenzliste.",
"collection": { "admin.registries.bitstream-formats.formats.table.internal": "intern",
"page": { "admin.registries.bitstream-formats.formats.table.mimetype": "MIME Type",
"news": "Neuigkeiten", "admin.registries.bitstream-formats.formats.table.name": "Name",
"license": "Lizenz", "admin.registries.bitstream-formats.formats.table.supportLevel.0": "Unbekannt",
"browse": { "admin.registries.bitstream-formats.formats.table.supportLevel.1": "Bekannt",
"recent": { "admin.registries.bitstream-formats.formats.table.supportLevel.2": "Unterstützt",
"head": "Aktuellste Veröffentlichungen" "admin.registries.bitstream-formats.formats.table.supportLevel.head": "Unterstützungsgrad",
} "admin.registries.bitstream-formats.head": "Referenzliste der Dateiformate",
} "admin.registries.bitstream-formats.title": "DSpace Angular :: Referenzliste der Dateiformate",
} "admin.registries.metadata.description": "Die Metadatenreferenzliste beinhaltet alle Metadatenfelder, die zur Verfügung stehen. Die Felder können in unterschiedlichen Schemata enthalten sein. Nichtsdestotrotz benötigt DSpace mindestens qualifiziertes Dublin Core.",
}, "admin.registries.metadata.head": "Metadatenreferenzliste",
"community": { "admin.registries.metadata.schemas.no-items": "Es gbit keine Metadatenschemata.",
"page": { "admin.registries.metadata.schemas.table.id": "ID",
"news": "Neuigkeiten", "admin.registries.metadata.schemas.table.name": "Name",
"license": "Lizenz" "admin.registries.metadata.schemas.table.namespace": "Namensraum",
}, "admin.registries.metadata.title": "DSpace Angular :: Metadatenreferenzliste",
"sub-collection-list": { "admin.registries.schema.description": "Dies ist das Metadatenschema für \"{{namespace}}\".",
"head": "Sammlungen in diesem Bereich" "admin.registries.schema.fields.head": "Felder in diesem Schema",
} "admin.registries.schema.fields.no-items": "Es gibt keine Felder in diesem Schema.",
}, "admin.registries.schema.fields.table.field": "Feld",
"item": { "admin.registries.schema.fields.table.scopenote": "Gültigkeitsbereich",
"page": { "admin.registries.schema.head": "Metadatenschemata",
"author": "Autor", "admin.registries.schema.title": "DSpace Angular :: Referenzliste der Metadatenschemata",
"abstract": "Kurzfassung", "auth.errors.invalid-user": "Ungültige E-Mail-Adresse oder Passwort.",
"date": "Datum", "auth.messages.expired": "Ihre Sitzung ist abgelaufen, bitte melden Sie sich erneut an.",
"uri": "URI", "browse.title": "Anzeige {{ collection }} nach {{ field }} {{ value }}",
"files": "Dateien", "collection.page.browse.recent.head": "Aktuellste Veröffentlichungen",
"collections": "Sammlungen", "collection.page.license": "Lizenz",
"filesection": { "collection.page.news": "Neuigkeiten",
"download": "Herunterladen", "community.page.license": "Lizenz",
"name": "Name:", "community.page.news": "Neuigkeiten",
"format": "Format:", "community.sub-collection-list.head": "Sammlungen in diesem Bereich",
"size": "Größe:", "error.browse-by": "Fehler beim Laden der Ressourcen",
"description": "Beschreibung:" "error.collection": "Fehler beim Laden der Sammlung.",
}, "error.community": "Fehler beim Laden des Bereiches.",
"link": { "error.default": "Fehler",
"simple": "Kurzanzeige", "error.item": "Fehler beim Laden der Ressource.",
"full": "Vollanzeige" "error.objects": "Fehler beim Laden der Objekte.",
} "error.recent-submissions": "Fehler beim Laden der aktuellsten Veröffentlichungen.",
} "error.search-results": "Fehler beim Laden der Suchergebnisse.",
}, "error.sub-collections": "Fehler beim Laden der untergeordneten Sammlungen.",
"nav": { "error.top-level-communities": "Fehler beim Laden der Hauptbereiche.",
"home": "Zur Startseite", "error.validation.license.notgranted": "Sie müssen der Lizenz zustimmen, um die Ressource einzureichen. Wenn dies zur Zeit nicht geht, können Sie die Einreichung speichern und später wiederaufnehmen oder löschen.",
"login": "Anmelden", "error.validation.pattern": "Die Eingabe kann nur folgendes Muster haben: {{ pattern }}.",
"logout": "Abmelden" "footer.copyright": "Copyright © 2002-{{ year }}",
}, "footer.link.dspace": "DSpace Software",
"pagination": { "footer.link.duraspace": "DuraSpace",
"results-per-page": "Ergebnisse pro Seite", "form.cancel": "Abbrechen",
"sort-direction": "Sortiermöglichkeiten", "form.first-name": "Vorname",
"showing": { "form.group-collapse": "Weniger",
"label": "Anzeige der Treffer ", "form.group-collapse-help": "Hier klicken, um die Anzeige zu reduzieren",
"detail": "{{ range }} bis {{ total }}" "form.group-expand": "Mehr",
} "form.group-expand-help": "Hier klicken, um mehr Elemente anzuzeigen",
}, "form.last-name": "Nachname",
"sorting": { "form.loading": "Am Laden ...",
"score": { "form.no-results": "Keine Ergebnisse gefunden",
"DESC": "Relevanz" "form.no-value": "Kein Wert eingegeben",
}, "form.remove": "Löschen",
"dc.title": { "form.search": "Suchen",
"ASC": "Titel aufsteigend", "form.submit": "Los",
"DESC": "Titel absteigend" "home.description": "",
} "home.title": "DSpace Angular :: Startseite",
}, "home.top-level-communities.head": "Bereiche in DSpace",
"title": "DSpace", "home.top-level-communities.help": "Wählen Sie einen Bereich, um seine Sammlungen einzusehen.",
"404": { "item.page.abstract": "Kurzfassung",
"help": "Die Seite, die Sie aufrufen wollten, konnte nicht gefunden werden. Sie könnte verschoben oder gelöscht worden sein. Mit dem Link unten kommen Sie zurück zur Startseite. ", "item.page.author": "Autor",
"page-not-found": "Seite nicht gefunden", "item.page.collections": "Sammlungen",
"link": { "item.page.date": "Datum",
"home-page": "Zurück zur Startseite" "item.page.files": "Dateien",
} "item.page.filesection.description": "Beschreibung:",
}, "item.page.filesection.download": "Herunterladen",
"home": { "item.page.filesection.format": "Format:",
"title": "DSpace Angular :: Startseite", "item.page.filesection.name": "Name:",
"description": "", "item.page.filesection.size": "Größe:",
"top-level-communities": { "item.page.link.full": "Vollanzeige",
"head": "Bereiche in DSpace", "item.page.link.simple": "Kurzanzeige",
"help": "Wählen Sie einen Bereich, um seine Sammlungen einzusehen." "item.page.uri": "URI",
} "loading.browse-by": "Die Ressourcen werden geladen ...",
}, "loading.collection": "Die Sammlung wird geladen ...",
"search": { "loading.community": "Der Bereich wird geladen ...",
"title": "DSpace Angular :: Suche", "loading.default": "Am Laden ...",
"description": "", "loading.item": "Die Ressource wird geladen ...",
"form": { "loading.objects": "Am Laden ...",
"search": "Suche", "loading.recent-submissions": "Die aktuellsten Veröffentlichungen werden geladen ...",
"search_dspace": "DSpace durchsuchen" "loading.search-results": "Die Suchergebnisse werden geladen ...",
}, "loading.sub-collections": "Die untergeordneten Sammlungen werden geladen ...",
"results": { "loading.top-level-communities": "Die Hauptbereiche werden geladen ...",
"head": "Suchergebnisse", "login.form.email": "E-Mail-Adresse",
"no-results": "Zu dieser Suche gibt es keine Treffer." "login.form.forgot-password": "Haben Sie Ihr Passwort vergessen?",
}, "login.form.header": "Bitte Loggen Sie sich ein.",
"sidebar": { "login.form.new-user": "Sind Sie neu hier? Klicken Sie hier, um sich zu registrieren.",
"close": "Zurück zu den Ergebnissen", "login.form.password": "Passwort",
"open": "Suchwerkzeuge", "login.form.submit": "Einloggen",
"results": "Ergebnisse", "login.title": "Einloggen",
"filters": { "logout.form.header": "Ausloggen aus DSpace",
"title": "Filter" "logout.form.submit": "Ausloggen",
}, "logout.title": "Ausloggen",
"settings": { "nav.home": "Zur Startseite",
"title": "Einstellungen", "nav.login": "Anmelden",
"sort-by": "Sortiere nach", "nav.logout": "Abmelden",
"rpp": "Treffer pro Seite" "pagination.results-per-page": "Ergebnisse pro Seite",
} "pagination.showing.detail": "{{ range }} bis {{ total }}",
}, "pagination.showing.label": "Anzeige der Treffer ",
"view-switch": { "pagination.sort-direction": "Sortiermöglichkeiten",
"show-list": "Zeige als Liste", "search.description": "",
"show-grid": "Zeige als Raster" "search.filters.applied.f.author": "Autor",
}, "search.filters.applied.f.dateIssued.max": "Enddatum",
"filters": { "search.filters.applied.f.dateIssued.min": "Anfangsdatum",
"head": "Filter", "search.filters.applied.f.has_content_in_original_bundle": "Besitzt Dateien",
"reset": "Filter zurücksetzen", "search.filters.applied.f.subject": "Thema",
"applied": { "search.filters.filter.author.head": "Autor",
"f.author": "Autor", "search.filters.filter.author.placeholder": "Autor",
"f.dateIssued.min": "Anfangsdatum", "search.filters.filter.dateIssued.head": "Datum",
"f.dateIssued.max": "Enddatum", "search.filters.filter.dateIssued.max.placeholder": "Frühestes Datum",
"f.subject": "Thema", "search.filters.filter.dateIssued.min.placeholder": "Ältestes Datum",
"f.has_content_in_original_bundle": "Besitzt Dateien" "search.filters.filter.has_content_in_original_bundle.head": "Besitzt Dateien",
}, "search.filters.filter.scope.head": "Bereich",
"filter": { "search.filters.filter.scope.placeholder": "Bereichsfilter",
"show-more": "Zeige mehr", "search.filters.filter.show-less": "Zeige weniger",
"show-less": "Zeige weniger", "search.filters.filter.show-more": "Zeige mehr",
"author": { "search.filters.filter.subject.head": "Schlagwort",
"placeholder": "Autor", "search.filters.filter.subject.placeholder": "Schlagwort",
"head": "Autor" "search.filters.head": "Filter",
}, "search.filters.reset": "Filter zurücksetzen",
"scope": { "search.form.search": "Suche",
"placeholder": "Bereichsfilter", "search.form.search_dspace": "DSpace durchsuchen",
"head": "Bereich" "search.results.head": "Suchergebnisse",
}, "search.results.no-results": "Zu dieser Suche gibt es keine Treffer.",
"subject": { "search.sidebar.close": "Zurück zu den Ergebnissen",
"placeholder": "Schlagwort", "search.sidebar.filters.title": "Filter",
"head": "Schlagwort" "search.sidebar.open": "Suchwerkzeuge",
}, "search.sidebar.results": "Ergebnisse",
"dateIssued": { "search.sidebar.settings.rpp": "Treffer pro Seite",
"max": { "search.sidebar.settings.sort-by": "Sortiere nach",
"placeholder": "Frühestes Datum" "search.sidebar.settings.title": "Einstellungen",
}, "search.title": "DSpace Angular :: Suche",
"min": { "search.view-switch.show-grid": "Zeige als Raster",
"placeholder": "Ältestes Datum" "search.view-switch.show-list": "Zeige als Liste",
}, "sorting.dc.title.ASC": "Titel aufsteigend",
"head": "Datum" "sorting.dc.title.DESC": "Titel absteigend",
}, "sorting.score.DESC": "Relevanz",
"has_content_in_original_bundle": { "title": "DSpace"
"head": "Besitzt Dateien"
}
}
}
},
"browse": {
"title": "Anzeige {{ collection }} nach {{ field }} {{ value }}"
},
"admin": {
"registries": {
"metadata": {
"title": "DSpace Angular :: Metadatenreferenzliste",
"head": "Metadatenreferenzliste",
"description": "Die Metadatenreferenzliste beinhaltet alle Metadatenfelder, die zur Verfügung stehen. Die Felder können in unterschiedlichen Schemata enthalten sein. Nichtsdestotrotz benötigt DSpace mindestens qualifiziertes Dublin Core.",
"schemas": {
"table": {
"id": "ID",
"namespace": "Namensraum",
"name": "Name"
},
"no-items": "Es gbit keine Metadatenschemata."
}
},
"schema": {
"title": "DSpace Angular :: Referenzliste der Metadatenschemata",
"head": "Metadatenschemata",
"description": "Dies ist das Metadatenschema für \"{{namespace}}\".",
"fields": {
"head": "Felder in diesem Schema",
"table": {
"field": "Feld",
"scopenote": "Gültigkeitsbereich"
},
"no-items": "Es gibt keine Felder in diesem Schema."
}
},
"bitstream-formats": {
"title": "DSpace Angular :: Referenzliste der Dateiformate",
"head": "Referenzliste der Dateiformate",
"description": "Diese Liste enhtält die in diesem Repositorium zulässigen Dateiformate und den jeweiligen Unterstützungsgrad.",
"formats": {
"table": {
"name": "Name",
"mimetype": "MIME Type",
"supportLevel": {
"head": "Unterstützungsgrad",
"0": "Unbekannt",
"1": "Bekannt",
"2": "Unterstützt"
},
"internal": "intern"
},
"no-items": "Es gibt keine Formate in dieser Referenzliste."
}
}
}
},
"loading": {
"default": "Am Laden ...",
"top-level-communities": "Die Hauptbereiche werden geladen ...",
"community": "Der Bereich wird geladen ...",
"collection": "Die Sammlung wird geladen ...",
"sub-collections": "Die untergeordneten Sammlungen werden geladen ...",
"recent-submissions": "Die aktuellsten Veröffentlichungen werden geladen ...",
"item": "Die Ressource wird geladen ...",
"objects": "Am Laden ...",
"search-results": "Die Suchergebnisse werden geladen ...",
"browse-by": "Die Ressourcen werden geladen ..."
},
"error": {
"default": "Fehler",
"top-level-communities": "Fehler beim Laden der Hauptbereiche.",
"community": "Fehler beim Laden des Bereiches.",
"collection": "Fehler beim Laden der Sammlung.",
"sub-collections": "Fehler beim Laden der untergeordneten Sammlungen.",
"recent-submissions": "Fehler beim Laden der aktuellsten Veröffentlichungen.",
"item": "Fehler beim Laden der Ressource.",
"objects": "Fehler beim Laden der Objekte.",
"search-results": "Fehler beim Laden der Suchergebnisse.",
"browse-by": "Fehler beim Laden der Ressourcen",
"validation": {
"pattern": "Die Eingabe kann nur folgendes Muster haben: {{ pattern }}.",
"license": {
"notgranted": "Sie müssen der Lizenz zustimmen, um die Ressource einzureichen. Wenn dies zur Zeit nicht geht, können Sie die Einreichung speichern und später wiederaufnehmen oder löschen."
}
}
},
"form": {
"submit": "Los",
"cancel": "Abbrechen",
"search": "Suchen",
"remove": "Löschen",
"first-name": "Vorname",
"last-name": "Nachname",
"loading": "Am Laden ...",
"no-results": "Keine Ergebnisse gefunden",
"no-value": "Kein Wert eingegeben",
"group-collapse": "Weniger",
"group-expand": "Mehr",
"group-collapse-help": "Hier klicken, um die Anzeige zu reduzieren",
"group-expand-help": "Hier klicken, um mehr Elemente anzuzeigen"
},
"login": {
"title": "Einloggen",
"form": {
"header": "Bitte Loggen Sie sich ein.",
"email": "E-Mail-Adresse",
"forgot-password": "Haben Sie Ihr Passwort vergessen?",
"new-user": "Sind Sie neu hier? Klicken Sie hier, um sich zu registrieren.",
"password": "Passwort",
"submit": "Einloggen"
}
},
"logout": {
"title": "Ausloggen",
"form": {
"header": "Ausloggen aus DSpace",
"submit": "Ausloggen"
}
},
"auth": {
"messages": {
"expired": "Ihre Sitzung ist abgelaufen, bitte melden Sie sich erneut an."
},
"errors": {
"invalid-user": "Ungültige E-Mail-Adresse oder Passwort."
}
}
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,277 +1,149 @@
{ {
"footer": { "404.help": "De pagina die u zoekt kan niet gevonden worden. De pagina werd mogelijk verplaatst of verwijderd. U kan onderstaande knop gebruiken om terug naar de homepagina te gaan. ",
"copyright": "copyright © 2002-{{ year }}", "404.link.home-page": "Terug naar de homepagina",
"link.dspace": "DSpace software", "404.page-not-found": "Pagina niet gevonden",
"link.duraspace": "DuraSpace" "admin.registries.bitstream-formats.description": "Deze lijst van Bitstream formaten biedt informatie over de formaten die in deze repository zijn toegelaten en op welke manier ze ondersteund worden. De term Bitstream wordt in DSpace gebruikt om een bestand aan te duiden dat samen met metadata onderdeel uitmaakt van een item. De naam bitstream duidt op het feit dat het bestand achterliggend wordt opgeslaan zonder bestandsextensie.",
}, "admin.registries.bitstream-formats.formats.no-items": "Er kunnen geen bitstreamformaten getoond worden.",
"collection": { "admin.registries.bitstream-formats.formats.table.internal": "intern",
"page": { "admin.registries.bitstream-formats.formats.table.mimetype": "MIME Type",
"news": "Nieuws", "admin.registries.bitstream-formats.formats.table.name": "Naam",
"license": "Licentie", "admin.registries.bitstream-formats.formats.table.supportLevel.0": "Onbekend",
"browse": { "admin.registries.bitstream-formats.formats.table.supportLevel.1": "Gekend",
"recent": { "admin.registries.bitstream-formats.formats.table.supportLevel.2": "Ondersteund",
"head": "Recent toegevoegd" "admin.registries.bitstream-formats.formats.table.supportLevel.head": "Ondersteuning",
} "admin.registries.bitstream-formats.head": "Bitstream Formaat Register",
} "admin.registries.bitstream-formats.title": "DSpace Angular :: Bitstream Formaat Register",
} "admin.registries.metadata.description": "Het metadataregister omvat de lijst van alle metadatavelden die beschikbaar zijn in het systeem. Deze velden kunnen verspreid zijn over verschillende metadataschema's. Het qualified Dublin Core schema (dc) is een verplicht schema en kan niet worden verwijderd.",
}, "admin.registries.metadata.head": "Metadata Register",
"community": { "admin.registries.metadata.schemas.no-items": "Er kunnen geen metadataschema's getoond worden.",
"page": { "admin.registries.metadata.schemas.table.id": "ID",
"news": "Nieuws", "admin.registries.metadata.schemas.table.name": "Naam",
"license": "Licentie" "admin.registries.metadata.schemas.table.namespace": "Naamruimte",
}, "admin.registries.metadata.title": "DSpace Angular :: Metadata Register",
"sub-collection-list": { "admin.registries.schema.description": "Dit is het metadataschema voor \"{{namespace}}\".",
"head": "Collecties in deze Community" "admin.registries.schema.fields.head": "Schema metadatavelden",
} "admin.registries.schema.fields.no-items": "Er kunnen geen metadatavelden getoond worden.",
}, "admin.registries.schema.fields.table.field": "Veld",
"item": { "admin.registries.schema.fields.table.scopenote": "Opmerking over bereik",
"page": { "admin.registries.schema.head": "Metadata Schema",
"author": "Auteur", "admin.registries.schema.title": "DSpace Angular :: Metadata Schema Register",
"abstract": "Abstract", "auth.errors.invalid-user": "Ongeldig e-mailadres of wachtwoord.",
"date": "Datum", "auth.messages.expired": "Uw sessie is vervallen. Gelieve opnieuw aan te melden.",
"uri": "URI", "browse.title": "Verken {{ collection }} volgens {{ field }} {{ value }}",
"files": "Bestanden", "collection.page.browse.recent.head": "Recent toegevoegd",
"collections": "Collecties", "collection.page.license": "Licentie",
"filesection": { "collection.page.news": "Nieuws",
"download": "Download", "community.page.license": "Licentie",
"name": "Naam:", "community.page.news": "Nieuws",
"format": "Formaat:", "community.sub-collection-list.head": "Collecties in deze Community",
"size": "Grootte:", "error.browse-by": "Fout bij het ophalen van items",
"description": "Beschrijving:" "error.collection": "Fout bij het ophalen van een collectie",
}, "error.community": "Fout bij het ophalen van een community",
"link": { "error.default": "Fout",
"simple": "Eenvoudige itemweergave", "error.item": "Fout bij het ophalen van items",
"full": "Volledige itemweergave" "error.objects": "Fout bij het ophalen van objecten",
} "error.recent-submissions": "Fout bij het ophalen van recent toegevoegde items",
} "error.search-results": "Fout bij het ophalen van zoekresultaten",
}, "error.sub-collections": "Fout bij het ophalen van sub-collecties",
"nav": { "error.top-level-communities": "Fout bij het inladen van communities op het hoogste niveau",
"home": "Home", "error.validation.license.notgranted": "U moet de invoerlicentie goedkeuren om de invoer af te werken. Indien u deze licentie momenteel niet kan of mag goedkeuren, kan u uw werk opslaan en de invoer later afwerken. U kunt dit nieuwe item ook verwijderen indien u niet voldoet aan de vereisten van de invoerlicentie.",
"login": "Log In", "error.validation.pattern": "Deze invoer is niet toegelaten volgens dit patroon: {{ pattern }}.",
"logout": "Log Uit" "footer.copyright": "copyright © 2002-{{ year }}",
}, "footer.link.dspace": "DSpace software",
"pagination": { "footer.link.duraspace": "DuraSpace",
"results-per-page": "Resultaten per pagina", "form.cancel": "Annuleer",
"sort-direction": "Sorteermogelijkheden", "form.first-name": "Voornaam",
"showing": { "form.group-collapse": "Inklappen",
"label": "Resultaten ", "form.group-collapse-help": "Klik hier op in te klappen",
"detail": "{{ range }} van {{ total }}" "form.group-expand": "Uitklappen",
} "form.group-expand-help": "Klik hier om uit te klappen en om meer onderdelen toe te voegen",
}, "form.last-name": "Achternaam",
"sorting": { "form.loading": "Inladen...",
"score": { "form.no-results": "Geen resultaten gevonden",
"DESC": "Relevantie" "form.no-value": "Geen waarde ingevoerd",
}, "form.remove": "Verwijder",
"dc.title": { "form.search": "Zoek",
"ASC": "Oplopend op titel", "form.submit": "Verstuur",
"DESC": "Aflopend op titel" "home.description": "",
} "home.title": "DSpace Angular :: Home",
}, "home.top-level-communities.head": "Communities in DSpace",
"title": "DSpace", "home.top-level-communities.help": "Selecteer een community om diens collecties te verkennen.",
"404": { "item.page.abstract": "Abstract",
"help": "De pagina die u zoekt kan niet gevonden worden. De pagina werd mogelijk verplaatst of verwijderd. U kan onderstaande knop gebruiken om terug naar de homepagina te gaan. ", "item.page.author": "Auteur",
"page-not-found": "Pagina niet gevonden", "item.page.collections": "Collecties",
"link": { "item.page.date": "Datum",
"home-page": "Terug naar de homepagina" "item.page.files": "Bestanden",
} "item.page.filesection.description": "Beschrijving:",
}, "item.page.filesection.download": "Download",
"home": { "item.page.filesection.format": "Formaat:",
"title": "DSpace Angular :: Home", "item.page.filesection.name": "Naam:",
"description": "", "item.page.filesection.size": "Grootte:",
"top-level-communities": { "item.page.link.full": "Volledige itemweergave",
"head": "Communities in DSpace", "item.page.link.simple": "Eenvoudige itemweergave",
"help": "Selecteer een community om diens collecties te verkennen." "item.page.uri": "URI",
} "loading.browse-by": "Items worden ingeladen...",
}, "loading.collection": "Collectie wordt ingeladen...",
"search": { "loading.community": "Community wordt ingeladen...",
"title": "DSpace Angular :: Zoek", "loading.default": "Laden...",
"description": "", "loading.item": "Item wordt ingeladen...",
"form": { "loading.objects": "Laden...",
"search": "Zoek", "loading.recent-submissions": "Recent toegevoegde items worden ingeladen...",
"search_dspace": "Zoek in DSpace" "loading.search-results": "Zoekresultaten worden ingeladen...",
}, "loading.sub-collections": "De sub-collecties worden ingeladen...",
"results": { "loading.top-level-communities": "Inladen van de Communities op het hoogste niveau...",
"head": "Zoekresultaten", "login.form.email": "Email adres",
"no-results": "Er waren geen resultaten voor deze zoekopdracht" "login.form.forgot-password": "Bent u uw wachtwoord vergeten?",
}, "login.form.header": "Gelieve in te loggen in DSpace",
"sidebar": { "login.form.new-user": "Nieuwe gebruiker? Gelieve u hier te registreren",
"close": "Terug naar de resultaten", "login.form.password": "Wachtwoord",
"open": "Zoek Tools", "login.form.submit": "Aanmelden",
"results": "resultaten", "login.title": "Aanmelden",
"filters": { "logout.form.header": "Afmelden in DSpace",
"title": "Filters" "logout.form.submit": "Afmelden",
}, "logout.title": "Afmelden",
"settings": { "nav.home": "Home",
"title": "Instellingen", "nav.login": "Log In",
"sort-by": "Sorteer volgens", "nav.logout": "Log Uit",
"rpp": "Resultaten per pagina" "pagination.results-per-page": "Resultaten per pagina",
} "pagination.showing.detail": "{{ range }} van {{ total }}",
}, "pagination.showing.label": "Resultaten ",
"view-switch": { "pagination.sort-direction": "Sorteermogelijkheden",
"show-list": "Toon als lijst", "search.description": "",
"show-grid": "Toon in raster" "search.filters.applied.f.author": "Auteur",
}, "search.filters.applied.f.dateIssued.max": "Einddatum",
"filters": { "search.filters.applied.f.dateIssued.min": "Startdatum",
"head": "Filters", "search.filters.applied.f.has_content_in_original_bundle": "Heeft bestanden",
"reset": "Filters verwijderen", "search.filters.applied.f.subject": "Sleutelwoord",
"applied": { "search.filters.filter.author.head": "Auteur",
"f.author": "Auteur", "search.filters.filter.author.placeholder": "Auteursnaam",
"f.dateIssued.min": "Startdatum", "search.filters.filter.dateIssued.head": "Datum",
"f.dateIssued.max": "Einddatum", "search.filters.filter.dateIssued.max.placeholder": "Vroegste Datum",
"f.subject": "Sleutelwoord", "search.filters.filter.dateIssued.min.placeholder": "Laatste Datum",
"f.has_content_in_original_bundle": "Heeft bestanden" "search.filters.filter.has_content_in_original_bundle.head": "Heeft bestanden",
}, "search.filters.filter.scope.head": "Bereik",
"filter": { "search.filters.filter.scope.placeholder": "Bereikfilter",
"show-more": "Toon meer", "search.filters.filter.show-less": "Inklappen",
"show-less": "Inklappen", "search.filters.filter.show-more": "Toon meer",
"author": { "search.filters.filter.subject.head": "Onderwerp",
"placeholder": "Auteursnaam", "search.filters.filter.subject.placeholder": "Onderwerp",
"head": "Auteur" "search.filters.head": "Filters",
}, "search.filters.reset": "Filters verwijderen",
"scope": { "search.form.search": "Zoek",
"placeholder": "Bereikfilter", "search.form.search_dspace": "Zoek in DSpace",
"head": "Bereik" "search.results.head": "Zoekresultaten",
}, "search.results.no-results": "Er waren geen resultaten voor deze zoekopdracht",
"subject": { "search.sidebar.close": "Terug naar de resultaten",
"placeholder": "Onderwerp", "search.sidebar.filters.title": "Filters",
"head": "Onderwerp" "search.sidebar.open": "Zoek Tools",
}, "search.sidebar.results": "resultaten",
"dateIssued": { "search.sidebar.settings.rpp": "Resultaten per pagina",
"max": { "search.sidebar.settings.sort-by": "Sorteer volgens",
"placeholder": "Vroegste Datum" "search.sidebar.settings.title": "Instellingen",
}, "search.title": "DSpace Angular :: Zoek",
"min": { "search.view-switch.show-grid": "Toon in raster",
"placeholder": "Laatste Datum" "search.view-switch.show-list": "Toon als lijst",
}, "sorting.dc.title.ASC": "Oplopend op titel",
"head": "Datum" "sorting.dc.title.DESC": "Aflopend op titel",
}, "sorting.score.DESC": "Relevantie",
"has_content_in_original_bundle": { "title": "DSpace"
"head": "Heeft bestanden"
}
}
}
},
"browse": {
"title": "Verken {{ collection }} volgens {{ field }} {{ value }}"
},
"admin": {
"registries": {
"metadata": {
"title": "DSpace Angular :: Metadata Register",
"head": "Metadata Register",
"description": "Het metadataregister omvat de lijst van alle metadatavelden die beschikbaar zijn in het systeem. Deze velden kunnen verspreid zijn over verschillende metadataschema's. Het qualified Dublin Core schema (dc) is een verplicht schema en kan niet worden verwijderd.",
"schemas": {
"table": {
"id": "ID",
"namespace": "Naamruimte",
"name": "Naam"
},
"no-items": "Er kunnen geen metadataschema's getoond worden."
}
},
"schema": {
"title": "DSpace Angular :: Metadata Schema Register",
"head": "Metadata Schema",
"description": "Dit is het metadataschema voor \"{{namespace}}\".",
"fields": {
"head": "Schema metadatavelden",
"table": {
"field": "Veld",
"scopenote": "Opmerking over bereik"
},
"no-items": "Er kunnen geen metadatavelden getoond worden."
}
},
"bitstream-formats": {
"title": "DSpace Angular :: Bitstream Formaat Register",
"head": "Bitstream Formaat Register",
"description": "Deze lijst van Bitstream formaten biedt informatie over de formaten die in deze repository zijn toegelaten en op welke manier ze ondersteund worden. De term Bitstream wordt in DSpace gebruikt om een bestand aan te duiden dat samen met metadata onderdeel uitmaakt van een item. De naam bitstream duidt op het feit dat het bestand achterliggend wordt opgeslaan zonder bestandsextensie.",
"formats": {
"table": {
"name": "Naam",
"mimetype": "MIME Type",
"supportLevel": {
"head": "Ondersteuning",
"0": "Onbekend",
"1": "Gekend",
"2": "Ondersteund"
},
"internal": "intern"
},
"no-items": "Er kunnen geen bitstreamformaten getoond worden."
}
}
}
},
"loading": {
"default": "Laden...",
"top-level-communities": "Inladen van de Communities op het hoogste niveau...",
"community": "Community wordt ingeladen...",
"collection": "Collectie wordt ingeladen...",
"sub-collections": "De sub-collecties worden ingeladen...",
"recent-submissions": "Recent toegevoegde items worden ingeladen...",
"item": "Item wordt ingeladen...",
"objects": "Laden...",
"search-results": "Zoekresultaten worden ingeladen...",
"browse-by": "Items worden ingeladen..."
},
"error": {
"default": "Fout",
"top-level-communities": "Fout bij het inladen van communities op het hoogste niveau",
"community": "Fout bij het ophalen van een community",
"collection": "Fout bij het ophalen van een collectie",
"sub-collections": "Fout bij het ophalen van sub-collecties",
"recent-submissions": "Fout bij het ophalen van recent toegevoegde items",
"item": "Fout bij het ophalen van items",
"objects": "Fout bij het ophalen van objecten",
"search-results": "Fout bij het ophalen van zoekresultaten",
"browse-by": "Fout bij het ophalen van items",
"validation": {
"pattern": "Deze invoer is niet toegelaten volgens dit patroon: {{ pattern }}.",
"license": {
"notgranted": "U moet de invoerlicentie goedkeuren om de invoer af te werken. Indien u deze licentie momenteel niet kan of mag goedkeuren, kan u uw werk opslaan en de invoer later afwerken. U kunt dit nieuwe item ook verwijderen indien u niet voldoet aan de vereisten van de invoerlicentie."
}
}
},
"form": {
"submit": "Verstuur",
"cancel": "Annuleer",
"search": "Zoek",
"remove": "Verwijder",
"first-name": "Voornaam",
"last-name": "Achternaam",
"loading": "Inladen...",
"no-results": "Geen resultaten gevonden",
"no-value": "Geen waarde ingevoerd",
"group-collapse": "Inklappen",
"group-expand": "Uitklappen",
"group-collapse-help": "Klik hier op in te klappen",
"group-expand-help": "Klik hier om uit te klappen en om meer onderdelen toe te voegen"
},
"login": {
"title": "Aanmelden",
"form": {
"header": "Gelieve in te loggen in DSpace",
"email": "Email adres",
"forgot-password": "Bent u uw wachtwoord vergeten?",
"new-user": "Nieuwe gebruiker? Gelieve u hier te registreren",
"password": "Wachtwoord",
"submit": "Aanmelden"
}
},
"logout": {
"title": "Afmelden",
"form": {
"header": "Afmelden in DSpace",
"submit": "Afmelden"
}
},
"auth": {
"messages": {
"expired": "Uw sessie is vervallen. Gelieve opnieuw aan te melden."
},
"errors": {
"invalid-user": "Ongeldig e-mailadres of wachtwoord."
}
}
} }

BIN
resources/images/banner.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

View File

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

After

Width:  |  Height:  |  Size: 3.9 KiB

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

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

View File

@@ -13,6 +13,7 @@ import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { EnumKeysPipe } from '../../../shared/utils/enum-keys-pipe'; import { EnumKeysPipe } from '../../../shared/utils/enum-keys-pipe';
import { HostWindowService } from '../../../shared/host-window.service'; import { HostWindowService } from '../../../shared/host-window.service';
import { HostWindowServiceStub } from '../../../shared/testing/host-window-service-stub'; import { HostWindowServiceStub } from '../../../shared/testing/host-window-service-stub';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/testing/utils';
describe('BitstreamFormatsComponent', () => { describe('BitstreamFormatsComponent', () => {
let comp: BitstreamFormatsComponent; let comp: BitstreamFormatsComponent;
@@ -52,7 +53,7 @@ describe('BitstreamFormatsComponent', () => {
extensions: null extensions: null
} }
]; ];
const mockFormats = observableOf(new RemoteData(false, false, true, undefined, new PaginatedList(null, mockFormatsList))); const mockFormats = createSuccessfulRemoteDataObject$(new PaginatedList(null, mockFormatsList));
const registryServiceStub = { const registryServiceStub = {
getBitstreamFormats: () => mockFormats getBitstreamFormats: () => mockFormats
}; };

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,15 +1,13 @@
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 { getRelatedItemsByTypeLabel } from '../shared/item-relationships-utils';
@rendersItemType('Publication', ItemViewMode.Full) @rendersItemType('Publication', ItemViewMode.Full)
@rendersItemType(DEFAULT_ITEM_TYPE, ItemViewMode.Full) @rendersItemType(DEFAULT_ITEM_TYPE, ItemViewMode.Full)
@@ -40,33 +38,23 @@ 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'), getRelatedItemsByTypeLabel(this.item.id, 'isProjectOfPublication')
relationsToItems(this.item.id, this.ids)
); );
this.orgUnits$ = this.resolvedRelsAndTypes$.pipe( this.orgUnits$ = this.resolvedRelsAndTypes$.pipe(
filterRelationsByTypeLabel('isOrgUnitOfPublication'), getRelatedItemsByTypeLabel(this.item.id, 'isOrgUnitOfPublication')
relationsToItems(this.item.id, this.ids)
); );
this.journalIssues$ = this.resolvedRelsAndTypes$.pipe( this.journalIssues$ = this.resolvedRelsAndTypes$.pipe(
filterRelationsByTypeLabel('isJournalIssueOfPublication'), getRelatedItemsByTypeLabel(this.item.id, 'isJournalIssueOfPublication')
relationsToItems(this.item.id, this.ids)
); );
} }

View File

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

View File

@@ -26,6 +26,7 @@ import { MetadatumRepresentation } from '../../../../core/shared/metadata-repres
import { ItemMetadataRepresentation } from '../../../../core/shared/metadata-representation/item/item-metadata-representation.model'; import { ItemMetadataRepresentation } from '../../../../core/shared/metadata-representation/item/item-metadata-representation.model';
import { MetadataMap, MetadataValue } from '../../../../core/shared/metadata.models'; import { MetadataMap, MetadataValue } from '../../../../core/shared/metadata.models';
import { compareArraysUsing, compareArraysUsingIds } from './item-relationships-utils'; import { compareArraysUsing, compareArraysUsingIds } from './item-relationships-utils';
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils';
/** /**
* Create a generic test for an item-page-fields component using a mockItem and the type of component * Create a generic test for an item-page-fields component using a mockItem and the type of component
@@ -102,11 +103,13 @@ export function containsFieldInput(fields: DebugElement[], metadataKey: string):
} }
export function createRelationshipsObservable() { export function createRelationshipsObservable() {
return observableOf(new RemoteData(false, false, true, null, new PaginatedList(new PageInfo(), [ return createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [
Object.assign(new Relationship(), { Object.assign(new Relationship(), {
relationshipType: observableOf(new RemoteData(false, false, true, null, new RelationshipType())) relationshipType: createSuccessfulRemoteDataObject$(new RelationshipType()),
leftItem: createSuccessfulRemoteDataObject$(new Item()),
rightItem: createSuccessfulRemoteDataObject$(new Item())
}) })
]))); ]));
} }
describe('ItemComponent', () => { describe('ItemComponent', () => {
const arr1 = [ const arr1 = [
@@ -319,20 +322,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: observableOf(new RemoteData(false, false, true, null, new PaginatedList(new PageInfo(), [
Object.assign(new Relationship(), {
uuid: '123',
id: '123',
leftId: '1',
rightId: '2',
relationshipType: observableOf(new RemoteData(false, false, true, null, 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',
@@ -353,21 +367,10 @@ 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) {
return observableOf(new RemoteData(false, false, true, null, relatedItem)) return createSuccessfulRemoteDataObject$(relatedItem)
} }
} }
}) as ItemDataService; }) as ItemDataService;
@@ -397,7 +400,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', () => {

View File

@@ -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)
); );
} }

View File

@@ -1,6 +1,6 @@
<ds-filtered-search-page <ds-filtered-search-page
[fixedFilterQuery]="fixedFilter" [fixedFilterQuery]="fixedFilter"
[fixedFilter$]="fixedFilter$" [configuration$]="configuration$"
[searchEnabled]="searchEnabled" [searchEnabled]="searchEnabled"
[sideBarWidth]="sideBarWidth"> [sideBarWidth]="sideBarWidth">
</ds-filtered-search-page> </ds-filtered-search-page>

View File

@@ -47,9 +47,9 @@ describe('RelatedEntitiesSearchComponent', () => {
expect(comp.fixedFilter).toEqual(mockFilter); expect(comp.fixedFilter).toEqual(mockFilter);
}); });
it('should create a fixedFilter$', () => { it('should create a configuration$', () => {
comp.fixedFilter$.subscribe((fixedFilter) => { comp.configuration$.subscribe((configuration) => {
expect(fixedFilter).toEqual(mockRelationEntityType); expect(configuration).toEqual(mockRelationEntityType);
}) })
}); });

View File

@@ -47,7 +47,7 @@ export class RelatedEntitiesSearchComponent implements OnInit {
@Input() sideBarWidth = 4; @Input() sideBarWidth = 4;
fixedFilter: string; fixedFilter: string;
fixedFilter$: Observable<string>; configuration$: Observable<string>;
constructor(private fixedFilterService: SearchFixedFilterService) { constructor(private fixedFilterService: SearchFixedFilterService) {
} }
@@ -57,7 +57,7 @@ export class RelatedEntitiesSearchComponent implements OnInit {
this.fixedFilter = this.fixedFilterService.getFilterByRelation(this.relationType, this.item.id); this.fixedFilter = this.fixedFilterService.getFilterByRelation(this.relationType, this.item.id);
} }
if (isNotEmpty(this.relationEntityType)) { if (isNotEmpty(this.relationEntityType)) {
this.fixedFilter$ = of(this.relationEntityType); this.configuration$ = of(this.relationEntityType);
} }
} }

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,21 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { configureSearchComponentTestingModule } from './search-page.component.spec';
import { SearchConfigurationService } from './search-service/search-configuration.service';
import { ConfigurationSearchPageComponent } from './configuration-search-page.component';
describe('ConfigurationSearchPageComponent', () => {
let comp: ConfigurationSearchPageComponent;
let fixture: ComponentFixture<ConfigurationSearchPageComponent>;
let searchConfigService: SearchConfigurationService;
beforeEach(async(() => {
configureSearchComponentTestingModule(ConfigurationSearchPageComponent);
}));
beforeEach(() => {
fixture = TestBed.createComponent(ConfigurationSearchPageComponent);
comp = fixture.componentInstance;
searchConfigService = (comp as any).searchConfigService;
fixture.detectChanges();
});
});

View File

@@ -0,0 +1,71 @@
import { HostWindowService } from '../shared/host-window.service';
import { SearchService } from './search-service/search.service';
import { SearchSidebarService } from './search-sidebar/search-sidebar.service';
import { SearchPageComponent } from './search-page.component';
import { ChangeDetectionStrategy, Component, Inject, Input, OnInit } from '@angular/core';
import { pushInOut } from '../shared/animations/push';
import { RouteService } from '../shared/services/route.service';
import { SearchConfigurationService } from './search-service/search-configuration.service';
import { Observable } from 'rxjs';
import { PaginatedSearchOptions } from './paginated-search-options.model';
import { SEARCH_CONFIG_SERVICE } from '../+my-dspace-page/my-dspace-page.component';
import { map } from 'rxjs/operators';
/**
* This component renders a search page using a configuration as input.
*/
@Component({
selector: 'ds-configuration-search-page',
styleUrls: ['./search-page.component.scss'],
templateUrl: './search-page.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
animations: [pushInOut],
providers: [
{
provide: SEARCH_CONFIG_SERVICE,
useClass: SearchConfigurationService
}
]
})
export class ConfigurationSearchPageComponent extends SearchPageComponent implements OnInit {
/**
* The configuration to use for the search options
* If empty, the configuration will be determined by the route parameter called 'configuration'
*/
@Input() configuration: string;
constructor(protected service: SearchService,
protected sidebarService: SearchSidebarService,
protected windowService: HostWindowService,
@Inject(SEARCH_CONFIG_SERVICE) public searchConfigService: SearchConfigurationService,
protected routeService: 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 configuration using the configuration input
* This is to make sure the configuration is included in the paginated search options, as it is not part of any
* query or route parameters
* @returns {Observable<PaginatedSearchOptions>}
*/
protected getSearchOptions(): Observable<PaginatedSearchOptions> {
return this.searchConfigService.paginatedSearchOptions.pipe(
map((options: PaginatedSearchOptions) => {
const config = this.configuration || options.configuration;
return Object.assign(options, { configuration: config });
})
);
}
}

View File

@@ -0,0 +1,22 @@
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
@Injectable()
/**
* Assemble the correct i18n key for the configuration search page's title depending on the current route's configuration parameter.
* The format of the key will be "{configuration}.search.title" with:
* - configuration: The current configuration stored in route.params
*/
export class ConfigurationSearchPageGuard implements CanActivate {
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
const configuration = route.params.configuration;
const newTitle = configuration + '.search.title';
route.data = { title: newTitle };
return true;
}
}

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