diff --git a/package.json b/package.json index 34e77a8928..3a54b941dd 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,8 @@ "docs": "typedoc --options typedoc.json ./src/", "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" + "patch-protractor": "ncp node_modules/webdriver-manager node_modules/protractor/node_modules/webdriver-manager", + "sync-i18n": "node ./scripts/sync-i18n-files.js" }, "dependencies": { "@angular/animations": "^6.1.4", @@ -174,7 +175,9 @@ "angular2-template-loader": "0.6.2", "autoprefixer": "^9.1.3", "caniuse-lite": "^1.0.30000697", + "cli-progress": "^3.3.1", "codelyzer": "^4.4.4", + "commander": "^3.0.2", "compression-webpack-plugin": "^1.1.6", "copy-webpack-plugin": "^4.4.1", "copyfiles": "^2.1.1", diff --git a/resources/i18n/cs.json5 b/resources/i18n/cs.json5 index bd4363409b..29fb51777a 100644 --- a/resources/i18n/cs.json5 +++ b/resources/i18n/cs.json5 @@ -1,176 +1,3090 @@ { + + // "404.help": "We can't find the page you're looking for. The page may have been moved or deleted. You can use the button below to get back to the home page. ", "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. ", + + // "404.link.home-page": "Take me to the home page", "404.link.home-page": "Přejít na domovskou stránku", + + // "404.page-not-found": "page not found", "404.page-not-found": "stránka nenalezena", - + + + + // "admin.registries.bitstream-formats.create.failure.content": "An error occurred while creating the new bitstream format.", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.create.failure.content": "An error occurred while creating the new bitstream format.", + + // "admin.registries.bitstream-formats.create.failure.head": "Failure", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.create.failure.head": "Failure", + + // "admin.registries.bitstream-formats.create.head": "Create Bitstream format", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.create.head": "Create Bitstream format", + + // "admin.registries.bitstream-formats.create.new": "Add a new bitstream format", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.create.new": "Add a new bitstream format", + + // "admin.registries.bitstream-formats.create.success.content": "The new bitstream format was successfully created.", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.create.success.content": "The new bitstream format was successfully created.", + + // "admin.registries.bitstream-formats.create.success.head": "Success", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.create.success.head": "Success", + + // "admin.registries.bitstream-formats.delete.failure.amount": "Failed to remove {{ amount }} format(s)", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.delete.failure.amount": "Failed to remove {{ amount }} format(s)", + + // "admin.registries.bitstream-formats.delete.failure.head": "Failure", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.delete.failure.head": "Failure", + + // "admin.registries.bitstream-formats.delete.success.amount": "Successfully removed {{ amount }} format(s)", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.delete.success.amount": "Successfully removed {{ amount }} format(s)", + + // "admin.registries.bitstream-formats.delete.success.head": "Success", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.delete.success.head": "Success", + + // "admin.registries.bitstream-formats.description": "This list of bitstream formats provides information about known formats and their support level.", "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ů.", - "admin.registries.bitstream-formats.formats.table.internal": "interní", - "admin.registries.bitstream-formats.formats.table.mimetype": "Typ MIME", - "admin.registries.bitstream-formats.formats.table.name": "Název", - "admin.registries.bitstream-formats.formats.table.supportLevel.0": "Neznámá", - "admin.registries.bitstream-formats.formats.table.supportLevel.1": "Známá", - "admin.registries.bitstream-formats.formats.table.supportLevel.2": "Podpora", - "admin.registries.bitstream-formats.formats.table.supportLevel.head": "Úroveň podpory", + + // "admin.registries.bitstream-formats.edit.description.hint": "", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.description.hint": "", + + // "admin.registries.bitstream-formats.edit.description.label": "Description", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.description.label": "Description", + + // "admin.registries.bitstream-formats.edit.extensions.hint": "Extensions are file extensions that are used to automatically identify the format of uploaded files. You can enter several extensions for each format.", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.extensions.hint": "Extensions are file extensions that are used to automatically identify the format of uploaded files. You can enter several extensions for each format.", + + // "admin.registries.bitstream-formats.edit.extensions.label": "File extensions", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.extensions.label": "File extensions", + + // "admin.registries.bitstream-formats.edit.extensions.placeholder": "Enter a file extenstion without the dot", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.extensions.placeholder": "Enter a file extenstion without the dot", + + // "admin.registries.bitstream-formats.edit.failure.content": "An error occurred while editing the bitstream format.", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.failure.content": "An error occurred while editing the bitstream format.", + + // "admin.registries.bitstream-formats.edit.failure.head": "Failure", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.failure.head": "Failure", + + // "admin.registries.bitstream-formats.edit.head": "Bitstream format: {{ format }}", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.head": "Bitstream format: {{ format }}", + + // "admin.registries.bitstream-formats.edit.internal.hint": "Formats marked as internal are are hidden from the user, and used for administrative purposes.", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.internal.hint": "Formats marked as internal are are hidden from the user, and used for administrative purposes.", + + // "admin.registries.bitstream-formats.edit.internal.label": "Internal", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.internal.label": "Internal", + + // "admin.registries.bitstream-formats.edit.mimetype.hint": "The MIME type associated with this format, does not have to be unique.", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.mimetype.hint": "The MIME type associated with this format, does not have to be unique.", + + // "admin.registries.bitstream-formats.edit.mimetype.label": "MIME Type", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.mimetype.label": "MIME Type", + + // "admin.registries.bitstream-formats.edit.shortDescription.hint": "A unique name for this format, (e.g. Microsoft Word XP or Microsoft Word 2000)", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.shortDescription.hint": "A unique name for this format, (e.g. Microsoft Word XP or Microsoft Word 2000)", + + // "admin.registries.bitstream-formats.edit.shortDescription.label": "Name", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.shortDescription.label": "Name", + + // "admin.registries.bitstream-formats.edit.success.content": "The bitstream format was successfully edited.", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.success.content": "The bitstream format was successfully edited.", + + // "admin.registries.bitstream-formats.edit.success.head": "Success", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.success.head": "Success", + + // "admin.registries.bitstream-formats.edit.supportLevel.hint": "The level of support your institution pledges for this format.", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.supportLevel.hint": "The level of support your institution pledges for this format.", + + // "admin.registries.bitstream-formats.edit.supportLevel.label": "Support level", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.supportLevel.label": "Support level", + + // "admin.registries.bitstream-formats.head": "Bitstream Format Registry", "admin.registries.bitstream-formats.head": "Registr formátů souborů", + + // "admin.registries.bitstream-formats.no-items": "No bitstream formats to show.", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.no-items": "No bitstream formats to show.", + + // "admin.registries.bitstream-formats.table.delete": "Delete selected", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.table.delete": "Delete selected", + + // "admin.registries.bitstream-formats.table.deselect-all": "Deselect all", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.table.deselect-all": "Deselect all", + + // "admin.registries.bitstream-formats.table.internal": "internal", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.table.internal": "internal", + + // "admin.registries.bitstream-formats.table.mimetype": "MIME Type", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.table.mimetype": "MIME Type", + + // "admin.registries.bitstream-formats.table.name": "Name", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.table.name": "Name", + + // "admin.registries.bitstream-formats.table.return": "Return", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.table.return": "Return", + + // "admin.registries.bitstream-formats.table.supportLevel.KNOWN": "Known", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.table.supportLevel.KNOWN": "Known", + + // "admin.registries.bitstream-formats.table.supportLevel.SUPPORTED": "Supported", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.table.supportLevel.SUPPORTED": "Supported", + + // "admin.registries.bitstream-formats.table.supportLevel.UNKNOWN": "Unknown", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.table.supportLevel.UNKNOWN": "Unknown", + + // "admin.registries.bitstream-formats.table.supportLevel.head": "Support Level", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.table.supportLevel.head": "Support Level", + + // "admin.registries.bitstream-formats.title": "DSpace Angular :: Bitstream Format Registry", "admin.registries.bitstream-formats.title": "DSpace Angular :: Registr formátů souborů", - + + + + // "admin.registries.metadata.description": "The metadata registry maintains a list of all metadata fields available in the repository. These fields may be divided amongst multiple schemas. However, DSpace requires the qualified Dublin Core schema.", "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 Kvalifikovaný Dublin Core.", + + // "admin.registries.metadata.form.create": "Create metadata schema", + // TODO New key - Add a translation + "admin.registries.metadata.form.create": "Create metadata schema", + + // "admin.registries.metadata.form.edit": "Edit metadata schema", + // TODO New key - Add a translation + "admin.registries.metadata.form.edit": "Edit metadata schema", + + // "admin.registries.metadata.form.name": "Name", + // TODO New key - Add a translation + "admin.registries.metadata.form.name": "Name", + + // "admin.registries.metadata.form.namespace": "Namespace", + // TODO New key - Add a translation + "admin.registries.metadata.form.namespace": "Namespace", + + // "admin.registries.metadata.head": "Metadata Registry", "admin.registries.metadata.head": "Registr metadat", + + // "admin.registries.metadata.schemas.no-items": "No metadata schemas to show.", "admin.registries.metadata.schemas.no-items": "Žádná schémata metadat.", + + // "admin.registries.metadata.schemas.table.delete": "Delete selected", + // TODO New key - Add a translation + "admin.registries.metadata.schemas.table.delete": "Delete selected", + + // "admin.registries.metadata.schemas.table.id": "ID", "admin.registries.metadata.schemas.table.id": "ID", + + // "admin.registries.metadata.schemas.table.name": "Name", "admin.registries.metadata.schemas.table.name": "Název", + + // "admin.registries.metadata.schemas.table.namespace": "Namespace", "admin.registries.metadata.schemas.table.namespace": "Jmenný prostor", + + // "admin.registries.metadata.title": "DSpace Angular :: Metadata Registry", "admin.registries.metadata.title": "DSpace Angular :: Registr metadat", - + + + + // "admin.registries.schema.description": "This is the metadata schema for \"{{namespace}}\".", "admin.registries.schema.description": "Toto je schéma metadat pro „{{namespace}}“.", + + // "admin.registries.schema.fields.head": "Schema metadata fields", "admin.registries.schema.fields.head": "Pole schématu metadat", + + // "admin.registries.schema.fields.no-items": "No metadata fields to show.", "admin.registries.schema.fields.no-items": "Žádná metadatová pole.", + + // "admin.registries.schema.fields.table.delete": "Delete selected", + // TODO New key - Add a translation + "admin.registries.schema.fields.table.delete": "Delete selected", + + // "admin.registries.schema.fields.table.field": "Field", "admin.registries.schema.fields.table.field": "Pole", + + // "admin.registries.schema.fields.table.scopenote": "Scope Note", "admin.registries.schema.fields.table.scopenote": "Poznámka o rozsahu", + + // "admin.registries.schema.form.create": "Create metadata field", + // TODO New key - Add a translation + "admin.registries.schema.form.create": "Create metadata field", + + // "admin.registries.schema.form.edit": "Edit metadata field", + // TODO New key - Add a translation + "admin.registries.schema.form.edit": "Edit metadata field", + + // "admin.registries.schema.form.element": "Element", + // TODO New key - Add a translation + "admin.registries.schema.form.element": "Element", + + // "admin.registries.schema.form.qualifier": "Qualifier", + // TODO New key - Add a translation + "admin.registries.schema.form.qualifier": "Qualifier", + + // "admin.registries.schema.form.scopenote": "Scope Note", + // TODO New key - Add a translation + "admin.registries.schema.form.scopenote": "Scope Note", + + // "admin.registries.schema.head": "Metadata Schema", "admin.registries.schema.head": "Schéma metadat", + + // "admin.registries.schema.notification.created": "Successfully created metadata schema \"{{prefix}}\"", + // TODO New key - Add a translation + "admin.registries.schema.notification.created": "Successfully created metadata schema \"{{prefix}}\"", + + // "admin.registries.schema.notification.deleted.failure": "Failed to delete {{amount}} metadata schemas", + // TODO New key - Add a translation + "admin.registries.schema.notification.deleted.failure": "Failed to delete {{amount}} metadata schemas", + + // "admin.registries.schema.notification.deleted.success": "Successfully deleted {{amount}} metadata schemas", + // TODO New key - Add a translation + "admin.registries.schema.notification.deleted.success": "Successfully deleted {{amount}} metadata schemas", + + // "admin.registries.schema.notification.edited": "Successfully edited metadata schema \"{{prefix}}\"", + // TODO New key - Add a translation + "admin.registries.schema.notification.edited": "Successfully edited metadata schema \"{{prefix}}\"", + + // "admin.registries.schema.notification.failure": "Error", + // TODO New key - Add a translation + "admin.registries.schema.notification.failure": "Error", + + // "admin.registries.schema.notification.field.created": "Successfully created metadata field \"{{field}}\"", + // TODO New key - Add a translation + "admin.registries.schema.notification.field.created": "Successfully created metadata field \"{{field}}\"", + + // "admin.registries.schema.notification.field.deleted.failure": "Failed to delete {{amount}} metadata fields", + // TODO New key - Add a translation + "admin.registries.schema.notification.field.deleted.failure": "Failed to delete {{amount}} metadata fields", + + // "admin.registries.schema.notification.field.deleted.success": "Successfully deleted {{amount}} metadata fields", + // TODO New key - Add a translation + "admin.registries.schema.notification.field.deleted.success": "Successfully deleted {{amount}} metadata fields", + + // "admin.registries.schema.notification.field.edited": "Successfully edited metadata field \"{{field}}\"", + // TODO New key - Add a translation + "admin.registries.schema.notification.field.edited": "Successfully edited metadata field \"{{field}}\"", + + // "admin.registries.schema.notification.success": "Success", + // TODO New key - Add a translation + "admin.registries.schema.notification.success": "Success", + + // "admin.registries.schema.return": "Return", + // TODO New key - Add a translation + "admin.registries.schema.return": "Return", + + // "admin.registries.schema.title": "DSpace Angular :: Metadata Schema Registry", "admin.registries.schema.title": "DSpace Angular :: Registr schémat metadat", - + + + + // "auth.errors.invalid-user": "Invalid email address or password.", "auth.errors.invalid-user": "Neplatná e-mailová adresa nebo heslo.", + + // "auth.messages.expired": "Your session has expired. Please log in again.", "auth.messages.expired": "Vaše relace vypršela. Prosím, znova se přihlaste.", - + + + + // "browse.comcol.by.author": "By Author", + // TODO New key - Add a translation + "browse.comcol.by.author": "By Author", + + // "browse.comcol.by.dateissued": "By Issue Date", + // TODO New key - Add a translation + "browse.comcol.by.dateissued": "By Issue Date", + + // "browse.comcol.by.subject": "By Subject", + // TODO New key - Add a translation + "browse.comcol.by.subject": "By Subject", + + // "browse.comcol.by.title": "By Title", + // TODO New key - Add a translation + "browse.comcol.by.title": "By Title", + + // "browse.comcol.head": "Browse", + // TODO New key - Add a translation + "browse.comcol.head": "Browse", + + // "browse.empty": "No items to show.", + // TODO New key - Add a translation + "browse.empty": "No items to show.", + + // "browse.metadata.author": "Author", + // TODO New key - Add a translation + "browse.metadata.author": "Author", + + // "browse.metadata.dateissued": "Issue Date", + // TODO New key - Add a translation + "browse.metadata.dateissued": "Issue Date", + + // "browse.metadata.subject": "Subject", + // TODO New key - Add a translation + "browse.metadata.subject": "Subject", + + // "browse.metadata.title": "Title", + // TODO New key - Add a translation + "browse.metadata.title": "Title", + + // "browse.startsWith.choose_start": "(Choose start)", + // TODO New key - Add a translation + "browse.startsWith.choose_start": "(Choose start)", + + // "browse.startsWith.choose_year": "(Choose year)", + // TODO New key - Add a translation + "browse.startsWith.choose_year": "(Choose year)", + + // "browse.startsWith.jump": "Jump to a point in the index:", + // TODO New key - Add a translation + "browse.startsWith.jump": "Jump to a point in the index:", + + // "browse.startsWith.months.april": "April", + // TODO New key - Add a translation + "browse.startsWith.months.april": "April", + + // "browse.startsWith.months.august": "August", + // TODO New key - Add a translation + "browse.startsWith.months.august": "August", + + // "browse.startsWith.months.december": "December", + // TODO New key - Add a translation + "browse.startsWith.months.december": "December", + + // "browse.startsWith.months.february": "February", + // TODO New key - Add a translation + "browse.startsWith.months.february": "February", + + // "browse.startsWith.months.january": "January", + // TODO New key - Add a translation + "browse.startsWith.months.january": "January", + + // "browse.startsWith.months.july": "July", + // TODO New key - Add a translation + "browse.startsWith.months.july": "July", + + // "browse.startsWith.months.june": "June", + // TODO New key - Add a translation + "browse.startsWith.months.june": "June", + + // "browse.startsWith.months.march": "March", + // TODO New key - Add a translation + "browse.startsWith.months.march": "March", + + // "browse.startsWith.months.may": "May", + // TODO New key - Add a translation + "browse.startsWith.months.may": "May", + + // "browse.startsWith.months.none": "(Choose month)", + // TODO New key - Add a translation + "browse.startsWith.months.none": "(Choose month)", + + // "browse.startsWith.months.november": "November", + // TODO New key - Add a translation + "browse.startsWith.months.november": "November", + + // "browse.startsWith.months.october": "October", + // TODO New key - Add a translation + "browse.startsWith.months.october": "October", + + // "browse.startsWith.months.september": "September", + // TODO New key - Add a translation + "browse.startsWith.months.september": "September", + + // "browse.startsWith.submit": "Go", + // TODO New key - Add a translation + "browse.startsWith.submit": "Go", + + // "browse.startsWith.type_date": "Or type in a date (year-month):", + // TODO New key - Add a translation + "browse.startsWith.type_date": "Or type in a date (year-month):", + + // "browse.startsWith.type_text": "Or enter first few letters:", + // TODO New key - Add a translation + "browse.startsWith.type_text": "Or enter first few letters:", + + // "browse.title": "Browsing {{ collection }} by {{ field }} {{ value }}", "browse.title": "Prohlížíte {{ collection }} dle {{ field }} {{ value }}", - + + + + // "chips.remove": "Remove chip", + // TODO New key - Add a translation + "chips.remove": "Remove chip", + + + + // "collection.create.head": "Create a Collection", + // TODO New key - Add a translation + "collection.create.head": "Create a Collection", + + // "collection.create.sub-head": "Create a Collection for Community {{ parent }}", + // TODO New key - Add a translation + "collection.create.sub-head": "Create a Collection for Community {{ parent }}", + + // "collection.delete.cancel": "Cancel", + // TODO New key - Add a translation + "collection.delete.cancel": "Cancel", + + // "collection.delete.confirm": "Confirm", + // TODO New key - Add a translation + "collection.delete.confirm": "Confirm", + + // "collection.delete.head": "Delete Collection", + // TODO New key - Add a translation + "collection.delete.head": "Delete Collection", + + // "collection.delete.notification.fail": "Collection could not be deleted", + // TODO New key - Add a translation + "collection.delete.notification.fail": "Collection could not be deleted", + + // "collection.delete.notification.success": "Successfully deleted collection", + // TODO New key - Add a translation + "collection.delete.notification.success": "Successfully deleted collection", + + // "collection.delete.text": "Are you sure you want to delete collection \"{{ dso }}\"", + // TODO New key - Add a translation + "collection.delete.text": "Are you sure you want to delete collection \"{{ dso }}\"", + + + + // "collection.edit.delete": "Delete this collection", + // TODO New key - Add a translation + "collection.edit.delete": "Delete this collection", + + // "collection.edit.head": "Edit Collection", + // TODO New key - Add a translation + "collection.edit.head": "Edit Collection", + + + + // "collection.edit.item-mapper.cancel": "Cancel", + // TODO New key - Add a translation + "collection.edit.item-mapper.cancel": "Cancel", + + // "collection.edit.item-mapper.collection": "Collection: \"{{name}}\"", + // TODO New key - Add a translation + "collection.edit.item-mapper.collection": "Collection: \"{{name}}\"", + + // "collection.edit.item-mapper.confirm": "Map selected items", + // TODO New key - Add a translation + "collection.edit.item-mapper.confirm": "Map selected items", + + // "collection.edit.item-mapper.description": "This is the item mapper tool that allows collection administrators to map items from other collections into this collection. You can search for items from other collections and map them, or browse the list of currently mapped items.", + // TODO New key - Add a translation + "collection.edit.item-mapper.description": "This is the item mapper tool that allows collection administrators to map items from other collections into this collection. You can search for items from other collections and map them, or browse the list of currently mapped items.", + + // "collection.edit.item-mapper.head": "Item Mapper - Map Items from Other Collections", + // TODO New key - Add a translation + "collection.edit.item-mapper.head": "Item Mapper - Map Items from Other Collections", + + // "collection.edit.item-mapper.no-search": "Please enter a query to search", + // TODO New key - Add a translation + "collection.edit.item-mapper.no-search": "Please enter a query to search", + + // "collection.edit.item-mapper.notifications.map.error.content": "Errors occurred for mapping of {{amount}} items.", + // TODO New key - Add a translation + "collection.edit.item-mapper.notifications.map.error.content": "Errors occurred for mapping of {{amount}} items.", + + // "collection.edit.item-mapper.notifications.map.error.head": "Mapping errors", + // TODO New key - Add a translation + "collection.edit.item-mapper.notifications.map.error.head": "Mapping errors", + + // "collection.edit.item-mapper.notifications.map.success.content": "Successfully mapped {{amount}} items.", + // TODO New key - Add a translation + "collection.edit.item-mapper.notifications.map.success.content": "Successfully mapped {{amount}} items.", + + // "collection.edit.item-mapper.notifications.map.success.head": "Mapping completed", + // TODO New key - Add a translation + "collection.edit.item-mapper.notifications.map.success.head": "Mapping completed", + + // "collection.edit.item-mapper.notifications.unmap.error.content": "Errors occurred for removing the mappings of {{amount}} items.", + // TODO New key - Add a translation + "collection.edit.item-mapper.notifications.unmap.error.content": "Errors occurred for removing the mappings of {{amount}} items.", + + // "collection.edit.item-mapper.notifications.unmap.error.head": "Remove mapping errors", + // TODO New key - Add a translation + "collection.edit.item-mapper.notifications.unmap.error.head": "Remove mapping errors", + + // "collection.edit.item-mapper.notifications.unmap.success.content": "Successfully removed the mappings of {{amount}} items.", + // TODO New key - Add a translation + "collection.edit.item-mapper.notifications.unmap.success.content": "Successfully removed the mappings of {{amount}} items.", + + // "collection.edit.item-mapper.notifications.unmap.success.head": "Remove mapping completed", + // TODO New key - Add a translation + "collection.edit.item-mapper.notifications.unmap.success.head": "Remove mapping completed", + + // "collection.edit.item-mapper.remove": "Remove selected item mappings", + // TODO New key - Add a translation + "collection.edit.item-mapper.remove": "Remove selected item mappings", + + // "collection.edit.item-mapper.tabs.browse": "Browse mapped items", + // TODO New key - Add a translation + "collection.edit.item-mapper.tabs.browse": "Browse mapped items", + + // "collection.edit.item-mapper.tabs.map": "Map new items", + // TODO New key - Add a translation + "collection.edit.item-mapper.tabs.map": "Map new items", + + + + // "collection.form.abstract": "Short Description", + // TODO New key - Add a translation + "collection.form.abstract": "Short Description", + + // "collection.form.description": "Introductory text (HTML)", + // TODO New key - Add a translation + "collection.form.description": "Introductory text (HTML)", + + // "collection.form.errors.title.required": "Please enter a collection name", + // TODO New key - Add a translation + "collection.form.errors.title.required": "Please enter a collection name", + + // "collection.form.license": "License", + // TODO New key - Add a translation + "collection.form.license": "License", + + // "collection.form.provenance": "Provenance", + // TODO New key - Add a translation + "collection.form.provenance": "Provenance", + + // "collection.form.rights": "Copyright text (HTML)", + // TODO New key - Add a translation + "collection.form.rights": "Copyright text (HTML)", + + // "collection.form.tableofcontents": "News (HTML)", + // TODO New key - Add a translation + "collection.form.tableofcontents": "News (HTML)", + + // "collection.form.title": "Name", + // TODO New key - Add a translation + "collection.form.title": "Name", + + + + // "collection.page.browse.recent.head": "Recent Submissions", "collection.page.browse.recent.head": "Poslední příspěvky", + + // "collection.page.browse.recent.empty": "No items to show", + // TODO New key - Add a translation + "collection.page.browse.recent.empty": "No items to show", + + // "collection.page.handle": "Permanent URI for this collection", + // TODO New key - Add a translation + "collection.page.handle": "Permanent URI for this collection", + + // "collection.page.license": "License", "collection.page.license": "Licence", + + // "collection.page.news": "News", "collection.page.news": "Novinky", - + + + + // "collection.select.confirm": "Confirm selected", + // TODO New key - Add a translation + "collection.select.confirm": "Confirm selected", + + // "collection.select.empty": "No collections to show", + // TODO New key - Add a translation + "collection.select.empty": "No collections to show", + + // "collection.select.table.title": "Title", + // TODO New key - Add a translation + "collection.select.table.title": "Title", + + + + // "community.create.head": "Create a Community", + // TODO New key - Add a translation + "community.create.head": "Create a Community", + + // "community.create.sub-head": "Create a Sub-Community for Community {{ parent }}", + // TODO New key - Add a translation + "community.create.sub-head": "Create a Sub-Community for Community {{ parent }}", + + // "community.delete.cancel": "Cancel", + // TODO New key - Add a translation + "community.delete.cancel": "Cancel", + + // "community.delete.confirm": "Confirm", + // TODO New key - Add a translation + "community.delete.confirm": "Confirm", + + // "community.delete.head": "Delete Community", + // TODO New key - Add a translation + "community.delete.head": "Delete Community", + + // "community.delete.notification.fail": "Community could not be deleted", + // TODO New key - Add a translation + "community.delete.notification.fail": "Community could not be deleted", + + // "community.delete.notification.success": "Successfully deleted community", + // TODO New key - Add a translation + "community.delete.notification.success": "Successfully deleted community", + + // "community.delete.text": "Are you sure you want to delete community \"{{ dso }}\"", + // TODO New key - Add a translation + "community.delete.text": "Are you sure you want to delete community \"{{ dso }}\"", + + // "community.edit.delete": "Delete this community", + // TODO New key - Add a translation + "community.edit.delete": "Delete this community", + + // "community.edit.head": "Edit Community", + // TODO New key - Add a translation + "community.edit.head": "Edit Community", + + // "community.form.abstract": "Short Description", + // TODO New key - Add a translation + "community.form.abstract": "Short Description", + + // "community.form.description": "Introductory text (HTML)", + // TODO New key - Add a translation + "community.form.description": "Introductory text (HTML)", + + // "community.form.errors.title.required": "Please enter a community name", + // TODO New key - Add a translation + "community.form.errors.title.required": "Please enter a community name", + + // "community.form.rights": "Copyright text (HTML)", + // TODO New key - Add a translation + "community.form.rights": "Copyright text (HTML)", + + // "community.form.tableofcontents": "News (HTML)", + // TODO New key - Add a translation + "community.form.tableofcontents": "News (HTML)", + + // "community.form.title": "Name", + // TODO New key - Add a translation + "community.form.title": "Name", + + // "community.page.handle": "Permanent URI for this community", + // TODO New key - Add a translation + "community.page.handle": "Permanent URI for this community", + + // "community.page.license": "License", "community.page.license": "Licence", + + // "community.page.news": "News", "community.page.news": "Novinky", + + // "community.all-lists.head": "Subcommunities and Collections", + // TODO New key - Add a translation + "community.all-lists.head": "Subcommunities and Collections", + + // "community.sub-collection-list.head": "Collections of this Community", "community.sub-collection-list.head": "Kolekce v této komunitě", - + + // "community.sub-community-list.head": "Communities of this Community", + // TODO New key - Add a translation + "community.sub-community-list.head": "Communities of this Community", + + + + // "dso-selector.create.collection.head": "New collection", + // TODO New key - Add a translation + "dso-selector.create.collection.head": "New collection", + + // "dso-selector.create.community.head": "New community", + // TODO New key - Add a translation + "dso-selector.create.community.head": "New community", + + // "dso-selector.create.community.sub-level": "Create a new community in", + // TODO New key - Add a translation + "dso-selector.create.community.sub-level": "Create a new community in", + + // "dso-selector.create.community.top-level": "Create a new top-level community", + // TODO New key - Add a translation + "dso-selector.create.community.top-level": "Create a new top-level community", + + // "dso-selector.create.item.head": "New item", + // TODO New key - Add a translation + "dso-selector.create.item.head": "New item", + + // "dso-selector.edit.collection.head": "Edit collection", + // TODO New key - Add a translation + "dso-selector.edit.collection.head": "Edit collection", + + // "dso-selector.edit.community.head": "Edit community", + // TODO New key - Add a translation + "dso-selector.edit.community.head": "Edit community", + + // "dso-selector.edit.item.head": "Edit item", + // TODO New key - Add a translation + "dso-selector.edit.item.head": "Edit item", + + // "dso-selector.no-results": "No {{ type }} found", + // TODO New key - Add a translation + "dso-selector.no-results": "No {{ type }} found", + + // "dso-selector.placeholder": "Search for a {{ type }}", + // TODO New key - Add a translation + "dso-selector.placeholder": "Search for a {{ type }}", + + + + // "error.browse-by": "Error fetching items", "error.browse-by": "Chyba během stahování záznamů", + + // "error.collection": "Error fetching collection", "error.collection": "Chyba během stahování kolekce", + + // "error.collections": "Error fetching collections", + // TODO New key - Add a translation + "error.collections": "Error fetching collections", + + // "error.community": "Error fetching community", "error.community": "Chyba během stahování komunity", + // "error.identifier": "No item found for the identifier", + // TODO New key - Add a translation + "error.identifier": "No item found for the identifier", + + // "error.identifier": "No item found for the identifier", + // TODO New key - Add a translation + "error.identifier": "No item found for the identifier", + + // "error.default": "Error", "error.default": "Chyba", + + // "error.item": "Error fetching item", "error.item": "Chyba během stahování záznamu", + + // "error.items": "Error fetching items", + // TODO New key - Add a translation + "error.items": "Error fetching items", + + // "error.objects": "Error fetching objects", "error.objects": "Chyba během stahování objektů", + + // "error.recent-submissions": "Error fetching recent submissions", "error.recent-submissions": "Chyba během stahování posledních příspěvků", + + // "error.search-results": "Error fetching search results", "error.search-results": "Chyba během stahování výsledků hledání", + + // "error.sub-collections": "Error fetching sub-collections", "error.sub-collections": "Chyba během stahování subkolekcí", + + // "error.sub-communities": "Error fetching sub-communities", + // TODO New key - Add a translation + "error.sub-communities": "Error fetching sub-communities", + + // "error.submission.sections.init-form-error": "An error occurred during section initialize, please check your input-form configuration. Details are below :

", + // TODO New key - Add a translation + "error.submission.sections.init-form-error": "An error occurred during section initialize, please check your input-form configuration. Details are below :

", + + // "error.top-level-communities": "Error fetching top-level communities", "error.top-level-communities": "Chyba během stahování komunit nejvyšší úrovně", + + // "error.validation.license.notgranted": "You must grant this license to complete your submission. If you are unable to grant this license at this time you may save your work and return later or remove the submission.", "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.", - "error.validation.pattern": "Tento vstup je omezen dle vzoru: {{ pattern }}.", - + + // "error.validation.pattern": "This input is restricted by the current pattern: {{ pattern }}.", + // TODO New key - Add a translation + "error.validation.pattern": "This input is restricted by the current pattern: {{ pattern }}.", + + + + // "footer.copyright": "copyright © 2002-{{ year }}", "footer.copyright": "copyright © 2002-{{ year }}", + + // "footer.link.dspace": "DSpace software", "footer.link.dspace": "software DSpace", + + // "footer.link.duraspace": "DuraSpace", "footer.link.duraspace": "DuraSpace", - + + + + // "form.cancel": "Cancel", "form.cancel": "Zrušit", + + // "form.clear": "Clear", + // TODO New key - Add a translation + "form.clear": "Clear", + + // "form.clear-help": "Click here to remove the selected value", + // TODO New key - Add a translation + "form.clear-help": "Click here to remove the selected value", + + // "form.edit": "Edit", + // TODO New key - Add a translation + "form.edit": "Edit", + + // "form.edit-help": "Click here to edit the selected value", + // TODO New key - Add a translation + "form.edit-help": "Click here to edit the selected value", + + // "form.first-name": "First name", "form.first-name": "Křestní jméno", + + // "form.group-collapse": "Collapse", "form.group-collapse": "Sbalit", + + // "form.group-collapse-help": "Click here to collapse", "form.group-collapse-help": "Kliknutím sem sbalíte", + + // "form.group-expand": "Expand", "form.group-expand": "Rozbalit", + + // "form.group-expand-help": "Click here to expand and add more elements", "form.group-expand-help": "Kliknutím sem rozbalíte a přidáte další prvky", + + // "form.last-name": "Last name", "form.last-name": "Příjmení", + + // "form.loading": "Loading...", "form.loading": "Načítá se...", + + // "form.no-results": "No results found", "form.no-results": "Nebyli nalezeny žádné výsledky", + + // "form.no-value": "No value entered", "form.no-value": "Nebyla zadána hodnota", + + // "form.other-information": {}, + // TODO New key - Add a translation + "form.other-information": {}, + + // "form.remove": "Remove", "form.remove": "Smazat", + + // "form.save": "Save", + // TODO New key - Add a translation + "form.save": "Save", + + // "form.save-help": "Save changes", + // TODO New key - Add a translation + "form.save-help": "Save changes", + + // "form.search": "Search", "form.search": "Hledat", + + // "form.search-help": "Click here to looking for an existing correspondence", + // TODO New key - Add a translation + "form.search-help": "Click here to looking for an existing correspondence", + + // "form.submit": "Submit", "form.submit": "Odeslat", - + + + + // "home.description": "", "home.description": "", + + // "home.title": "DSpace Angular :: Home", "home.title": "DSpace Angular :: Domů", + + // "home.top-level-communities.head": "Communities in DSpace", "home.top-level-communities.head": "Komunity v DSpace", + + // "home.top-level-communities.help": "Select a community to browse its collections.", "home.top-level-communities.help": "Vybráním komunity můžete prohlížet její kolekce.", - + + + + // "item.edit.delete.cancel": "Cancel", + // TODO New key - Add a translation + "item.edit.delete.cancel": "Cancel", + + // "item.edit.delete.confirm": "Delete", + // TODO New key - Add a translation + "item.edit.delete.confirm": "Delete", + + // "item.edit.delete.description": "Are you sure this item should be completely deleted? Caution: At present, no tombstone would be left.", + // TODO New key - Add a translation + "item.edit.delete.description": "Are you sure this item should be completely deleted? Caution: At present, no tombstone would be left.", + + // "item.edit.delete.error": "An error occurred while deleting the item", + // TODO New key - Add a translation + "item.edit.delete.error": "An error occurred while deleting the item", + + // "item.edit.delete.header": "Delete item: {{ id }}", + // TODO New key - Add a translation + "item.edit.delete.header": "Delete item: {{ id }}", + + // "item.edit.delete.success": "The item has been deleted", + // TODO New key - Add a translation + "item.edit.delete.success": "The item has been deleted", + + // "item.edit.head": "Edit Item", + // TODO New key - Add a translation + "item.edit.head": "Edit Item", + + + + // "item.edit.item-mapper.buttons.add": "Map item to selected collections", + // TODO New key - Add a translation + "item.edit.item-mapper.buttons.add": "Map item to selected collections", + + // "item.edit.item-mapper.buttons.remove": "Remove item's mapping for selected collections", + // TODO New key - Add a translation + "item.edit.item-mapper.buttons.remove": "Remove item's mapping for selected collections", + + // "item.edit.item-mapper.cancel": "Cancel", + // TODO New key - Add a translation + "item.edit.item-mapper.cancel": "Cancel", + + // "item.edit.item-mapper.description": "This is the item mapper tool that allows administrators to map this item to other collections. You can search for collections and map them, or browse the list of collections the item is currently mapped to.", + // TODO New key - Add a translation + "item.edit.item-mapper.description": "This is the item mapper tool that allows administrators to map this item to other collections. You can search for collections and map them, or browse the list of collections the item is currently mapped to.", + + // "item.edit.item-mapper.head": "Item Mapper - Map Item to Collections", + // TODO New key - Add a translation + "item.edit.item-mapper.head": "Item Mapper - Map Item to Collections", + + // "item.edit.item-mapper.item": "Item: \"{{name}}\"", + // TODO New key - Add a translation + "item.edit.item-mapper.item": "Item: \"{{name}}\"", + + // "item.edit.item-mapper.no-search": "Please enter a query to search", + // TODO New key - Add a translation + "item.edit.item-mapper.no-search": "Please enter a query to search", + + // "item.edit.item-mapper.notifications.add.error.content": "Errors occurred for mapping of item to {{amount}} collections.", + // TODO New key - Add a translation + "item.edit.item-mapper.notifications.add.error.content": "Errors occurred for mapping of item to {{amount}} collections.", + + // "item.edit.item-mapper.notifications.add.error.head": "Mapping errors", + // TODO New key - Add a translation + "item.edit.item-mapper.notifications.add.error.head": "Mapping errors", + + // "item.edit.item-mapper.notifications.add.success.content": "Successfully mapped item to {{amount}} collections.", + // TODO New key - Add a translation + "item.edit.item-mapper.notifications.add.success.content": "Successfully mapped item to {{amount}} collections.", + + // "item.edit.item-mapper.notifications.add.success.head": "Mapping completed", + // TODO New key - Add a translation + "item.edit.item-mapper.notifications.add.success.head": "Mapping completed", + + // "item.edit.item-mapper.notifications.remove.error.content": "Errors occurred for the removal of the mapping to {{amount}} collections.", + // TODO New key - Add a translation + "item.edit.item-mapper.notifications.remove.error.content": "Errors occurred for the removal of the mapping to {{amount}} collections.", + + // "item.edit.item-mapper.notifications.remove.error.head": "Removal of mapping errors", + // TODO New key - Add a translation + "item.edit.item-mapper.notifications.remove.error.head": "Removal of mapping errors", + + // "item.edit.item-mapper.notifications.remove.success.content": "Successfully removed mapping of item to {{amount}} collections.", + // TODO New key - Add a translation + "item.edit.item-mapper.notifications.remove.success.content": "Successfully removed mapping of item to {{amount}} collections.", + + // "item.edit.item-mapper.notifications.remove.success.head": "Removal of mapping completed", + // TODO New key - Add a translation + "item.edit.item-mapper.notifications.remove.success.head": "Removal of mapping completed", + + // "item.edit.item-mapper.tabs.browse": "Browse mapped collections", + // TODO New key - Add a translation + "item.edit.item-mapper.tabs.browse": "Browse mapped collections", + + // "item.edit.item-mapper.tabs.map": "Map new collections", + // TODO New key - Add a translation + "item.edit.item-mapper.tabs.map": "Map new collections", + + + + // "item.edit.metadata.add-button": "Add", + // TODO New key - Add a translation + "item.edit.metadata.add-button": "Add", + + // "item.edit.metadata.discard-button": "Discard", + // TODO New key - Add a translation + "item.edit.metadata.discard-button": "Discard", + + // "item.edit.metadata.edit.buttons.edit": "Edit", + // TODO New key - Add a translation + "item.edit.metadata.edit.buttons.edit": "Edit", + + // "item.edit.metadata.edit.buttons.remove": "Remove", + // TODO New key - Add a translation + "item.edit.metadata.edit.buttons.remove": "Remove", + + // "item.edit.metadata.edit.buttons.undo": "Undo changes", + // TODO New key - Add a translation + "item.edit.metadata.edit.buttons.undo": "Undo changes", + + // "item.edit.metadata.edit.buttons.unedit": "Stop editing", + // TODO New key - Add a translation + "item.edit.metadata.edit.buttons.unedit": "Stop editing", + + // "item.edit.metadata.headers.edit": "Edit", + // TODO New key - Add a translation + "item.edit.metadata.headers.edit": "Edit", + + // "item.edit.metadata.headers.field": "Field", + // TODO New key - Add a translation + "item.edit.metadata.headers.field": "Field", + + // "item.edit.metadata.headers.language": "Lang", + // TODO New key - Add a translation + "item.edit.metadata.headers.language": "Lang", + + // "item.edit.metadata.headers.value": "Value", + // TODO New key - Add a translation + "item.edit.metadata.headers.value": "Value", + + // "item.edit.metadata.metadatafield.invalid": "Please choose a valid metadata field", + // TODO New key - Add a translation + "item.edit.metadata.metadatafield.invalid": "Please choose a valid metadata field", + + // "item.edit.metadata.notifications.discarded.content": "Your changes were discarded. To reinstate your changes click the 'Undo' button", + // TODO New key - Add a translation + "item.edit.metadata.notifications.discarded.content": "Your changes were discarded. To reinstate your changes click the 'Undo' button", + + // "item.edit.metadata.notifications.discarded.title": "Changed discarded", + // TODO New key - Add a translation + "item.edit.metadata.notifications.discarded.title": "Changed discarded", + + // "item.edit.metadata.notifications.invalid.content": "Your changes were not saved. Please make sure all fields are valid before you save.", + // TODO New key - Add a translation + "item.edit.metadata.notifications.invalid.content": "Your changes were not saved. Please make sure all fields are valid before you save.", + + // "item.edit.metadata.notifications.invalid.title": "Metadata invalid", + // TODO New key - Add a translation + "item.edit.metadata.notifications.invalid.title": "Metadata invalid", + + // "item.edit.metadata.notifications.outdated.content": "The item you're currently working on has been changed by another user. Your current changes are discarded to prevent conflicts", + // TODO New key - Add a translation + "item.edit.metadata.notifications.outdated.content": "The item you're currently working on has been changed by another user. Your current changes are discarded to prevent conflicts", + + // "item.edit.metadata.notifications.outdated.title": "Changed outdated", + // TODO New key - Add a translation + "item.edit.metadata.notifications.outdated.title": "Changed outdated", + + // "item.edit.metadata.notifications.saved.content": "Your changes to this item's metadata were saved.", + // TODO New key - Add a translation + "item.edit.metadata.notifications.saved.content": "Your changes to this item's metadata were saved.", + + // "item.edit.metadata.notifications.saved.title": "Metadata saved", + // TODO New key - Add a translation + "item.edit.metadata.notifications.saved.title": "Metadata saved", + + // "item.edit.metadata.reinstate-button": "Undo", + // TODO New key - Add a translation + "item.edit.metadata.reinstate-button": "Undo", + + // "item.edit.metadata.save-button": "Save", + // TODO New key - Add a translation + "item.edit.metadata.save-button": "Save", + + + + // "item.edit.modify.overview.field": "Field", + // TODO New key - Add a translation + "item.edit.modify.overview.field": "Field", + + // "item.edit.modify.overview.language": "Language", + // TODO New key - Add a translation + "item.edit.modify.overview.language": "Language", + + // "item.edit.modify.overview.value": "Value", + // TODO New key - Add a translation + "item.edit.modify.overview.value": "Value", + + + + // "item.edit.move.cancel": "Cancel", + // TODO New key - Add a translation + "item.edit.move.cancel": "Cancel", + + // "item.edit.move.description": "Select the collection you wish to move this item to. To narrow down the list of displayed collections, you can enter a search query in the box.", + // TODO New key - Add a translation + "item.edit.move.description": "Select the collection you wish to move this item to. To narrow down the list of displayed collections, you can enter a search query in the box.", + + // "item.edit.move.error": "An error occured when attempting to move the item", + // TODO New key - Add a translation + "item.edit.move.error": "An error occured when attempting to move the item", + + // "item.edit.move.head": "Move item: {{id}}", + // TODO New key - Add a translation + "item.edit.move.head": "Move item: {{id}}", + + // "item.edit.move.inheritpolicies.checkbox": "Inherit policies", + // TODO New key - Add a translation + "item.edit.move.inheritpolicies.checkbox": "Inherit policies", + + // "item.edit.move.inheritpolicies.description": "Inherit the default policies of the destination collection", + // TODO New key - Add a translation + "item.edit.move.inheritpolicies.description": "Inherit the default policies of the destination collection", + + // "item.edit.move.move": "Move", + // TODO New key - Add a translation + "item.edit.move.move": "Move", + + // "item.edit.move.processing": "Moving...", + // TODO New key - Add a translation + "item.edit.move.processing": "Moving...", + + // "item.edit.move.search.placeholder": "Enter a search query to look for collections", + // TODO New key - Add a translation + "item.edit.move.search.placeholder": "Enter a search query to look for collections", + + // "item.edit.move.success": "The item has been moved succesfully", + // TODO New key - Add a translation + "item.edit.move.success": "The item has been moved succesfully", + + // "item.edit.move.title": "Move item", + // TODO New key - Add a translation + "item.edit.move.title": "Move item", + + + + // "item.edit.private.cancel": "Cancel", + // TODO New key - Add a translation + "item.edit.private.cancel": "Cancel", + + // "item.edit.private.confirm": "Make it Private", + // TODO New key - Add a translation + "item.edit.private.confirm": "Make it Private", + + // "item.edit.private.description": "Are you sure this item should be made private in the archive?", + // TODO New key - Add a translation + "item.edit.private.description": "Are you sure this item should be made private in the archive?", + + // "item.edit.private.error": "An error occurred while making the item private", + // TODO New key - Add a translation + "item.edit.private.error": "An error occurred while making the item private", + + // "item.edit.private.header": "Make item private: {{ id }}", + // TODO New key - Add a translation + "item.edit.private.header": "Make item private: {{ id }}", + + // "item.edit.private.success": "The item is now private", + // TODO New key - Add a translation + "item.edit.private.success": "The item is now private", + + + + // "item.edit.public.cancel": "Cancel", + // TODO New key - Add a translation + "item.edit.public.cancel": "Cancel", + + // "item.edit.public.confirm": "Make it Public", + // TODO New key - Add a translation + "item.edit.public.confirm": "Make it Public", + + // "item.edit.public.description": "Are you sure this item should be made public in the archive?", + // TODO New key - Add a translation + "item.edit.public.description": "Are you sure this item should be made public in the archive?", + + // "item.edit.public.error": "An error occurred while making the item public", + // TODO New key - Add a translation + "item.edit.public.error": "An error occurred while making the item public", + + // "item.edit.public.header": "Make item public: {{ id }}", + // TODO New key - Add a translation + "item.edit.public.header": "Make item public: {{ id }}", + + // "item.edit.public.success": "The item is now public", + // TODO New key - Add a translation + "item.edit.public.success": "The item is now public", + + + + // "item.edit.reinstate.cancel": "Cancel", + // TODO New key - Add a translation + "item.edit.reinstate.cancel": "Cancel", + + // "item.edit.reinstate.confirm": "Reinstate", + // TODO New key - Add a translation + "item.edit.reinstate.confirm": "Reinstate", + + // "item.edit.reinstate.description": "Are you sure this item should be reinstated to the archive?", + // TODO New key - Add a translation + "item.edit.reinstate.description": "Are you sure this item should be reinstated to the archive?", + + // "item.edit.reinstate.error": "An error occurred while reinstating the item", + // TODO New key - Add a translation + "item.edit.reinstate.error": "An error occurred while reinstating the item", + + // "item.edit.reinstate.header": "Reinstate item: {{ id }}", + // TODO New key - Add a translation + "item.edit.reinstate.header": "Reinstate item: {{ id }}", + + // "item.edit.reinstate.success": "The item was reinstated successfully", + // TODO New key - Add a translation + "item.edit.reinstate.success": "The item was reinstated successfully", + + + + // "item.edit.relationships.discard-button": "Discard", + // TODO New key - Add a translation + "item.edit.relationships.discard-button": "Discard", + + // "item.edit.relationships.edit.buttons.remove": "Remove", + // TODO New key - Add a translation + "item.edit.relationships.edit.buttons.remove": "Remove", + + // "item.edit.relationships.edit.buttons.undo": "Undo changes", + // TODO New key - Add a translation + "item.edit.relationships.edit.buttons.undo": "Undo changes", + + // "item.edit.relationships.notifications.discarded.content": "Your changes were discarded. To reinstate your changes click the 'Undo' button", + // TODO New key - Add a translation + "item.edit.relationships.notifications.discarded.content": "Your changes were discarded. To reinstate your changes click the 'Undo' button", + + // "item.edit.relationships.notifications.discarded.title": "Changes discarded", + // TODO New key - Add a translation + "item.edit.relationships.notifications.discarded.title": "Changes discarded", + + // "item.edit.relationships.notifications.failed.title": "Error deleting relationship", + // TODO New key - Add a translation + "item.edit.relationships.notifications.failed.title": "Error deleting relationship", + + // "item.edit.relationships.notifications.outdated.content": "The item you're currently working on has been changed by another user. Your current changes are discarded to prevent conflicts", + // TODO New key - Add a translation + "item.edit.relationships.notifications.outdated.content": "The item you're currently working on has been changed by another user. Your current changes are discarded to prevent conflicts", + + // "item.edit.relationships.notifications.outdated.title": "Changes outdated", + // TODO New key - Add a translation + "item.edit.relationships.notifications.outdated.title": "Changes outdated", + + // "item.edit.relationships.notifications.saved.content": "Your changes to this item's relationships were saved.", + // TODO New key - Add a translation + "item.edit.relationships.notifications.saved.content": "Your changes to this item's relationships were saved.", + + // "item.edit.relationships.notifications.saved.title": "Relationships saved", + // TODO New key - Add a translation + "item.edit.relationships.notifications.saved.title": "Relationships saved", + + // "item.edit.relationships.reinstate-button": "Undo", + // TODO New key - Add a translation + "item.edit.relationships.reinstate-button": "Undo", + + // "item.edit.relationships.save-button": "Save", + // TODO New key - Add a translation + "item.edit.relationships.save-button": "Save", + + + + // "item.edit.tabs.bitstreams.head": "Item Bitstreams", + // TODO New key - Add a translation + "item.edit.tabs.bitstreams.head": "Item Bitstreams", + + // "item.edit.tabs.bitstreams.title": "Item Edit - Bitstreams", + // TODO New key - Add a translation + "item.edit.tabs.bitstreams.title": "Item Edit - Bitstreams", + + // "item.edit.tabs.curate.head": "Curate", + // TODO New key - Add a translation + "item.edit.tabs.curate.head": "Curate", + + // "item.edit.tabs.curate.title": "Item Edit - Curate", + // TODO New key - Add a translation + "item.edit.tabs.curate.title": "Item Edit - Curate", + + // "item.edit.tabs.metadata.head": "Item Metadata", + // TODO New key - Add a translation + "item.edit.tabs.metadata.head": "Item Metadata", + + // "item.edit.tabs.metadata.title": "Item Edit - Metadata", + // TODO New key - Add a translation + "item.edit.tabs.metadata.title": "Item Edit - Metadata", + + // "item.edit.tabs.relationships.head": "Item Relationships", + // TODO New key - Add a translation + "item.edit.tabs.relationships.head": "Item Relationships", + + // "item.edit.tabs.relationships.title": "Item Edit - Relationships", + // TODO New key - Add a translation + "item.edit.tabs.relationships.title": "Item Edit - Relationships", + + // "item.edit.tabs.status.buttons.authorizations.button": "Authorizations...", + // TODO New key - Add a translation + "item.edit.tabs.status.buttons.authorizations.button": "Authorizations...", + + // "item.edit.tabs.status.buttons.authorizations.label": "Edit item's authorization policies", + // TODO New key - Add a translation + "item.edit.tabs.status.buttons.authorizations.label": "Edit item's authorization policies", + + // "item.edit.tabs.status.buttons.delete.button": "Permanently delete", + // TODO New key - Add a translation + "item.edit.tabs.status.buttons.delete.button": "Permanently delete", + + // "item.edit.tabs.status.buttons.delete.label": "Completely expunge item", + // TODO New key - Add a translation + "item.edit.tabs.status.buttons.delete.label": "Completely expunge item", + + // "item.edit.tabs.status.buttons.mappedCollections.button": "Mapped collections", + // TODO New key - Add a translation + "item.edit.tabs.status.buttons.mappedCollections.button": "Mapped collections", + + // "item.edit.tabs.status.buttons.mappedCollections.label": "Manage mapped collections", + // TODO New key - Add a translation + "item.edit.tabs.status.buttons.mappedCollections.label": "Manage mapped collections", + + // "item.edit.tabs.status.buttons.move.button": "Move...", + // TODO New key - Add a translation + "item.edit.tabs.status.buttons.move.button": "Move...", + + // "item.edit.tabs.status.buttons.move.label": "Move item to another collection", + // TODO New key - Add a translation + "item.edit.tabs.status.buttons.move.label": "Move item to another collection", + + // "item.edit.tabs.status.buttons.private.button": "Make it private...", + // TODO New key - Add a translation + "item.edit.tabs.status.buttons.private.button": "Make it private...", + + // "item.edit.tabs.status.buttons.private.label": "Make item private", + // TODO New key - Add a translation + "item.edit.tabs.status.buttons.private.label": "Make item private", + + // "item.edit.tabs.status.buttons.public.button": "Make it public...", + // TODO New key - Add a translation + "item.edit.tabs.status.buttons.public.button": "Make it public...", + + // "item.edit.tabs.status.buttons.public.label": "Make item public", + // TODO New key - Add a translation + "item.edit.tabs.status.buttons.public.label": "Make item public", + + // "item.edit.tabs.status.buttons.reinstate.button": "Reinstate...", + // TODO New key - Add a translation + "item.edit.tabs.status.buttons.reinstate.button": "Reinstate...", + + // "item.edit.tabs.status.buttons.reinstate.label": "Reinstate item into the repository", + // TODO New key - Add a translation + "item.edit.tabs.status.buttons.reinstate.label": "Reinstate item into the repository", + + // "item.edit.tabs.status.buttons.withdraw.button": "Withdraw...", + // TODO New key - Add a translation + "item.edit.tabs.status.buttons.withdraw.button": "Withdraw...", + + // "item.edit.tabs.status.buttons.withdraw.label": "Withdraw item from the repository", + // TODO New key - Add a translation + "item.edit.tabs.status.buttons.withdraw.label": "Withdraw item from the repository", + + // "item.edit.tabs.status.description": "Welcome to the item management page. From here you can withdraw, reinstate, move or delete the item. You may also update or add new metadata / bitstreams on the other tabs.", + // TODO New key - Add a translation + "item.edit.tabs.status.description": "Welcome to the item management page. From here you can withdraw, reinstate, move or delete the item. You may also update or add new metadata / bitstreams on the other tabs.", + + // "item.edit.tabs.status.head": "Item Status", + // TODO New key - Add a translation + "item.edit.tabs.status.head": "Item Status", + + // "item.edit.tabs.status.labels.handle": "Handle", + // TODO New key - Add a translation + "item.edit.tabs.status.labels.handle": "Handle", + + // "item.edit.tabs.status.labels.id": "Item Internal ID", + // TODO New key - Add a translation + "item.edit.tabs.status.labels.id": "Item Internal ID", + + // "item.edit.tabs.status.labels.itemPage": "Item Page", + // TODO New key - Add a translation + "item.edit.tabs.status.labels.itemPage": "Item Page", + + // "item.edit.tabs.status.labels.lastModified": "Last Modified", + // TODO New key - Add a translation + "item.edit.tabs.status.labels.lastModified": "Last Modified", + + // "item.edit.tabs.status.title": "Item Edit - Status", + // TODO New key - Add a translation + "item.edit.tabs.status.title": "Item Edit - Status", + + // "item.edit.tabs.view.head": "View Item", + // TODO New key - Add a translation + "item.edit.tabs.view.head": "View Item", + + // "item.edit.tabs.view.title": "Item Edit - View", + // TODO New key - Add a translation + "item.edit.tabs.view.title": "Item Edit - View", + + + + // "item.edit.withdraw.cancel": "Cancel", + // TODO New key - Add a translation + "item.edit.withdraw.cancel": "Cancel", + + // "item.edit.withdraw.confirm": "Withdraw", + // TODO New key - Add a translation + "item.edit.withdraw.confirm": "Withdraw", + + // "item.edit.withdraw.description": "Are you sure this item should be withdrawn from the archive?", + // TODO New key - Add a translation + "item.edit.withdraw.description": "Are you sure this item should be withdrawn from the archive?", + + // "item.edit.withdraw.error": "An error occurred while withdrawing the item", + // TODO New key - Add a translation + "item.edit.withdraw.error": "An error occurred while withdrawing the item", + + // "item.edit.withdraw.header": "Withdraw item: {{ id }}", + // TODO New key - Add a translation + "item.edit.withdraw.header": "Withdraw item: {{ id }}", + + // "item.edit.withdraw.success": "The item was withdrawn successfully", + // TODO New key - Add a translation + "item.edit.withdraw.success": "The item was withdrawn successfully", + + + + // "item.page.abstract": "Abstract", "item.page.abstract": "Abstrakt", + + // "item.page.author": "Authors", "item.page.author": "Autor", + + // "item.page.citation": "Citation", + // TODO New key - Add a translation + "item.page.citation": "Citation", + + // "item.page.collections": "Collections", "item.page.collections": "Kolekce", + + // "item.page.date": "Date", "item.page.date": "Datum", + + // "item.page.files": "Files", "item.page.files": "Soubory", - "item.page.filesection.description": "Popis:", + + // "item.page.filesection.description": "Description:", + // TODO New key - Add a translation + "item.page.filesection.description": "Description:", + + // "item.page.filesection.download": "Download", "item.page.filesection.download": "Stáhnout", - "item.page.filesection.format": "Formát:", - "item.page.filesection.name": "Název:", - "item.page.filesection.size": "Velikost:", + + // "item.page.filesection.format": "Format:", + // TODO New key - Add a translation + "item.page.filesection.format": "Format:", + + // "item.page.filesection.name": "Name:", + // TODO New key - Add a translation + "item.page.filesection.name": "Name:", + + // "item.page.filesection.size": "Size:", + // TODO New key - Add a translation + "item.page.filesection.size": "Size:", + + // "item.page.journal.search.title": "Articles in this journal", + // TODO New key - Add a translation + "item.page.journal.search.title": "Articles in this journal", + + // "item.page.link.full": "Full item page", "item.page.link.full": "Úplný záznam", + + // "item.page.link.simple": "Simple item page", "item.page.link.simple": "Minimální záznam", + + // "item.page.person.search.title": "Articles by this author", + // TODO New key - Add a translation + "item.page.person.search.title": "Articles by this author", + + // "item.page.related-items.view-more": "View more", + // TODO New key - Add a translation + "item.page.related-items.view-more": "View more", + + // "item.page.related-items.view-less": "View less", + // TODO New key - Add a translation + "item.page.related-items.view-less": "View less", + + // "item.page.subject": "Keywords", + // TODO New key - Add a translation + "item.page.subject": "Keywords", + + // "item.page.uri": "URI", "item.page.uri": "URI", - + + + + // "item.select.confirm": "Confirm selected", + // TODO New key - Add a translation + "item.select.confirm": "Confirm selected", + + // "item.select.empty": "No items to show", + // TODO New key - Add a translation + "item.select.empty": "No items to show", + + // "item.select.table.author": "Author", + // TODO New key - Add a translation + "item.select.table.author": "Author", + + // "item.select.table.collection": "Collection", + // TODO New key - Add a translation + "item.select.table.collection": "Collection", + + // "item.select.table.title": "Title", + // TODO New key - Add a translation + "item.select.table.title": "Title", + + + + // "journal.listelement.badge": "Journal", + // TODO New key - Add a translation + "journal.listelement.badge": "Journal", + + // "journal.page.description": "Description", + // TODO New key - Add a translation + "journal.page.description": "Description", + + // "journal.page.editor": "Editor-in-Chief", + // TODO New key - Add a translation + "journal.page.editor": "Editor-in-Chief", + + // "journal.page.issn": "ISSN", + // TODO New key - Add a translation + "journal.page.issn": "ISSN", + + // "journal.page.publisher": "Publisher", + // TODO New key - Add a translation + "journal.page.publisher": "Publisher", + + // "journal.page.titleprefix": "Journal: ", + // TODO New key - Add a translation + "journal.page.titleprefix": "Journal: ", + + // "journal.search.results.head": "Journal Search Results", + // TODO New key - Add a translation + "journal.search.results.head": "Journal Search Results", + + // "journal.search.title": "DSpace Angular :: Journal Search", + // TODO New key - Add a translation + "journal.search.title": "DSpace Angular :: Journal Search", + + + + // "journalissue.listelement.badge": "Journal Issue", + // TODO New key - Add a translation + "journalissue.listelement.badge": "Journal Issue", + + // "journalissue.page.description": "Description", + // TODO New key - Add a translation + "journalissue.page.description": "Description", + + // "journalissue.page.issuedate": "Issue Date", + // TODO New key - Add a translation + "journalissue.page.issuedate": "Issue Date", + + // "journalissue.page.journal-issn": "Journal ISSN", + // TODO New key - Add a translation + "journalissue.page.journal-issn": "Journal ISSN", + + // "journalissue.page.journal-title": "Journal Title", + // TODO New key - Add a translation + "journalissue.page.journal-title": "Journal Title", + + // "journalissue.page.keyword": "Keywords", + // TODO New key - Add a translation + "journalissue.page.keyword": "Keywords", + + // "journalissue.page.number": "Number", + // TODO New key - Add a translation + "journalissue.page.number": "Number", + + // "journalissue.page.titleprefix": "Journal Issue: ", + // TODO New key - Add a translation + "journalissue.page.titleprefix": "Journal Issue: ", + + + + // "journalvolume.listelement.badge": "Journal Volume", + // TODO New key - Add a translation + "journalvolume.listelement.badge": "Journal Volume", + + // "journalvolume.page.description": "Description", + // TODO New key - Add a translation + "journalvolume.page.description": "Description", + + // "journalvolume.page.issuedate": "Issue Date", + // TODO New key - Add a translation + "journalvolume.page.issuedate": "Issue Date", + + // "journalvolume.page.titleprefix": "Journal Volume: ", + // TODO New key - Add a translation + "journalvolume.page.titleprefix": "Journal Volume: ", + + // "journalvolume.page.volume": "Volume", + // TODO New key - Add a translation + "journalvolume.page.volume": "Volume", + + + + // "loading.browse-by": "Loading items...", "loading.browse-by": "Načítají se záznamy...", + + // "loading.browse-by-page": "Loading page...", + // TODO New key - Add a translation + "loading.browse-by-page": "Loading page...", + + // "loading.collection": "Loading collection...", "loading.collection": "Načítá se kolekce...", + + // "loading.collections": "Loading collections...", + // TODO New key - Add a translation + "loading.collections": "Loading collections...", + + // "loading.community": "Loading community...", "loading.community": "Načítá se komunita...", + + // "loading.default": "Loading...", "loading.default": "Načítá se...", + + // "loading.item": "Loading item...", "loading.item": "Načítá se záznam...", + + // "loading.items": "Loading items...", + // TODO New key - Add a translation + "loading.items": "Loading items...", + + // "loading.mydspace-results": "Loading items...", + // TODO New key - Add a translation + "loading.mydspace-results": "Loading items...", + + // "loading.objects": "Loading...", "loading.objects": "Načítá se...", + + // "loading.recent-submissions": "Loading recent submissions...", "loading.recent-submissions": "Načítají se poslední příspěvky...", + + // "loading.search-results": "Loading search results...", "loading.search-results": "Načítají se výsledky hledání...", + + // "loading.sub-collections": "Loading sub-collections...", "loading.sub-collections": "Načítají se subkolekce...", + + // "loading.sub-communities": "Loading sub-communities...", + // TODO New key - Add a translation + "loading.sub-communities": "Loading sub-communities...", + + // "loading.top-level-communities": "Loading top-level communities...", "loading.top-level-communities": "Načítají se komunity nejvyšší úrovně...", - + + + + // "login.form.email": "Email address", "login.form.email": "E-mailová adresa", + + // "login.form.forgot-password": "Have you forgotten your password?", "login.form.forgot-password": "Zapomněli jste své heslo?", + + // "login.form.header": "Please log in to DSpace", "login.form.header": "Prosím, přihlaste se do DSpace", + + // "login.form.new-user": "New user? Click here to register.", "login.form.new-user": "Nový uživatel? Zaregistrujte se kliknutím sem.", + + // "login.form.password": "Password", "login.form.password": "Heslo", + + // "login.form.submit": "Log in", "login.form.submit": "Přihlásit se", + + // "login.title": "Login", "login.title": "Přihlásit se", - + + + + // "logout.form.header": "Log out from DSpace", "logout.form.header": "Odhlásit se z DSpace", + + // "logout.form.submit": "Log out", "logout.form.submit": "Odhlásit se", + + // "logout.title": "Logout", "logout.title": "Odhlásit se", - - "nav.home": "Domů", + + + + // "menu.header.admin": "Admin", + // TODO New key - Add a translation + "menu.header.admin": "Admin", + + // "menu.header.image.logo": "Repository logo", + // TODO New key - Add a translation + "menu.header.image.logo": "Repository logo", + + + + // "menu.section.access_control": "Access Control", + // TODO New key - Add a translation + "menu.section.access_control": "Access Control", + + // "menu.section.access_control_authorizations": "Authorizations", + // TODO New key - Add a translation + "menu.section.access_control_authorizations": "Authorizations", + + // "menu.section.access_control_groups": "Groups", + // TODO New key - Add a translation + "menu.section.access_control_groups": "Groups", + + // "menu.section.access_control_people": "People", + // TODO New key - Add a translation + "menu.section.access_control_people": "People", + + + + // "menu.section.browse_community": "This Community", + // TODO New key - Add a translation + "menu.section.browse_community": "This Community", + + // "menu.section.browse_community_by_author": "By Author", + // TODO New key - Add a translation + "menu.section.browse_community_by_author": "By Author", + + // "menu.section.browse_community_by_issue_date": "By Issue Date", + // TODO New key - Add a translation + "menu.section.browse_community_by_issue_date": "By Issue Date", + + // "menu.section.browse_community_by_title": "By Title", + // TODO New key - Add a translation + "menu.section.browse_community_by_title": "By Title", + + // "menu.section.browse_global": "All of DSpace", + // TODO New key - Add a translation + "menu.section.browse_global": "All of DSpace", + + // "menu.section.browse_global_by_author": "By Author", + // TODO New key - Add a translation + "menu.section.browse_global_by_author": "By Author", + + // "menu.section.browse_global_by_dateissued": "By Issue Date", + // TODO New key - Add a translation + "menu.section.browse_global_by_dateissued": "By Issue Date", + + // "menu.section.browse_global_by_subject": "By Subject", + // TODO New key - Add a translation + "menu.section.browse_global_by_subject": "By Subject", + + // "menu.section.browse_global_by_title": "By Title", + // TODO New key - Add a translation + "menu.section.browse_global_by_title": "By Title", + + // "menu.section.browse_global_communities_and_collections": "Communities & Collections", + // TODO New key - Add a translation + "menu.section.browse_global_communities_and_collections": "Communities & Collections", + + + + // "menu.section.control_panel": "Control Panel", + // TODO New key - Add a translation + "menu.section.control_panel": "Control Panel", + + // "menu.section.curation_task": "Curation Task", + // TODO New key - Add a translation + "menu.section.curation_task": "Curation Task", + + + + // "menu.section.edit": "Edit", + // TODO New key - Add a translation + "menu.section.edit": "Edit", + + // "menu.section.edit_collection": "Collection", + // TODO New key - Add a translation + "menu.section.edit_collection": "Collection", + + // "menu.section.edit_community": "Community", + // TODO New key - Add a translation + "menu.section.edit_community": "Community", + + // "menu.section.edit_item": "Item", + // TODO New key - Add a translation + "menu.section.edit_item": "Item", + + + + // "menu.section.export": "Export", + // TODO New key - Add a translation + "menu.section.export": "Export", + + // "menu.section.export_collection": "Collection", + // TODO New key - Add a translation + "menu.section.export_collection": "Collection", + + // "menu.section.export_community": "Community", + // TODO New key - Add a translation + "menu.section.export_community": "Community", + + // "menu.section.export_item": "Item", + // TODO New key - Add a translation + "menu.section.export_item": "Item", + + // "menu.section.export_metadata": "Metadata", + // TODO New key - Add a translation + "menu.section.export_metadata": "Metadata", + + + + // "menu.section.find": "Find", + // TODO New key - Add a translation + "menu.section.find": "Find", + + // "menu.section.find_items": "Items", + // TODO New key - Add a translation + "menu.section.find_items": "Items", + + // "menu.section.find_private_items": "Private Items", + // TODO New key - Add a translation + "menu.section.find_private_items": "Private Items", + + // "menu.section.find_withdrawn_items": "Withdrawn Items", + // TODO New key - Add a translation + "menu.section.find_withdrawn_items": "Withdrawn Items", + + + + // "menu.section.icon.access_control": "Access Control menu section", + // TODO New key - Add a translation + "menu.section.icon.access_control": "Access Control menu section", + + // "menu.section.icon.control_panel": "Control Panel menu section", + // TODO New key - Add a translation + "menu.section.icon.control_panel": "Control Panel menu section", + + // "menu.section.icon.curation_task": "Curation Task menu section", + // TODO New key - Add a translation + "menu.section.icon.curation_task": "Curation Task menu section", + + // "menu.section.icon.edit": "Edit menu section", + // TODO New key - Add a translation + "menu.section.icon.edit": "Edit menu section", + + // "menu.section.icon.export": "Export menu section", + // TODO New key - Add a translation + "menu.section.icon.export": "Export menu section", + + // "menu.section.icon.find": "Find menu section", + // TODO New key - Add a translation + "menu.section.icon.find": "Find menu section", + + // "menu.section.icon.import": "Import menu section", + // TODO New key - Add a translation + "menu.section.icon.import": "Import menu section", + + // "menu.section.icon.new": "New menu section", + // TODO New key - Add a translation + "menu.section.icon.new": "New menu section", + + // "menu.section.icon.pin": "Pin sidebar", + // TODO New key - Add a translation + "menu.section.icon.pin": "Pin sidebar", + + // "menu.section.icon.registries": "Registries menu section", + // TODO New key - Add a translation + "menu.section.icon.registries": "Registries menu section", + + // "menu.section.icon.statistics_task": "Statistics Task menu section", + // TODO New key - Add a translation + "menu.section.icon.statistics_task": "Statistics Task menu section", + + // "menu.section.icon.unpin": "Unpin sidebar", + // TODO New key - Add a translation + "menu.section.icon.unpin": "Unpin sidebar", + + + + // "menu.section.import": "Import", + // TODO New key - Add a translation + "menu.section.import": "Import", + + // "menu.section.import_batch": "Batch Import (ZIP)", + // TODO New key - Add a translation + "menu.section.import_batch": "Batch Import (ZIP)", + + // "menu.section.import_metadata": "Metadata", + // TODO New key - Add a translation + "menu.section.import_metadata": "Metadata", + + + + // "menu.section.new": "New", + // TODO New key - Add a translation + "menu.section.new": "New", + + // "menu.section.new_collection": "Collection", + // TODO New key - Add a translation + "menu.section.new_collection": "Collection", + + // "menu.section.new_community": "Community", + // TODO New key - Add a translation + "menu.section.new_community": "Community", + + // "menu.section.new_item": "Item", + // TODO New key - Add a translation + "menu.section.new_item": "Item", + + // "menu.section.new_item_version": "Item Version", + // TODO New key - Add a translation + "menu.section.new_item_version": "Item Version", + + + + // "menu.section.pin": "Pin sidebar", + // TODO New key - Add a translation + "menu.section.pin": "Pin sidebar", + + // "menu.section.unpin": "Unpin sidebar", + // TODO New key - Add a translation + "menu.section.unpin": "Unpin sidebar", + + + + // "menu.section.registries": "Registries", + // TODO New key - Add a translation + "menu.section.registries": "Registries", + + // "menu.section.registries_format": "Format", + // TODO New key - Add a translation + "menu.section.registries_format": "Format", + + // "menu.section.registries_metadata": "Metadata", + // TODO New key - Add a translation + "menu.section.registries_metadata": "Metadata", + + + + // "menu.section.statistics": "Statistics", + // TODO New key - Add a translation + "menu.section.statistics": "Statistics", + + // "menu.section.statistics_task": "Statistics Task", + // TODO New key - Add a translation + "menu.section.statistics_task": "Statistics Task", + + + + // "menu.section.toggle.access_control": "Toggle Access Control section", + // TODO New key - Add a translation + "menu.section.toggle.access_control": "Toggle Access Control section", + + // "menu.section.toggle.control_panel": "Toggle Control Panel section", + // TODO New key - Add a translation + "menu.section.toggle.control_panel": "Toggle Control Panel section", + + // "menu.section.toggle.curation_task": "Toggle Curation Task section", + // TODO New key - Add a translation + "menu.section.toggle.curation_task": "Toggle Curation Task section", + + // "menu.section.toggle.edit": "Toggle Edit section", + // TODO New key - Add a translation + "menu.section.toggle.edit": "Toggle Edit section", + + // "menu.section.toggle.export": "Toggle Export section", + // TODO New key - Add a translation + "menu.section.toggle.export": "Toggle Export section", + + // "menu.section.toggle.find": "Toggle Find section", + // TODO New key - Add a translation + "menu.section.toggle.find": "Toggle Find section", + + // "menu.section.toggle.import": "Toggle Import section", + // TODO New key - Add a translation + "menu.section.toggle.import": "Toggle Import section", + + // "menu.section.toggle.new": "Toggle New section", + // TODO New key - Add a translation + "menu.section.toggle.new": "Toggle New section", + + // "menu.section.toggle.registries": "Toggle Registries section", + // TODO New key - Add a translation + "menu.section.toggle.registries": "Toggle Registries section", + + // "menu.section.toggle.statistics_task": "Toggle Statistics Task section", + // TODO New key - Add a translation + "menu.section.toggle.statistics_task": "Toggle Statistics Task section", + + + + // "mydspace.description": "", + // TODO New key - Add a translation + "mydspace.description": "", + + // "mydspace.general.text-here": "HERE", + // TODO New key - Add a translation + "mydspace.general.text-here": "HERE", + + // "mydspace.messages.controller-help": "Select this option to send a message to item's submitter.", + // TODO New key - Add a translation + "mydspace.messages.controller-help": "Select this option to send a message to item's submitter.", + + // "mydspace.messages.description-placeholder": "Insert your message here...", + // TODO New key - Add a translation + "mydspace.messages.description-placeholder": "Insert your message here...", + + // "mydspace.messages.hide-msg": "Hide message", + // TODO New key - Add a translation + "mydspace.messages.hide-msg": "Hide message", + + // "mydspace.messages.mark-as-read": "Mark as read", + // TODO New key - Add a translation + "mydspace.messages.mark-as-read": "Mark as read", + + // "mydspace.messages.mark-as-unread": "Mark as unread", + // TODO New key - Add a translation + "mydspace.messages.mark-as-unread": "Mark as unread", + + // "mydspace.messages.no-content": "No content.", + // TODO New key - Add a translation + "mydspace.messages.no-content": "No content.", + + // "mydspace.messages.no-messages": "No messages yet.", + // TODO New key - Add a translation + "mydspace.messages.no-messages": "No messages yet.", + + // "mydspace.messages.send-btn": "Send", + // TODO New key - Add a translation + "mydspace.messages.send-btn": "Send", + + // "mydspace.messages.show-msg": "Show message", + // TODO New key - Add a translation + "mydspace.messages.show-msg": "Show message", + + // "mydspace.messages.subject-placeholder": "Subject...", + // TODO New key - Add a translation + "mydspace.messages.subject-placeholder": "Subject...", + + // "mydspace.messages.submitter-help": "Select this option to send a message to controller.", + // TODO New key - Add a translation + "mydspace.messages.submitter-help": "Select this option to send a message to controller.", + + // "mydspace.messages.title": "Messages", + // TODO New key - Add a translation + "mydspace.messages.title": "Messages", + + // "mydspace.messages.to": "To", + // TODO New key - Add a translation + "mydspace.messages.to": "To", + + // "mydspace.new-submission": "New submission", + // TODO New key - Add a translation + "mydspace.new-submission": "New submission", + + // "mydspace.results.head": "Your submissions", + // TODO New key - Add a translation + "mydspace.results.head": "Your submissions", + + // "mydspace.results.no-abstract": "No Abstract", + // TODO New key - Add a translation + "mydspace.results.no-abstract": "No Abstract", + + // "mydspace.results.no-authors": "No Authors", + // TODO New key - Add a translation + "mydspace.results.no-authors": "No Authors", + + // "mydspace.results.no-collections": "No Collections", + // TODO New key - Add a translation + "mydspace.results.no-collections": "No Collections", + + // "mydspace.results.no-date": "No Date", + // TODO New key - Add a translation + "mydspace.results.no-date": "No Date", + + // "mydspace.results.no-files": "No Files", + // TODO New key - Add a translation + "mydspace.results.no-files": "No Files", + + // "mydspace.results.no-results": "There were no items to show", + // TODO New key - Add a translation + "mydspace.results.no-results": "There were no items to show", + + // "mydspace.results.no-title": "No title", + // TODO New key - Add a translation + "mydspace.results.no-title": "No title", + + // "mydspace.results.no-uri": "No Uri", + // TODO New key - Add a translation + "mydspace.results.no-uri": "No Uri", + + // "mydspace.show.workflow": "All tasks", + // TODO New key - Add a translation + "mydspace.show.workflow": "All tasks", + + // "mydspace.show.workspace": "Your Submissions", + // TODO New key - Add a translation + "mydspace.show.workspace": "Your Submissions", + + // "mydspace.status.archived": "Archived", + // TODO New key - Add a translation + "mydspace.status.archived": "Archived", + + // "mydspace.status.validation": "Validation", + // TODO New key - Add a translation + "mydspace.status.validation": "Validation", + + // "mydspace.status.waiting-for-controller": "Waiting for controller", + // TODO New key - Add a translation + "mydspace.status.waiting-for-controller": "Waiting for controller", + + // "mydspace.status.workflow": "Workflow", + // TODO New key - Add a translation + "mydspace.status.workflow": "Workflow", + + // "mydspace.status.workspace": "Workspace", + // TODO New key - Add a translation + "mydspace.status.workspace": "Workspace", + + // "mydspace.title": "MyDSpace", + // TODO New key - Add a translation + "mydspace.title": "MyDSpace", + + // "mydspace.upload.upload-failed": "Error creating new workspace. Please verify the content uploaded before retry.", + // TODO New key - Add a translation + "mydspace.upload.upload-failed": "Error creating new workspace. Please verify the content uploaded before retry.", + + // "mydspace.upload.upload-multiple-successful": "{{qty}} new workspace items created.", + // TODO New key - Add a translation + "mydspace.upload.upload-multiple-successful": "{{qty}} new workspace items created.", + + // "mydspace.upload.upload-successful": "New workspace item created. Click {{here}} for edit it.", + // TODO New key - Add a translation + "mydspace.upload.upload-successful": "New workspace item created. Click {{here}} for edit it.", + + // "mydspace.view-btn": "View", + // TODO New key - Add a translation + "mydspace.view-btn": "View", + + + + // "nav.browse.header": "All of DSpace", + // TODO New key - Add a translation + "nav.browse.header": "All of DSpace", + + // "nav.community-browse.header": "By Community", + // TODO New key - Add a translation + "nav.community-browse.header": "By Community", + + // "nav.language": "Language switch", + // TODO New key - Add a translation + "nav.language": "Language switch", + + // "nav.login": "Log In", "nav.login": "Přihlásit se", + + // "nav.logout": "Log Out", "nav.logout": "Odhlásit se", - + + // "nav.mydspace": "MyDSpace", + // TODO New key - Add a translation + "nav.mydspace": "MyDSpace", + + // "nav.search": "Search", + // TODO New key - Add a translation + "nav.search": "Search", + + // "nav.statistics.header": "Statistics", + // TODO New key - Add a translation + "nav.statistics.header": "Statistics", + + + + // "orgunit.listelement.badge": "Organizational Unit", + // TODO New key - Add a translation + "orgunit.listelement.badge": "Organizational Unit", + + // "orgunit.page.city": "City", + // TODO New key - Add a translation + "orgunit.page.city": "City", + + // "orgunit.page.country": "Country", + // TODO New key - Add a translation + "orgunit.page.country": "Country", + + // "orgunit.page.dateestablished": "Date established", + // TODO New key - Add a translation + "orgunit.page.dateestablished": "Date established", + + // "orgunit.page.description": "Description", + // TODO New key - Add a translation + "orgunit.page.description": "Description", + + // "orgunit.page.id": "ID", + // TODO New key - Add a translation + "orgunit.page.id": "ID", + + // "orgunit.page.titleprefix": "Organizational Unit: ", + // TODO New key - Add a translation + "orgunit.page.titleprefix": "Organizational Unit: ", + + + + // "pagination.results-per-page": "Results Per Page", "pagination.results-per-page": "Výsledků na stránku", + + // "pagination.showing.detail": "{{ range }} of {{ total }}", "pagination.showing.detail": "{{ range }} z {{ total }}", + + // "pagination.showing.label": "Now showing ", "pagination.showing.label": "Zobrazují se záznamy ", + + // "pagination.sort-direction": "Sort Options", "pagination.sort-direction": "Seřazení", - + + + + // "person.listelement.badge": "Person", + // TODO New key - Add a translation + "person.listelement.badge": "Person", + + // "person.page.birthdate": "Birth Date", + // TODO New key - Add a translation + "person.page.birthdate": "Birth Date", + + // "person.page.email": "Email Address", + // TODO New key - Add a translation + "person.page.email": "Email Address", + + // "person.page.firstname": "First Name", + // TODO New key - Add a translation + "person.page.firstname": "First Name", + + // "person.page.jobtitle": "Job Title", + // TODO New key - Add a translation + "person.page.jobtitle": "Job Title", + + // "person.page.lastname": "Last Name", + // TODO New key - Add a translation + "person.page.lastname": "Last Name", + + // "person.page.link.full": "Show all metadata", + // TODO New key - Add a translation + "person.page.link.full": "Show all metadata", + + // "person.page.orcid": "ORCID", + // TODO New key - Add a translation + "person.page.orcid": "ORCID", + + // "person.page.staffid": "Staff ID", + // TODO New key - Add a translation + "person.page.staffid": "Staff ID", + + // "person.page.titleprefix": "Person: ", + // TODO New key - Add a translation + "person.page.titleprefix": "Person: ", + + // "person.search.results.head": "Person Search Results", + // TODO New key - Add a translation + "person.search.results.head": "Person Search Results", + + // "person.search.title": "DSpace Angular :: Person Search", + // TODO New key - Add a translation + "person.search.title": "DSpace Angular :: Person Search", + + + + // "project.listelement.badge": "Research Project", + // TODO New key - Add a translation + "project.listelement.badge": "Research Project", + + // "project.page.contributor": "Contributors", + // TODO New key - Add a translation + "project.page.contributor": "Contributors", + + // "project.page.description": "Description", + // TODO New key - Add a translation + "project.page.description": "Description", + + // "project.page.expectedcompletion": "Expected Completion", + // TODO New key - Add a translation + "project.page.expectedcompletion": "Expected Completion", + + // "project.page.funder": "Funders", + // TODO New key - Add a translation + "project.page.funder": "Funders", + + // "project.page.id": "ID", + // TODO New key - Add a translation + "project.page.id": "ID", + + // "project.page.keyword": "Keywords", + // TODO New key - Add a translation + "project.page.keyword": "Keywords", + + // "project.page.status": "Status", + // TODO New key - Add a translation + "project.page.status": "Status", + + // "project.page.titleprefix": "Research Project: ", + // TODO New key - Add a translation + "project.page.titleprefix": "Research Project: ", + + + + // "publication.listelement.badge": "Publication", + // TODO New key - Add a translation + "publication.listelement.badge": "Publication", + + // "publication.page.description": "Description", + // TODO New key - Add a translation + "publication.page.description": "Description", + + // "publication.page.journal-issn": "Journal ISSN", + // TODO New key - Add a translation + "publication.page.journal-issn": "Journal ISSN", + + // "publication.page.journal-title": "Journal Title", + // TODO New key - Add a translation + "publication.page.journal-title": "Journal Title", + + // "publication.page.publisher": "Publisher", + // TODO New key - Add a translation + "publication.page.publisher": "Publisher", + + // "publication.page.titleprefix": "Publication: ", + // TODO New key - Add a translation + "publication.page.titleprefix": "Publication: ", + + // "publication.page.volume-title": "Volume Title", + // TODO New key - Add a translation + "publication.page.volume-title": "Volume Title", + + // "publication.search.results.head": "Publication Search Results", + // TODO New key - Add a translation + "publication.search.results.head": "Publication Search Results", + + // "publication.search.title": "DSpace Angular :: Publication Search", + // TODO New key - Add a translation + "publication.search.title": "DSpace Angular :: Publication Search", + + + + // "relationships.isAuthorOf": "Authors", + // TODO New key - Add a translation + "relationships.isAuthorOf": "Authors", + + // "relationships.isIssueOf": "Journal Issues", + // TODO New key - Add a translation + "relationships.isIssueOf": "Journal Issues", + + // "relationships.isJournalIssueOf": "Journal Issue", + // TODO New key - Add a translation + "relationships.isJournalIssueOf": "Journal Issue", + + // "relationships.isJournalOf": "Journals", + // TODO New key - Add a translation + "relationships.isJournalOf": "Journals", + + // "relationships.isOrgUnitOf": "Organizational Units", + // TODO New key - Add a translation + "relationships.isOrgUnitOf": "Organizational Units", + + // "relationships.isPersonOf": "Authors", + // TODO New key - Add a translation + "relationships.isPersonOf": "Authors", + + // "relationships.isProjectOf": "Research Projects", + // TODO New key - Add a translation + "relationships.isProjectOf": "Research Projects", + + // "relationships.isPublicationOf": "Publications", + // TODO New key - Add a translation + "relationships.isPublicationOf": "Publications", + + // "relationships.isPublicationOfJournalIssue": "Articles", + // TODO New key - Add a translation + "relationships.isPublicationOfJournalIssue": "Articles", + + // "relationships.isSingleJournalOf": "Journal", + // TODO New key - Add a translation + "relationships.isSingleJournalOf": "Journal", + + // "relationships.isSingleVolumeOf": "Journal Volume", + // TODO New key - Add a translation + "relationships.isSingleVolumeOf": "Journal Volume", + + // "relationships.isVolumeOf": "Journal Volumes", + // TODO New key - Add a translation + "relationships.isVolumeOf": "Journal Volumes", + + + + // "search.description": "", "search.description": "", + + // "search.switch-configuration.title": "Show", + // TODO New key - Add a translation + "search.switch-configuration.title": "Show", + + // "search.title": "DSpace Angular :: Search", "search.title": "DSpace Angular :: Hledat", - + + + + // "search.filters.applied.f.author": "Author", "search.filters.applied.f.author": "Autor", + + // "search.filters.applied.f.dateIssued.max": "End date", "search.filters.applied.f.dateIssued.max": "Do data", + + // "search.filters.applied.f.dateIssued.min": "Start date", "search.filters.applied.f.dateIssued.min": "Od data", + + // "search.filters.applied.f.dateSubmitted": "Date submitted", + // TODO New key - Add a translation + "search.filters.applied.f.dateSubmitted": "Date submitted", + + // "search.filters.applied.f.entityType": "Item Type", + // TODO New key - Add a translation + "search.filters.applied.f.entityType": "Item Type", + + // "search.filters.applied.f.has_content_in_original_bundle": "Has files", "search.filters.applied.f.has_content_in_original_bundle": "Má soubory", + + // "search.filters.applied.f.itemtype": "Type", + // TODO New key - Add a translation + "search.filters.applied.f.itemtype": "Type", + + // "search.filters.applied.f.namedresourcetype": "Status", + // TODO New key - Add a translation + "search.filters.applied.f.namedresourcetype": "Status", + + // "search.filters.applied.f.subject": "Subject", "search.filters.applied.f.subject": "Předmět", - + + // "search.filters.applied.f.submitter": "Submitter", + // TODO New key - Add a translation + "search.filters.applied.f.submitter": "Submitter", + + + + // "search.filters.filter.author.head": "Author", "search.filters.filter.author.head": "Autor", + + // "search.filters.filter.author.placeholder": "Author name", "search.filters.filter.author.placeholder": "Jméno autora", + + // "search.filters.filter.birthDate.head": "Birth Date", + // TODO New key - Add a translation + "search.filters.filter.birthDate.head": "Birth Date", + + // "search.filters.filter.birthDate.placeholder": "Birth Date", + // TODO New key - Add a translation + "search.filters.filter.birthDate.placeholder": "Birth Date", + + // "search.filters.filter.creativeDatePublished.head": "Date Published", + // TODO New key - Add a translation + "search.filters.filter.creativeDatePublished.head": "Date Published", + + // "search.filters.filter.creativeDatePublished.placeholder": "Date Published", + // TODO New key - Add a translation + "search.filters.filter.creativeDatePublished.placeholder": "Date Published", + + // "search.filters.filter.creativeWorkEditor.head": "Editor", + // TODO New key - Add a translation + "search.filters.filter.creativeWorkEditor.head": "Editor", + + // "search.filters.filter.creativeWorkEditor.placeholder": "Editor", + // TODO New key - Add a translation + "search.filters.filter.creativeWorkEditor.placeholder": "Editor", + + // "search.filters.filter.creativeWorkKeywords.head": "Subject", + // TODO New key - Add a translation + "search.filters.filter.creativeWorkKeywords.head": "Subject", + + // "search.filters.filter.creativeWorkKeywords.placeholder": "Subject", + // TODO New key - Add a translation + "search.filters.filter.creativeWorkKeywords.placeholder": "Subject", + + // "search.filters.filter.creativeWorkPublisher.head": "Publisher", + // TODO New key - Add a translation + "search.filters.filter.creativeWorkPublisher.head": "Publisher", + + // "search.filters.filter.creativeWorkPublisher.placeholder": "Publisher", + // TODO New key - Add a translation + "search.filters.filter.creativeWorkPublisher.placeholder": "Publisher", + + // "search.filters.filter.dateIssued.head": "Date", "search.filters.filter.dateIssued.head": "Datum", + + // "search.filters.filter.dateIssued.max.placeholder": "Minimum Date", "search.filters.filter.dateIssued.max.placeholder": "Datum od", + + // "search.filters.filter.dateIssued.min.placeholder": "Maximum Date", "search.filters.filter.dateIssued.min.placeholder": "Datum do", + + // "search.filters.filter.dateSubmitted.head": "Date submitted", + // TODO New key - Add a translation + "search.filters.filter.dateSubmitted.head": "Date submitted", + + // "search.filters.filter.dateSubmitted.placeholder": "Date submitted", + // TODO New key - Add a translation + "search.filters.filter.dateSubmitted.placeholder": "Date submitted", + + // "search.filters.filter.entityType.head": "Item Type", + // TODO New key - Add a translation + "search.filters.filter.entityType.head": "Item Type", + + // "search.filters.filter.entityType.placeholder": "Item Type", + // TODO New key - Add a translation + "search.filters.filter.entityType.placeholder": "Item Type", + + // "search.filters.filter.has_content_in_original_bundle.head": "Has files", "search.filters.filter.has_content_in_original_bundle.head": "Má soubory", + + // "search.filters.filter.itemtype.head": "Type", + // TODO New key - Add a translation + "search.filters.filter.itemtype.head": "Type", + + // "search.filters.filter.itemtype.placeholder": "Type", + // TODO New key - Add a translation + "search.filters.filter.itemtype.placeholder": "Type", + + // "search.filters.filter.jobTitle.head": "Job Title", + // TODO New key - Add a translation + "search.filters.filter.jobTitle.head": "Job Title", + + // "search.filters.filter.jobTitle.placeholder": "Job Title", + // TODO New key - Add a translation + "search.filters.filter.jobTitle.placeholder": "Job Title", + + // "search.filters.filter.knowsLanguage.head": "Known language", + // TODO New key - Add a translation + "search.filters.filter.knowsLanguage.head": "Known language", + + // "search.filters.filter.knowsLanguage.placeholder": "Known language", + // TODO New key - Add a translation + "search.filters.filter.knowsLanguage.placeholder": "Known language", + + // "search.filters.filter.namedresourcetype.head": "Status", + // TODO New key - Add a translation + "search.filters.filter.namedresourcetype.head": "Status", + + // "search.filters.filter.namedresourcetype.placeholder": "Status", + // TODO New key - Add a translation + "search.filters.filter.namedresourcetype.placeholder": "Status", + + // "search.filters.filter.objectpeople.head": "People", + // TODO New key - Add a translation + "search.filters.filter.objectpeople.head": "People", + + // "search.filters.filter.objectpeople.placeholder": "People", + // TODO New key - Add a translation + "search.filters.filter.objectpeople.placeholder": "People", + + // "search.filters.filter.organizationAddressCountry.head": "Country", + // TODO New key - Add a translation + "search.filters.filter.organizationAddressCountry.head": "Country", + + // "search.filters.filter.organizationAddressCountry.placeholder": "Country", + // TODO New key - Add a translation + "search.filters.filter.organizationAddressCountry.placeholder": "Country", + + // "search.filters.filter.organizationAddressLocality.head": "City", + // TODO New key - Add a translation + "search.filters.filter.organizationAddressLocality.head": "City", + + // "search.filters.filter.organizationAddressLocality.placeholder": "City", + // TODO New key - Add a translation + "search.filters.filter.organizationAddressLocality.placeholder": "City", + + // "search.filters.filter.organizationFoundingDate.head": "Date Founded", + // TODO New key - Add a translation + "search.filters.filter.organizationFoundingDate.head": "Date Founded", + + // "search.filters.filter.organizationFoundingDate.placeholder": "Date Founded", + // TODO New key - Add a translation + "search.filters.filter.organizationFoundingDate.placeholder": "Date Founded", + + // "search.filters.filter.scope.head": "Scope", "search.filters.filter.scope.head": "Rozsah", + + // "search.filters.filter.scope.placeholder": "Scope filter", "search.filters.filter.scope.placeholder": "Filtr rozsahu", + + // "search.filters.filter.show-less": "Collapse", "search.filters.filter.show-less": "Sbalit", + + // "search.filters.filter.show-more": "Show more", "search.filters.filter.show-more": "Zobrazit více", + + // "search.filters.filter.subject.head": "Subject", "search.filters.filter.subject.head": "Předmět", + + // "search.filters.filter.subject.placeholder": "Subject", "search.filters.filter.subject.placeholder": "Předmět", - + + // "search.filters.filter.submitter.head": "Submitter", + // TODO New key - Add a translation + "search.filters.filter.submitter.head": "Submitter", + + // "search.filters.filter.submitter.placeholder": "Submitter", + // TODO New key - Add a translation + "search.filters.filter.submitter.placeholder": "Submitter", + + + + // "search.filters.head": "Filters", "search.filters.head": "Filtry", + + // "search.filters.reset": "Reset filters", "search.filters.reset": "Obnovit filtry", - + + + + // "search.form.search": "Search", "search.form.search": "Hledat", + + // "search.form.search_dspace": "Search DSpace", "search.form.search_dspace": "Hledat v DSpace", - + + // "search.form.search_mydspace": "Search MyDSpace", + // TODO New key - Add a translation + "search.form.search_mydspace": "Search MyDSpace", + + + + // "search.results.head": "Search Results", "search.results.head": "Výsledky hledání", + + // "search.results.no-results": "Your search returned no results. Having trouble finding what you're looking for? Try putting", "search.results.no-results": "Nebyli nalezeny žádné výsledky", - + + // "search.results.no-results-link": "quotes around it", + // TODO New key - Add a translation + "search.results.no-results-link": "quotes around it", + + + + // "search.sidebar.close": "Back to results", "search.sidebar.close": "Zpět na výsledky", + + // "search.sidebar.filters.title": "Filters", "search.sidebar.filters.title": "Filtry", + + // "search.sidebar.open": "Search Tools", "search.sidebar.open": "Vyhledávací nástroje", + + // "search.sidebar.results": "results", "search.sidebar.results": "výsledky", + + // "search.sidebar.settings.rpp": "Results per page", "search.sidebar.settings.rpp": "Výsledků na stránku", + + // "search.sidebar.settings.sort-by": "Sort By", "search.sidebar.settings.sort-by": "Řadit dle", + + // "search.sidebar.settings.title": "Settings", "search.sidebar.settings.title": "Nastavení", - + + + + // "search.view-switch.show-detail": "Show detail", + // TODO New key - Add a translation + "search.view-switch.show-detail": "Show detail", + + // "search.view-switch.show-grid": "Show as grid", "search.view-switch.show-grid": "Zobrazit mřížku", + + // "search.view-switch.show-list": "Show as list", "search.view-switch.show-list": "Zobrazit seznam", - + + + + // "sorting.dc.title.ASC": "Title Ascending", "sorting.dc.title.ASC": "Název vzestupně", + + // "sorting.dc.title.DESC": "Title Descending", "sorting.dc.title.DESC": "Název sestupně", + + // "sorting.score.DESC": "Relevance", "sorting.score.DESC": "Relevance", - + + + + // "submission.edit.title": "Edit Submission", + // TODO New key - Add a translation + "submission.edit.title": "Edit Submission", + + // "submission.general.cannot_submit": "You have not the privilege to make a new submission.", + // TODO New key - Add a translation + "submission.general.cannot_submit": "You have not the privilege to make a new submission.", + + // "submission.general.deposit": "Deposit", + // TODO New key - Add a translation + "submission.general.deposit": "Deposit", + + // "submission.general.discard.confirm.cancel": "Cancel", + // TODO New key - Add a translation + "submission.general.discard.confirm.cancel": "Cancel", + + // "submission.general.discard.confirm.info": "This operation can't be undone. Are you sure?", + // TODO New key - Add a translation + "submission.general.discard.confirm.info": "This operation can't be undone. Are you sure?", + + // "submission.general.discard.confirm.submit": "Yes, I'm sure", + // TODO New key - Add a translation + "submission.general.discard.confirm.submit": "Yes, I'm sure", + + // "submission.general.discard.confirm.title": "Discard submission", + // TODO New key - Add a translation + "submission.general.discard.confirm.title": "Discard submission", + + // "submission.general.discard.submit": "Discard", + // TODO New key - Add a translation + "submission.general.discard.submit": "Discard", + + // "submission.general.save": "Save", + // TODO New key - Add a translation + "submission.general.save": "Save", + + // "submission.general.save-later": "Save for later", + // TODO New key - Add a translation + "submission.general.save-later": "Save for later", + + + + // "submission.sections.general.add-more": "Add more", + // TODO New key - Add a translation + "submission.sections.general.add-more": "Add more", + + // "submission.sections.general.collection": "Collection", + // TODO New key - Add a translation + "submission.sections.general.collection": "Collection", + + // "submission.sections.general.deposit_error_notice": "There was an issue when submitting the item, please try again later.", + // TODO New key - Add a translation + "submission.sections.general.deposit_error_notice": "There was an issue when submitting the item, please try again later.", + + // "submission.sections.general.deposit_success_notice": "Submission deposited successfully.", + // TODO New key - Add a translation + "submission.sections.general.deposit_success_notice": "Submission deposited successfully.", + + // "submission.sections.general.discard_error_notice": "There was an issue when discarding the item, please try again later.", + // TODO New key - Add a translation + "submission.sections.general.discard_error_notice": "There was an issue when discarding the item, please try again later.", + + // "submission.sections.general.discard_success_notice": "Submission discarded successfully.", + // TODO New key - Add a translation + "submission.sections.general.discard_success_notice": "Submission discarded successfully.", + + // "submission.sections.general.metadata-extracted": "New metadata have been extracted and added to the {{sectionId}} section.", + // TODO New key - Add a translation + "submission.sections.general.metadata-extracted": "New metadata have been extracted and added to the {{sectionId}} section.", + + // "submission.sections.general.metadata-extracted-new-section": "New {{sectionId}} section has been added to submission.", + // TODO New key - Add a translation + "submission.sections.general.metadata-extracted-new-section": "New {{sectionId}} section has been added to submission.", + + // "submission.sections.general.no-collection": "No collection found", + // TODO New key - Add a translation + "submission.sections.general.no-collection": "No collection found", + + // "submission.sections.general.no-sections": "No options available", + // TODO New key - Add a translation + "submission.sections.general.no-sections": "No options available", + + // "submission.sections.general.save_error_notice": "There was an issue when saving the item, please try again later.", + // TODO New key - Add a translation + "submission.sections.general.save_error_notice": "There was an issue when saving the item, please try again later.", + + // "submission.sections.general.save_success_notice": "Submission saved successfully.", + // TODO New key - Add a translation + "submission.sections.general.save_success_notice": "Submission saved successfully.", + + // "submission.sections.general.search-collection": "Search for a collection", + // TODO New key - Add a translation + "submission.sections.general.search-collection": "Search for a collection", + + // "submission.sections.general.sections_not_valid": "There are incomplete sections.", + // TODO New key - Add a translation + "submission.sections.general.sections_not_valid": "There are incomplete sections.", + + + + // "submission.sections.submit.progressbar.cclicense": "Creative commons license", + // TODO New key - Add a translation + "submission.sections.submit.progressbar.cclicense": "Creative commons license", + + // "submission.sections.submit.progressbar.describe.recycle": "Recycle", + // TODO New key - Add a translation + "submission.sections.submit.progressbar.describe.recycle": "Recycle", + + // "submission.sections.submit.progressbar.describe.stepcustom": "Describe", + // TODO New key - Add a translation + "submission.sections.submit.progressbar.describe.stepcustom": "Describe", + + // "submission.sections.submit.progressbar.describe.stepone": "Describe", + // TODO New key - Add a translation + "submission.sections.submit.progressbar.describe.stepone": "Describe", + + // "submission.sections.submit.progressbar.describe.steptwo": "Describe", + // TODO New key - Add a translation + "submission.sections.submit.progressbar.describe.steptwo": "Describe", + + // "submission.sections.submit.progressbar.detect-duplicate": "Potential duplicates", + // TODO New key - Add a translation + "submission.sections.submit.progressbar.detect-duplicate": "Potential duplicates", + + // "submission.sections.submit.progressbar.license": "Deposit license", + // TODO New key - Add a translation + "submission.sections.submit.progressbar.license": "Deposit license", + + // "submission.sections.submit.progressbar.upload": "Upload files", + // TODO New key - Add a translation + "submission.sections.submit.progressbar.upload": "Upload files", + + + + // "submission.sections.upload.delete.confirm.cancel": "Cancel", + // TODO New key - Add a translation + "submission.sections.upload.delete.confirm.cancel": "Cancel", + + // "submission.sections.upload.delete.confirm.info": "This operation can't be undone. Are you sure?", + // TODO New key - Add a translation + "submission.sections.upload.delete.confirm.info": "This operation can't be undone. Are you sure?", + + // "submission.sections.upload.delete.confirm.submit": "Yes, I'm sure", + // TODO New key - Add a translation + "submission.sections.upload.delete.confirm.submit": "Yes, I'm sure", + + // "submission.sections.upload.delete.confirm.title": "Delete bitstream", + // TODO New key - Add a translation + "submission.sections.upload.delete.confirm.title": "Delete bitstream", + + // "submission.sections.upload.delete.submit": "Delete", + // TODO New key - Add a translation + "submission.sections.upload.delete.submit": "Delete", + + // "submission.sections.upload.drop-message": "Drop files to attach them to the item", + // TODO New key - Add a translation + "submission.sections.upload.drop-message": "Drop files to attach them to the item", + + // "submission.sections.upload.form.access-condition-label": "Access condition type", + // TODO New key - Add a translation + "submission.sections.upload.form.access-condition-label": "Access condition type", + + // "submission.sections.upload.form.date-required": "Date is required.", + // TODO New key - Add a translation + "submission.sections.upload.form.date-required": "Date is required.", + + // "submission.sections.upload.form.from-label": "Access grant from", + // TODO New key - Add a translation + "submission.sections.upload.form.from-label": "Access grant from", + + // "submission.sections.upload.form.from-placeholder": "From", + // TODO New key - Add a translation + "submission.sections.upload.form.from-placeholder": "From", + + // "submission.sections.upload.form.group-label": "Group", + // TODO New key - Add a translation + "submission.sections.upload.form.group-label": "Group", + + // "submission.sections.upload.form.group-required": "Group is required.", + // TODO New key - Add a translation + "submission.sections.upload.form.group-required": "Group is required.", + + // "submission.sections.upload.form.until-label": "Access grant until", + // TODO New key - Add a translation + "submission.sections.upload.form.until-label": "Access grant until", + + // "submission.sections.upload.form.until-placeholder": "Until", + // TODO New key - Add a translation + "submission.sections.upload.form.until-placeholder": "Until", + + // "submission.sections.upload.header.policy.default.nolist": "Uploaded files in the {{collectionName}} collection will be accessible according to the following group(s):", + // TODO New key - Add a translation + "submission.sections.upload.header.policy.default.nolist": "Uploaded files in the {{collectionName}} collection will be accessible according to the following group(s):", + + // "submission.sections.upload.header.policy.default.withlist": "Please note that uploaded files in the {{collectionName}} collection will be accessible, in addition to what is explicitly decided for the single file, with the following group(s):", + // TODO New key - Add a translation + "submission.sections.upload.header.policy.default.withlist": "Please note that uploaded files in the {{collectionName}} collection will be accessible, in addition to what is explicitly decided for the single file, with the following group(s):", + + // "submission.sections.upload.info": "Here you will find all the files currently in the item. You can update the fle metadata and access conditions or upload additional files just dragging & dropping them everywhere in the page", + // TODO New key - Add a translation + "submission.sections.upload.info": "Here you will find all the files currently in the item. You can update the fle metadata and access conditions or upload additional files just dragging & dropping them everywhere in the page", + + // "submission.sections.upload.no-entry": "No", + // TODO New key - Add a translation + "submission.sections.upload.no-entry": "No", + + // "submission.sections.upload.no-file-uploaded": "No file uploaded yet.", + // TODO New key - Add a translation + "submission.sections.upload.no-file-uploaded": "No file uploaded yet.", + + // "submission.sections.upload.save-metadata": "Save metadata", + // TODO New key - Add a translation + "submission.sections.upload.save-metadata": "Save metadata", + + // "submission.sections.upload.undo": "Cancel", + // TODO New key - Add a translation + "submission.sections.upload.undo": "Cancel", + + // "submission.sections.upload.upload-failed": "Upload failed", + // TODO New key - Add a translation + "submission.sections.upload.upload-failed": "Upload failed", + + // "submission.sections.upload.upload-successful": "Upload successful", + // TODO New key - Add a translation + "submission.sections.upload.upload-successful": "Upload successful", + + + + // "submission.submit.title": "Submission", + // TODO New key - Add a translation + "submission.submit.title": "Submission", + + + + // "submission.workflow.generic.delete": "Delete", + // TODO New key - Add a translation + "submission.workflow.generic.delete": "Delete", + + // "submission.workflow.generic.delete-help": "If you would to discard this item, select \"Delete\". You will then be asked to confirm it.", + // TODO New key - Add a translation + "submission.workflow.generic.delete-help": "If you would to discard this item, select \"Delete\". You will then be asked to confirm it.", + + // "submission.workflow.generic.edit": "Edit", + // TODO New key - Add a translation + "submission.workflow.generic.edit": "Edit", + + // "submission.workflow.generic.edit-help": "Select this option to change the item's metadata.", + // TODO New key - Add a translation + "submission.workflow.generic.edit-help": "Select this option to change the item's metadata.", + + // "submission.workflow.generic.view": "View", + // TODO New key - Add a translation + "submission.workflow.generic.view": "View", + + // "submission.workflow.generic.view-help": "Select this option to view the item's metadata.", + // TODO New key - Add a translation + "submission.workflow.generic.view-help": "Select this option to view the item's metadata.", + + + + // "submission.workflow.tasks.claimed.approve": "Approve", + // TODO New key - Add a translation + "submission.workflow.tasks.claimed.approve": "Approve", + + // "submission.workflow.tasks.claimed.approve_help": "If you have reviewed the item and it is suitable for inclusion in the collection, select \"Approve\".", + // TODO New key - Add a translation + "submission.workflow.tasks.claimed.approve_help": "If you have reviewed the item and it is suitable for inclusion in the collection, select \"Approve\".", + + // "submission.workflow.tasks.claimed.edit": "Edit", + // TODO New key - Add a translation + "submission.workflow.tasks.claimed.edit": "Edit", + + // "submission.workflow.tasks.claimed.edit_help": "Select this option to change the item's metadata.", + // TODO New key - Add a translation + "submission.workflow.tasks.claimed.edit_help": "Select this option to change the item's metadata.", + + // "submission.workflow.tasks.claimed.reject.reason.info": "Please enter your reason for rejecting the submission into the box below, indicating whether the submitter may fix a problem and resubmit.", + // TODO New key - Add a translation + "submission.workflow.tasks.claimed.reject.reason.info": "Please enter your reason for rejecting the submission into the box below, indicating whether the submitter may fix a problem and resubmit.", + + // "submission.workflow.tasks.claimed.reject.reason.placeholder": "Describe the reason of reject", + // TODO New key - Add a translation + "submission.workflow.tasks.claimed.reject.reason.placeholder": "Describe the reason of reject", + + // "submission.workflow.tasks.claimed.reject.reason.submit": "Reject item", + // TODO New key - Add a translation + "submission.workflow.tasks.claimed.reject.reason.submit": "Reject item", + + // "submission.workflow.tasks.claimed.reject.reason.title": "Reason", + // TODO New key - Add a translation + "submission.workflow.tasks.claimed.reject.reason.title": "Reason", + + // "submission.workflow.tasks.claimed.reject.submit": "Reject", + // TODO New key - Add a translation + "submission.workflow.tasks.claimed.reject.submit": "Reject", + + // "submission.workflow.tasks.claimed.reject_help": "If you have reviewed the item and found it is not suitable for inclusion in the collection, select \"Reject\". You will then be asked to enter a message indicating why the item is unsuitable, and whether the submitter should change something and resubmit.", + // TODO New key - Add a translation + "submission.workflow.tasks.claimed.reject_help": "If you have reviewed the item and found it is not suitable for inclusion in the collection, select \"Reject\". You will then be asked to enter a message indicating why the item is unsuitable, and whether the submitter should change something and resubmit.", + + // "submission.workflow.tasks.claimed.return": "Return to pool", + // TODO New key - Add a translation + "submission.workflow.tasks.claimed.return": "Return to pool", + + // "submission.workflow.tasks.claimed.return_help": "Return the task to the pool so that another user may perform the task.", + // TODO New key - Add a translation + "submission.workflow.tasks.claimed.return_help": "Return the task to the pool so that another user may perform the task.", + + + + // "submission.workflow.tasks.generic.error": "Error occurred during operation...", + // TODO New key - Add a translation + "submission.workflow.tasks.generic.error": "Error occurred during operation...", + + // "submission.workflow.tasks.generic.processing": "Processing...", + // TODO New key - Add a translation + "submission.workflow.tasks.generic.processing": "Processing...", + + // "submission.workflow.tasks.generic.submitter": "Submitter", + // TODO New key - Add a translation + "submission.workflow.tasks.generic.submitter": "Submitter", + + // "submission.workflow.tasks.generic.success": "Operation successful", + // TODO New key - Add a translation + "submission.workflow.tasks.generic.success": "Operation successful", + + + + // "submission.workflow.tasks.pool.claim": "Claim", + // TODO New key - Add a translation + "submission.workflow.tasks.pool.claim": "Claim", + + // "submission.workflow.tasks.pool.claim_help": "Assign this task to yourself.", + // TODO New key - Add a translation + "submission.workflow.tasks.pool.claim_help": "Assign this task to yourself.", + + // "submission.workflow.tasks.pool.hide-detail": "Hide detail", + // TODO New key - Add a translation + "submission.workflow.tasks.pool.hide-detail": "Hide detail", + + // "submission.workflow.tasks.pool.show-detail": "Show detail", + // TODO New key - Add a translation + "submission.workflow.tasks.pool.show-detail": "Show detail", + + + + // "title": "DSpace", "title": "DSpace", -} + + + + // "uploader.browse": "browse", + // TODO New key - Add a translation + "uploader.browse": "browse", + + // "uploader.drag-message": "Drag & Drop your files here", + // TODO New key - Add a translation + "uploader.drag-message": "Drag & Drop your files here", + + // "uploader.or": ", or", + // TODO New key - Add a translation + "uploader.or": ", or", + + // "uploader.processing": "Processing", + // TODO New key - Add a translation + "uploader.processing": "Processing", + + // "uploader.queue-length": "Queue length", + // TODO New key - Add a translation + "uploader.queue-length": "Queue length", + + + + +} \ No newline at end of file diff --git a/resources/i18n/de.json5 b/resources/i18n/de.json5 index 29e3073592..9c069f546b 100644 --- a/resources/i18n/de.json5 +++ b/resources/i18n/de.json5 @@ -1,175 +1,1605 @@ { + // "404.help": "We can't find the page you're looking for. The page may have been moved or deleted. You can use the button below to get back to the home page. ", "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. ", + // "404.link.home-page": "Take me to the home page", "404.link.home-page": "Zurück zur Startseite", + // "404.page-not-found": "page not found", "404.page-not-found": "Seite nicht gefunden", - "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.", - "admin.registries.bitstream-formats.formats.table.internal": "intern", - "admin.registries.bitstream-formats.formats.table.mimetype": "MIME Type", - "admin.registries.bitstream-formats.formats.table.name": "Name", - "admin.registries.bitstream-formats.formats.table.supportLevel.0": "Unbekannt", - "admin.registries.bitstream-formats.formats.table.supportLevel.1": "Bekannt", - "admin.registries.bitstream-formats.formats.table.supportLevel.2": "Unterstützt", - "admin.registries.bitstream-formats.formats.table.supportLevel.head": "Unterstützungsgrad", + // "admin.registries.bitstream-formats.create.failure.content": "An error occurred while creating the new bitstream format.", + "admin.registries.bitstream-formats.create.failure.content": "Ein Fehler ist beim Anlegen eines neuen Dateiformates aufgetreten.", + // "admin.registries.bitstream-formats.create.failure.head": "Failure", + "admin.registries.bitstream-formats.create.failure.head": "Fehler", + // "admin.registries.bitstream-formats.create.head": "Create Bitstream format", + "admin.registries.bitstream-formats.create.head": "Neues Dateiformat anlegen", + // "admin.registries.bitstream-formats.create.new": "Add a new bitstream format", + "admin.registries.bitstream-formats.create.new": "Ein neues Dateiformat hinzufügen", + // "admin.registries.bitstream-formats.create.success.content": "The new bitstream format was successfully created.", + "admin.registries.bitstream-formats.create.success.content": "Das neue Dateiformat wurde erfolgreich angelegt.", + // "admin.registries.bitstream-formats.create.success.head": "Success", + "admin.registries.bitstream-formats.create.success.head": "Erfolg", + // "admin.registries.bitstream-formats.delete.failure.amount": "Failed to remove {{ amount }} format(s)", + "admin.registries.bitstream-formats.delete.failure.amount": "{{ amount }} Format(1) konnte(n) nicht gelöscht werden", + // "admin.registries.bitstream-formats.delete.failure.head": "Failure", + "admin.registries.bitstream-formats.delete.failure.head": "Fehler", + // "admin.registries.bitstream-formats.delete.success.amount": "Successfully removed {{ amount }} format(s)", + "admin.registries.bitstream-formats.delete.success.amount": "{{ amount }} Format(e) erfolgreich gelöscht", + // "admin.registries.bitstream-formats.delete.success.head": "Success", + "admin.registries.bitstream-formats.delete.success.head": "Erfolg", + // "admin.registries.bitstream-formats.description": "This list of bitstream formats provides information about known formats and their support level.", + "admin.registries.bitstream-formats.description": "Die Liste der Dateiformate enthält Informationen über bekannte Formate und deren Unterstützungsgrad.", + // "admin.registries.bitstream-formats.edit.description.hint": "", + "admin.registries.bitstream-formats.edit.description.hint": "", + // "admin.registries.bitstream-formats.edit.description.label": "Description", + "admin.registries.bitstream-formats.edit.description.label": "Beschreibung", + // "admin.registries.bitstream-formats.edit.extensions.hint": "Extensions are file extensions that are used to automatically identify the format of uploaded files. You can enter several extensions for each format.", + "admin.registries.bitstream-formats.edit.extensions.hint": "Extensionen sind Dateieindungen, welche zur Identifizierung der Formate von hochgeladenen Dateien dienen. Sie können mehrere Endungen pro Format angeben.", + // "admin.registries.bitstream-formats.edit.extensions.label": "File extensions", + "admin.registries.bitstream-formats.edit.extensions.label": "Dateiendungen", + // "admin.registries.bitstream-formats.edit.extensions.placeholder": "Enter a file extenstion without the dot", + "admin.registries.bitstream-formats.edit.extensions.placeholder": "Geben Sie die Endung ohne Punkt ein", + // "admin.registries.bitstream-formats.edit.failure.content": "An error occurred while editing the bitstream format.", + "admin.registries.bitstream-formats.edit.failure.content": "Ein Fehler ist beim Editieren des Dateiformates", + // "admin.registries.bitstream-formats.edit.failure.head": "Failure", + "admin.registries.bitstream-formats.edit.failure.head": "Fehler", + // "admin.registries.bitstream-formats.edit.head": "Bitstream format: {{ format }}", + "admin.registries.bitstream-formats.edit.head": "Dateiformat: {{ format }}", + // "admin.registries.bitstream-formats.edit.internal.hint": "Formats marked as internal are are hidden from the user, and used for administrative purposes.", + "admin.registries.bitstream-formats.edit.internal.hint": "Dateiformate, die als intern gekennzeichnit sind, dienen administrativen Zwecken und bleiben dem Endnutzer verborgen.", + // "admin.registries.bitstream-formats.edit.internal.label": "Internal", + "admin.registries.bitstream-formats.edit.internal.label": "Intern", + // "admin.registries.bitstream-formats.edit.mimetype.hint": "The MIME type associated with this format, does not have to be unique.", + "admin.registries.bitstream-formats.edit.mimetype.hint": "Der MIME Typ dieses Formates. Er muss nicht einzigartig sein.", + // "admin.registries.bitstream-formats.edit.mimetype.label": "MIME Type", + "admin.registries.bitstream-formats.edit.mimetype.label": "MIME Typ", + // "admin.registries.bitstream-formats.edit.shortDescription.hint": "A unique name for this format, (e.g. Microsoft Word XP or Microsoft Word 2000)", + "admin.registries.bitstream-formats.edit.shortDescription.hint": "Ein eindeutiger Name für dieses Format, (z.B. Microsoft Word XP oder Microsoft Word 2000)", + // "admin.registries.bitstream-formats.edit.shortDescription.label": "Name", + "admin.registries.bitstream-formats.edit.shortDescription.label": "Name", + // "admin.registries.bitstream-formats.edit.success.content": "The bitstream format was successfully edited.", + "admin.registries.bitstream-formats.edit.success.content": "Das Dateiformat wurde erfolgreich bearbeitet.", + // "admin.registries.bitstream-formats.edit.success.head": "Success", + "admin.registries.bitstream-formats.edit.success.head": "Erfolg", + // "admin.registries.bitstream-formats.edit.supportLevel.hint": "The level of support your institution pledges for this format.", + "admin.registries.bitstream-formats.edit.supportLevel.hint": "Der Unterstützungsgrad den Ihre Einrichtung für dieses Format anbietet.", + // "admin.registries.bitstream-formats.edit.supportLevel.label": "Support level", + "admin.registries.bitstream-formats.edit.supportLevel.label": "Unterstützungsgrad", + // "admin.registries.bitstream-formats.head": "Bitstream Format Registry", "admin.registries.bitstream-formats.head": "Referenzliste der Dateiformate", + // "admin.registries.bitstream-formats.no-items": "No bitstream formats to show.", + "admin.registries.bitstream-formats.no-items": "Es gibt keine Dateiformate in der Referenzliste.", + // "admin.registries.bitstream-formats.table.delete": "Delete selected", + "admin.registries.bitstream-formats.table.delete": "Auswahl löschen", + // "admin.registries.bitstream-formats.table.deselect-all": "Deselect all", + "admin.registries.bitstream-formats.table.deselect-all": "Alle abwählen", + // "admin.registries.bitstream-formats.table.internal": "internal", + "admin.registries.bitstream-formats.table.internal": "intern", + // "admin.registries.bitstream-formats.table.mimetype": "MIME Type", + "admin.registries.bitstream-formats.table.mimetype": "MIME Typ", + // "admin.registries.bitstream-formats.table.name": "Name", + "admin.registries.bitstream-formats.table.name": "Name", + // "admin.registries.bitstream-formats.table.return": "Return", + "admin.registries.bitstream-formats.table.return": "Zurück", + // "admin.registries.bitstream-formats.table.supportLevel.KNOWN": "Known", + "admin.registries.bitstream-formats.table.supportLevel.KNOWN": "Bekannt", + // "admin.registries.bitstream-formats.table.supportLevel.SUPPORTED": "Supported", + "admin.registries.bitstream-formats.table.supportLevel.SUPPORTED": "Unterstützt", + // "admin.registries.bitstream-formats.table.supportLevel.UNKNOWN": "Unknown", + "admin.registries.bitstream-formats.table.supportLevel.UNKNOWN": "Unbekannt", + // "admin.registries.bitstream-formats.table.supportLevel.head": "Support Level", + "admin.registries.bitstream-formats.table.supportLevel.head": "Unterstützungsgrad", + // "admin.registries.bitstream-formats.title": "DSpace Angular :: Bitstream Format Registry", "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.description": "The metadata registry maintains a list of all metadata fields available in the repository. These fields may be divided amongst multiple schemas. However, DSpace requires the qualified Dublin Core schema.", + "admin.registries.metadata.description": "In der Referenzliste der Metadaten sind alle Metadatenfelder aufgeführt, die in diesem Repositorium zur Verfügung stehen. Diese Felder können auf verschiedene Schemata aufgeteilt sein. Für DSpace ist das Dublin Core Schema auf jeden Fall erforderlich.", + // "admin.registries.metadata.form.create": "Create metadata schema", + "admin.registries.metadata.form.create": "Metadatenschema anlegen", + // "admin.registries.metadata.form.edit": "Edit metadata schema", + "admin.registries.metadata.form.edit": "Metadatenschema bearbeiten", + // "admin.registries.metadata.form.name": "Name", + "admin.registries.metadata.form.name": "Name", + // "admin.registries.metadata.form.namespace": "Namespace", + "admin.registries.metadata.form.namespace": "Namensraum", + // "admin.registries.metadata.head": "Metadata Registry", "admin.registries.metadata.head": "Metadatenreferenzliste", - "admin.registries.metadata.schemas.no-items": "Es gbit keine Metadatenschemata.", + // "admin.registries.metadata.schemas.no-items": "No metadata schemas to show.", + "admin.registries.metadata.schemas.no-items": "Es gibt keinen Metadatenschemata in der Referenzliste.", + // "admin.registries.metadata.schemas.table.delete": "Delete selected", + "admin.registries.metadata.schemas.table.delete": "Ausgewählte löschen", + // "admin.registries.metadata.schemas.table.id": "ID", "admin.registries.metadata.schemas.table.id": "ID", + // "admin.registries.metadata.schemas.table.name": "Name", "admin.registries.metadata.schemas.table.name": "Name", + // "admin.registries.metadata.schemas.table.namespace": "Namespace", "admin.registries.metadata.schemas.table.namespace": "Namensraum", + // "admin.registries.metadata.title": "DSpace Angular :: Metadata Registry", "admin.registries.metadata.title": "DSpace Angular :: Metadatenreferenzliste", - - "admin.registries.schema.description": "Dies ist das Metadatenschema für \"{{namespace}}\".", - "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.description": "This is the metadata schema for \"{{namespace}}\".", + "admin.registries.schema.description": "Dies ist das Metadatenschema für den Namensraum \"{{namespace}}\".", + // "admin.registries.schema.fields.head": "Schema metadata fields", + "admin.registries.schema.fields.head": "Im Schema enthaltene Metadatenfelder", + // "admin.registries.schema.fields.no-items": "No metadata fields to show.", + "admin.registries.schema.fields.no-items": "Es gibt keine Metadatenfelder in diesem Schema.", + // "admin.registries.schema.fields.table.delete": "Delete selected", + "admin.registries.schema.fields.table.delete": "Ausgewähltes löschen", + // "admin.registries.schema.fields.table.field": "Field", "admin.registries.schema.fields.table.field": "Feld", + // "admin.registries.schema.fields.table.scopenote": "Scope Note", "admin.registries.schema.fields.table.scopenote": "Gültigkeitsbereich", - "admin.registries.schema.head": "Metadatenschemata", + // "admin.registries.schema.form.create": "Create metadata field", + "admin.registries.schema.form.create": "Metadatenfeld anlegen", + // "admin.registries.schema.form.edit": "Edit metadata field", + "admin.registries.schema.form.edit": "Metadatenfeld bearbeiten", + // "admin.registries.schema.form.element": "Element", + "admin.registries.schema.form.element": "Element", + // "admin.registries.schema.form.qualifier": "Qualifier", + "admin.registries.schema.form.qualifier": "Qualifizierer", + // "admin.registries.schema.form.scopenote": "Scope Note", + "admin.registries.schema.form.scopenote": "Geltungsbereich", + // "admin.registries.schema.head": "Metadata Schema", + "admin.registries.schema.head": "Metadatenschema", + // "admin.registries.schema.notification.created": "Successfully created metadata schema \"{{prefix}}\"", + "admin.registries.schema.notification.created": "\"{{prefix}}\" wurde erfolgreich angelegt.", + // "admin.registries.schema.notification.deleted.failure": "Failed to delete {{amount}} metadata schemas", + "admin.registries.schema.notification.deleted.failure": "{{amount}} Metadatenschema(ta) konnte(n) nicht gelöscht werden", + // "admin.registries.schema.notification.deleted.success": "Successfully deleted {{amount}} metadata schemas", + "admin.registries.schema.notification.deleted.success": "{{amount}} Metadatenschema(ta) wurde(n) gelöscht.", + // "admin.registries.schema.notification.edited": "Successfully edited metadata schema \"{{prefix}}\"", + "admin.registries.schema.notification.edited": "Das Schema \"{{prefix}}\" wurde erfolgreich bearbeitet.", + // "admin.registries.schema.notification.failure": "Error", + "admin.registries.schema.notification.failure": "Fehler", + // "admin.registries.schema.notification.field.created": "Successfully created metadata field \"{{field}}\"", + "admin.registries.schema.notification.field.created": "Das Feld \"{{field}}\" wurde erfolgreich angelegt.", + // "admin.registries.schema.notification.field.deleted.failure": "Failed to delete {{amount}} metadata fields", + "admin.registries.schema.notification.field.deleted.failure": "{{amount}} Metadatenfeld(er) konnte(n) nicht gelöscht werden.", + // "admin.registries.schema.notification.field.deleted.success": "Successfully deleted {{amount}} metadata fields", + "admin.registries.schema.notification.field.deleted.success": "{{amount}} Metadatenfeld(er) wurde(n) erfolgreich gelöscht.", + // "admin.registries.schema.notification.field.edited": "Successfully edited metadata field \"{{field}}\"", + "admin.registries.schema.notification.field.edited": "Das Feld \"{{field}}\" wurde erfolgreich bearbeitet.", + // "admin.registries.schema.notification.success": "Success", + "admin.registries.schema.notification.success": "Erfolg", + // "admin.registries.schema.return": "Return", + "admin.registries.schema.return": "Zurück", + // "admin.registries.schema.title": "DSpace Angular :: Metadata Schema Registry", "admin.registries.schema.title": "DSpace Angular :: Referenzliste der Metadatenschemata", + // "auth.errors.invalid-user": "Invalid email address or password.", + "auth.errors.invalid-user": "Password oder E-Mail-Adresse ungültig.", + // "auth.messages.expired": "Your session has expired. Please log in again.", + "auth.messages.expired": "Ihre Sitzung ist abgelaufen, bitte loggen Sie sich erneut ein.", - "auth.errors.invalid-user": "Ungültige E-Mail-Adresse oder Passwort.", - "auth.messages.expired": "Ihre Sitzung ist abgelaufen, bitte melden Sie sich erneut an.", + // "browse.comcol.by.author": "By Author", + "browse.comcol.by.author": "Nach Autor/in", + // "browse.comcol.by.dateissued": "By Issue Date", + "browse.comcol.by.dateissued": "Nach Erscheinungsjahr", + // "browse.comcol.by.subject": "By Subject", + "browse.comcol.by.subject": "Nach Schlagwort", + // "browse.comcol.by.title": "By Title", + "browse.comcol.by.title": "Nach Titel", + // "browse.comcol.head": "Browse", + "browse.comcol.head": "Listen", + // "browse.empty": "No items to show.", + "browse.empty": "Es gibt keine Dokumente, die angezeigt werden können.", + // "browse.metadata.author": "Author", + "browse.metadata.author": "Autor/in", + // "browse.metadata.dateissued": "Issue Date", + "browse.metadata.dateissued": "Erscheinungsdatum", + // "browse.metadata.subject": "Subject", + "browse.metadata.subject": "Schlagwort", + // "browse.metadata.title": "Title", + "browse.metadata.title": "Titel", + // "browse.startsWith.choose_start": "(Choose start)", + "browse.startsWith.choose_start": "(Startpunkt wählen)", + // "browse.startsWith.choose_year": "(Choose year)", + "browse.startsWith.choose_year": "(Zeitpunkt wählen)", + // "browse.startsWith.jump": "Jump to a point in the index:", + "browse.startsWith.jump": "Zu einem Punkt im Index springen:", + // "browse.startsWith.months.april": "April", + "browse.startsWith.months.april": "April", + // "browse.startsWith.months.august": "August", + "browse.startsWith.months.august": "August", + // "browse.startsWith.months.december": "December", + "browse.startsWith.months.december": "Dezember", + // "browse.startsWith.months.february": "February", + "browse.startsWith.months.february": "Februar", + // "browse.startsWith.months.january": "January", + "browse.startsWith.months.january": "Januar", + // "browse.startsWith.months.july": "July", + "browse.startsWith.months.july": "Juli", + // "browse.startsWith.months.june": "June", + "browse.startsWith.months.june": "Juni", + // "browse.startsWith.months.march": "March", + "browse.startsWith.months.march": "März", + // "browse.startsWith.months.may": "May", + "browse.startsWith.months.may": "Mai", + // "browse.startsWith.months.none": "(Choose month)", + "browse.startsWith.months.none": "(Monat auswählen)", + // "browse.startsWith.months.november": "November", + "browse.startsWith.months.november": "November", + // "browse.startsWith.months.october": "October", + "browse.startsWith.months.october": "Oktober", + // "browse.startsWith.months.september": "September", + "browse.startsWith.months.september": "September", + // "browse.startsWith.submit": "Go", + "browse.startsWith.submit": "Los", + // "browse.startsWith.type_date": "Or type in a date (year-month):", + "browse.startsWith.type_date": "Oder geben Sie ein Datum ein:", + // "browse.startsWith.type_text": "Or enter first few letters:", + "browse.startsWith.type_text": "Oder geben Sie die ersten Buchstaben ein:", + // "browse.title": "Browsing {{ collection }} by {{ field }} {{ value }}", + "browse.title": "Auflistung von {{ collection }} nach {{ field }} {{ value }}", - "browse.title": "Anzeige {{ collection }} nach {{ field }} {{ value }}", - "collection.page.browse.recent.head": "Aktuellste Veröffentlichungen", + // "chips.remove": "Remove chip", + "chips.remove": "Teil löschen", + + // "collection.create.head": "Create a Collection", + "collection.create.head": "Eine Sammlung anlegen", + // "collection.create.sub-head": "Create a Collection for Community {{ parent }}", + "collection.create.sub-head": "Eine Sammlung in dem Bereich {{ parent }} anlegen", + // "collection.delete.cancel": "Cancel", + "collection.delete.cancel": "Abbrechen", + // "collection.delete.confirm": "Confirm", + "collection.delete.confirm": "Bestätigen", + // "collection.delete.head": "Delete Collection", + "collection.delete.head": "Sammlung löschen", + // "collection.delete.notification.fail": "Collection could not be deleted", + "collection.delete.notification.fail": "Die Sammlung konnte nicht gelöscht werden.", + // "collection.delete.notification.success": "Successfully deleted collection", + "collection.delete.notification.success": "Die Sammlung wurde erfolgreich gelöscht", + // "collection.delete.text": "Are you sure you want to delete collection \"{{ dso }}\"", + "collection.delete.text": "Sind Sie sicher, dass Sie die Sammlung \"{{ dso }}\" löschen wollen?", + + // "collection.edit.delete": "Delete this collection", + "collection.edit.delete": "Diese Sammlung löschen", + // "collection.edit.head": "Edit Collection", + "collection.edit.head": "Sammlung bearbeiten", + + // "collection.edit.item-mapper.cancel": "Cancel", + "collection.edit.item-mapper.cancel": "Abbrechen", + // "collection.edit.item-mapper.collection": "Collection: \"{{name}}\"", + "collection.edit.item-mapper.collection": "Sammlung: \"{{name}}\"", + // "collection.edit.item-mapper.confirm": "Map selected items", + "collection.edit.item-mapper.confirm": "Ausgewählte Ressourcen spiegeln", + // "collection.edit.item-mapper.description": "This is the item mapper tool that allows collection administrators to map items from other collections into this collection. You can search for items from other collections and map them, or browse the list of currently mapped items.", + "collection.edit.item-mapper.description": "Sammlungsadministratoren haben die Möglichkeit Ressourcen von einer Sammlung in eine andere zu spiegeln. Man kann nach Ressourcen in anderen Sammlungen suchen und diese spiegeln oder sich eine Liste der gespiegelten Ressourcen anzeigen lassen.", + // "collection.edit.item-mapper.head": "Item Mapper - Map Items from Other Collections", + "collection.edit.item-mapper.head": "Ressourcen Spiegeln - Spiegelt Ressourcen aus anderen Sammlungen", + // "collection.edit.item-mapper.no-search": "Please enter a query to search", + "collection.edit.item-mapper.no-search": "Bitte geben Sie eine Suchanfrage ein.", + // "collection.edit.item-mapper.notifications.map.error.content": "Errors occurred for mapping of {{amount}} items.", + "collection.edit.item-mapper.notifications.map.error.content": "Beim Spiegeln von {{amount}} Ressource(n) ist ein Fehler aufgetreten.", + // "collection.edit.item-mapper.notifications.map.error.head": "Mapping errors", + "collection.edit.item-mapper.notifications.map.error.head": "Fehler beim Spiegeln", + // "collection.edit.item-mapper.notifications.map.success.content": "Successfully mapped {{amount}} items.", + "collection.edit.item-mapper.notifications.map.success.content": "{{amount}} Ressource(n) erfolgreich gespiegelt.", + // "collection.edit.item-mapper.notifications.map.success.head": "Mapping completed", + "collection.edit.item-mapper.notifications.map.success.head": "Spiegelung abgeschlossen", + // "collection.edit.item-mapper.notifications.unmap.error.content": "Errors occurred for removing the mappings of {{amount}} items.", + "collection.edit.item-mapper.notifications.unmap.error.content": "Beim Spiegeln von {{amount}} Ressource(n) ist ein Fehler aufgetreten.", + // "collection.edit.item-mapper.notifications.unmap.error.head": "Remove mapping errors", + "collection.edit.item-mapper.notifications.unmap.error.head": "Spiegeln Entfernen Fehler", + // "collection.edit.item-mapper.notifications.unmap.success.content": "Successfully removed the mappings of {{amount}} items.", + "collection.edit.item-mapper.notifications.unmap.success.content": "{{amount}} Spiegelung(en) wurde(n) entfernt.", + // "collection.edit.item-mapper.notifications.unmap.success.head": "Remove mapping completed", + "collection.edit.item-mapper.notifications.unmap.success.head": "Spiegelung entfernen abgeschlossen", + // "collection.edit.item-mapper.remove": "Remove selected item mappings", + "collection.edit.item-mapper.remove": "Spiegelung der gewählten Ressourcen entfernen.", + // "collection.edit.item-mapper.tabs.browse": "Browse mapped items", + "collection.edit.item-mapper.tabs.browse": "Gespiegelte Ressourcen auflisten", + // "collection.edit.item-mapper.tabs.map": "Map new items", + "collection.edit.item-mapper.tabs.map": "Neue Ressourcen spiegeln", + + // "collection.form.abstract": "Short Description", + "collection.form.abstract": "Kurzbeschreibung", + // "collection.form.description": "Introductory text (HTML)", + "collection.form.description": "Einleitender Text (HTML)", + // "collection.form.errors.title.required": "Please enter a collection name", + "collection.form.errors.title.required": "Bitte geben Sie einen Namen für die Sammlung ein.", + // "collection.form.license": "License", + "collection.form.license": "Lizenzbestimmung", + // "collection.form.provenance": "Provenance", + "collection.form.provenance": "Herkunft", + // "collection.form.rights": "Copyright text (HTML)", + "collection.form.rights": "Copyright Text (HTML)", + // "collection.form.tableofcontents": "News (HTML)", + "collection.form.tableofcontents": "Neuigkeiten (HTML)", + // "collection.form.title": "Name", + "collection.form.title": "Name", + + // "collection.page.browse.recent.head": "Recent Submissions", + "collection.page.browse.recent.head": "Neueste Veröffentlichungen", + // "collection.page.browse.recent.empty": "No items to show", + "collection.page.browse.recent.empty": "Es gibt keine Ressourcen zum Anzeigen", + // "collection.page.handle": "Permanent URI for this collection", + "collection.page.handle": "Dauerhafte URI für die Sammlung", + // "collection.page.license": "License", "collection.page.license": "Lizenz", + // "collection.page.news": "News", "collection.page.news": "Neuigkeiten", + // "collection.select.confirm": "Confirm selected", + "collection.select.confirm": "Auswahl bestätigen", + // "collection.select.empty": "No collections to show", + "collection.select.empty": "Es gibt keine Sammlungen, die angezeigt werden können", + // "collection.select.table.title": "Title", + "collection.select.table.title": "Titel", + + // "community.create.head": "Create a Community", + "community.create.head": "Sammlung anlegen", + // "community.create.sub-head": "Create a Sub-Community for Community {{ parent }}", + "community.create.sub-head": "Teilbeirech im Bereich {{ parent }} anlegen", + // "community.delete.cancel": "Cancel", + "community.delete.cancel": "Abbrechen", + // "community.delete.confirm": "Confirm", + "community.delete.confirm": "Bestätigen", + // "community.delete.head": "Delete Community", + "community.delete.head": "Bereich Löschen", + // "community.delete.notification.fail": "Community could not be deleted", + "community.delete.notification.fail": "Der Bereich konnte nicht gelöscht werden.", + // "community.delete.notification.success": "Successfully deleted community", + "community.delete.notification.success": "Der Bereich wurde erfolgreich gelöscht.", + // "community.delete.text": "Are you sure you want to delete community \"{{ dso }}\"", + "community.delete.text": "Sind Sie sicher, dass Sie den Bereich \"{{ dso }}\" löschen möchten?", + // "community.edit.delete": "Delete this community", + "community.edit.delete": "Diesen Bereich löschen", + // "community.edit.head": "Edit Community", + "community.edit.head": "Bereich bearbeiten", + // "community.form.abstract": "Short Description", + "community.form.abstract": "Kurzbeschreibung", + // "community.form.description": "Introductory text (HTML)", + "community.form.description": "Einleitender Text (HTML)", + // "community.form.errors.title.required": "Please enter a community name", + "community.form.errors.title.required": "Bitte geben Sie einen Namen für den Bereich ein.", + // "community.form.rights": "Copyright text (HTML)", + "community.form.rights": "Copyrighterklärung (HTML)", + // "community.form.tableofcontents": "News (HTML)", + "community.form.tableofcontents": "Neuigkeiten (HTML)", + // "community.form.title": "Name", + "community.form.title": "Name", + // "community.page.handle": "Permanent URI for this community", + "community.page.handle": "Dauerhafte URI für den Bereich", + // "community.page.license": "License", "community.page.license": "Lizenz", + // "community.page.news": "News", "community.page.news": "Neuigkeiten", + // "community.all-lists.head": "Subcommunities and Collections", + "community.all-lists.head": "Teilbereiche in diesem Bereich", + // "community.sub-collection-list.head": "Collections of this Community", "community.sub-collection-list.head": "Sammlungen in diesem Bereich", + // "community.sub-community-list.head": "Communities of this Community", + "community.sub-community-list.head": "Teilbereiche in diesem Bereich", + // "dso-selector.create.collection.head": "New collection", + "dso-selector.create.collection.head": "Neue Sammlung", + // "dso-selector.create.community.head": "New community", + "dso-selector.create.community.head": "Neuer Bereich", + // "dso-selector.create.community.sub-level": "Create a new community in", + "dso-selector.create.community.sub-level": "Einen neuen Bereich anlegen in", + // "dso-selector.create.community.top-level": "Create a new top-level community", + "dso-selector.create.community.top-level": "Einen neuen Bereich auf oberster Ebene anlgen", + // "dso-selector.create.item.head": "New item", + "dso-selector.create.item.head": "Neue Ressource", + // "dso-selector.edit.collection.head": "Edit collection", + "dso-selector.edit.collection.head": "Sammlung bearbeiten", + // "dso-selector.edit.community.head": "Edit community", + "dso-selector.edit.community.head": "Bereich bearbeiten", + // "dso-selector.edit.item.head": "Edit item", + "dso-selector.edit.item.head": "Ressource bearbeiten", + // "dso-selector.no-results": "No {{ type }} found", + "dso-selector.no-results": "Kein(e) {{ type }} gefunden", + // "dso-selector.placeholder": "Search for a {{ type }}", + "dso-selector.placeholder": "Suche nach {{ type }}", + + // "error.browse-by": "Error fetching items", "error.browse-by": "Fehler beim Laden der Ressourcen", - "error.collection": "Fehler beim Laden der Sammlung.", - "error.community": "Fehler beim Laden des Bereiches.", + // "error.collection": "Error fetching collection", + "error.collection": "Fehler beim Laden der Sammlung", + // "error.collections": "Error fetching collections", + "error.collections": "Fehler beim Laden der Sammlungen", + // "error.community": "Error fetching community", + "error.community": "Fehler beim Laden des Bereichs", + // "error.identifier": "No item found for the identifier", + "error.identifier": "Zu dieser Kennung wurde keine Ressource gefunden", + // "error.default": "Error", "error.default": "Fehler", - "error.item": "Fehler beim Laden der Ressource.", - "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.", - "error.top-level-communities": "Fehler beim Laden der Hauptbereiche.", - "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.", - "error.validation.pattern": "Die Eingabe kann nur folgendes Muster haben: {{ pattern }}.", + // "error.item": "Error fetching item", + "error.item": "Fehler beim Laden der Ressource", + // "error.items": "Error fetching items", + "error.items": "Fejöer beim Laden der Ressorucen", + // "error.objects": "Error fetching objects", + "error.objects": "Fehler beim Laden der Objekte", + // "error.recent-submissions": "Error fetching recent submissions", + "error.recent-submissions": "Fehler beim Laden der aktuellsten Veröffentlichungen", + // "error.search-results": "Error fetching search results", + "error.search-results": "Fehler beim Laden der Suchergebenisse", + // "error.sub-collections": "Error fetching sub-collections", + "error.sub-collections": "Fehler beim Laden der Teilsammlungen", + // "error.sub-communities": "Error fetching sub-communities", + "error.sub-communities": "Fehler beim Laden der Teilbereiche", + // "error.submission.sections.init-form-error": "An error occurred during section initialize, please check your input-form configuration. Details are below :

", + "error.submission.sections.init-form-error": "Ein Fehler ist bei der Initialisierung der Eingabemaske aufgetreten. Bitte Überprüfen Sie die Konfiguration Ihrer Eingabemaske. Details s.u.

", + // "error.top-level-communities": "Error fetching top-level communities", + "error.top-level-communities": "Hauptbereich konnte nicht geladen werden", + // "error.validation.license.notgranted": "You must grant this license to complete your submission. If you are unable to grant this license at this time you may save your work and return later or remove the submission.", + "error.validation.license.notgranted": "Um die Veröffentlichung abzuschließen, müssen Sie die Lizenzbedingungen akzeptieren. Wenn Sie zur Zeit dazu nicht in der Lage sind, können Sie Ihre Arbeit sichern und später dazu zurückgkehren, um zuzustimmen oder die Einreichung zu löschen.", + // "error.validation.pattern": "This input is restricted by the current pattern: {{ pattern }}.", + "error.validation.pattern": "Die Eingabe hat dem folgenden Muster zu entsprechen: {{ pattern }}.", + // "footer.copyright": "copyright © 2002-{{ year }}", "footer.copyright": "Copyright © 2002-{{ year }}", - "footer.link.dspace": "DSpace Software", + // "footer.link.dspace": "DSpace software", + "footer.link.dspace": "DSpace software", + // "footer.link.duraspace": "DuraSpace", "footer.link.duraspace": "DuraSpace", + // "form.cancel": "Cancel", "form.cancel": "Abbrechen", + // "form.clear": "Clear", + "form.clear": "Eingaben löschen", + // "form.clear-help": "Click here to remove the selected value", + "form.clear-help": "Klicken Sie hier, um den ausgewählten Wert zu entfernen", + // "form.edit": "Edit", + "form.edit": "Bearbeiten", + // "form.edit-help": "Click here to edit the selected value", + "form.edit-help": "Klicken Sie hier, um den ausgwählten Wert zu bearbeiten", + // "form.first-name": "First name", "form.first-name": "Vorname", - "form.group-collapse": "Weniger", - "form.group-collapse-help": "Hier klicken, um die Anzeige zu reduzieren", - "form.group-expand": "Mehr", - "form.group-expand-help": "Hier klicken, um mehr Elemente anzuzeigen", + // "form.group-collapse": "Collapse", + "form.group-collapse": "Zusammenklappen", + // "form.group-collapse-help": "Click here to collapse", + "form.group-collapse-help": "Zum Zusammenfalten bitte hier klicken", + // "form.group-expand": "Expand", + "form.group-expand": "Auffalten", + // "form.group-expand-help": "Click here to expand and add more elements", + "form.group-expand-help": "Zum Ausklappten und Hinzufügen von mehr Elementen, klicken Sie hier", + // "form.last-name": "Last name", "form.last-name": "Nachname", + // "form.loading": "Loading...", "form.loading": "Am Laden ...", + // "form.no-results": "No results found", "form.no-results": "Keine Ergebnisse gefunden", + // "form.no-value": "No value entered", "form.no-value": "Kein Wert eingegeben", - "form.remove": "Löschen", - "form.search": "Suchen", - "form.submit": "Los", + // "form.other-information": {}, + "form.other-information": {}, + // "form.remove": "Remove", + "form.remove": "Entfernen", + // "form.save": "Save", + "form.save": "Speichern", + // "form.save-help": "Save changes", + "form.save-help": "Änderungen speichern", + // "form.search": "Search", + "form.search": "Suche", + // "form.search-help": "Click here to looking for an existing correspondence", + "form.search-help": "Klicken Sie hier, um eine Übereinstimmung zu suchen", + // "form.submit": "Submit", + "form.submit": "Abschicken", + // "home.description": "", "home.description": "", + // "home.title": "DSpace Angular :: Home", "home.title": "DSpace Angular :: Startseite", - "home.top-level-communities.head": "Bereiche in DSpace", - "home.top-level-communities.help": "Wählen Sie einen Bereich, um seine Sammlungen einzusehen.", + // "home.top-level-communities.head": "Communities in DSpace", + "home.top-level-communities.head": "Hauptbereiche in DSpace", + // "home.top-level-communities.help": "Select a community to browse its collections.", + "home.top-level-communities.help": "Wählen Sie einen Bereiche, um dessen Inhalt anzusehen.", - "item.page.abstract": "Kurzfassung", - "item.page.author": "Autor", + // "item.edit.delete.cancel": "Cancel", + "item.edit.delete.cancel": "Abbrechen", + // "item.edit.delete.confirm": "Delete", + "item.edit.delete.confirm": "Löschen", + // "item.edit.delete.description": "Are you sure this item should be completely deleted? Caution: At present, no tombstone would be left.", + "item.edit.delete.description": "Sind Sie sicher, dass diese Ressource komplett gelöscht werden soll. Warnung: Zur Zeit wird kein Grabstein hinterlassen", + // "item.edit.delete.error": "An error occurred while deleting the item", + "item.edit.delete.error": "Beim Löschen der Ressource ist ein Fehler aufgetreten", + // "item.edit.delete.header": "Delete item: {{ id }}", + "item.edit.delete.header": "Löschen der Ressource: {{ id }}", + // "item.edit.delete.success": "The item has been deleted", + "item.edit.delete.success": "Die Ressource wurde gelöscht", + // "item.edit.head": "Edit Item", + "item.edit.head": "Ressource bearbeiten", + + // "item.edit.item-mapper.buttons.add": "Map item to selected collections", + "item.edit.item-mapper.buttons.add": "Ressource in die gewählte(n) Sammlung(en) spiegeln", + // "item.edit.item-mapper.buttons.remove": "Remove item's mapping for selected collections", + "item.edit.item-mapper.buttons.remove": "Spiegelung der Ressource aus der/den gewählten Sammlung(en) entfernen", + // "item.edit.item-mapper.cancel": "Cancel", + "item.edit.item-mapper.cancel": "Abbrechen", + // "item.edit.item-mapper.description": "This is the item mapper tool that allows administrators to map this item to other collections. You can search for collections and map them, or browse the list of collections the item is currently mapped to.", + "item.edit.item-mapper.description": "Sammlungsadministratoren haben die Möglichkeit Ressourcen von einer Sammlung in eine andere zu spiegeln. Man kann nach Ressourcen in anderen Sammlungen suchen und diese spiegeln oder sich eine Liste der gespiegelten Ressourcen anzeigen lassen.", + // "item.edit.item-mapper.head": "Item Mapper - Map Item to Collections", + "item.edit.item-mapper.head": "Ressourcen Spiegeln - Spiegelt eine Resource in andere Sammlungen", + // "item.edit.item-mapper.item": "Item: \"{{name}}\"", + "item.edit.item-mapper.item": "Ressource: \"{{name}}\"", + // "item.edit.item-mapper.no-search": "Please enter a query to search", + "item.edit.item-mapper.no-search": "Bitte geben Sie einen Suchbegriff ein", + // "item.edit.item-mapper.notifications.add.error.content": "Errors occurred for mapping of item to {{amount}} collections.", + "item.edit.item-mapper.notifications.add.error.content": "Beim Spiegeln der Resource in {{amount}} Sammlung(en) ist ein Fehler aufgetreten.", + // "item.edit.item-mapper.notifications.add.error.head": "Mapping errors", + "item.edit.item-mapper.notifications.add.error.head": "Fehler beim Spiegeln", + // "item.edit.item-mapper.notifications.add.success.content": "Successfully mapped item to {{amount}} collections.", + "item.edit.item-mapper.notifications.add.success.content": "Ressource erfolgreich in {{amount}} Sammlung(en) gespiegelt.", + // "item.edit.item-mapper.notifications.add.success.head": "Mapping completed", + "item.edit.item-mapper.notifications.add.success.head": "Spiegeln abgeschlossen", + // "item.edit.item-mapper.notifications.remove.error.content": "Errors occurred for the removal of the mapping to {{amount}} collections.", + "item.edit.item-mapper.notifications.remove.error.content": "Beim Entfernen der Spiegelung in {{amount}} Sammlung(en) ist ein Fehler aufgetreten.", + // "item.edit.item-mapper.notifications.remove.error.head": "Removal of mapping errors", + "item.edit.item-mapper.notifications.remove.error.head": "Fehler beim Entfernen von gespiegelten Ressourcen", + // "item.edit.item-mapper.notifications.remove.success.content": "Successfully removed mapping of item to {{amount}} collections.", + "item.edit.item-mapper.notifications.remove.success.content": "Spiegelung der Ressource aus {{amount}} Sammlung(en) erfolgreich.", + // "item.edit.item-mapper.notifications.remove.success.head": "Removal of mapping completed", + "item.edit.item-mapper.notifications.remove.success.head": "Entfernen der Spiegelung abgeschlossen", + // "item.edit.item-mapper.tabs.browse": "Browse mapped collections", + "item.edit.item-mapper.tabs.browse": "Gespiegelte Sammlungen anzeigen", + // "item.edit.item-mapper.tabs.map": "Map new collections", + "item.edit.item-mapper.tabs.map": "Neue Sammlungen spiegeln", + + // "item.edit.metadata.add-button": "Add", + "item.edit.metadata.add-button": "Hinzufügen", + // "item.edit.metadata.discard-button": "Discard", + "item.edit.metadata.discard-button": "Verwerfen", + // "item.edit.metadata.edit.buttons.edit": "Edit", + "item.edit.metadata.edit.buttons.edit": "Bearbeiten", + // "item.edit.metadata.edit.buttons.remove": "Remove", + "item.edit.metadata.edit.buttons.remove": "Entfernen", + // "item.edit.metadata.edit.buttons.undo": "Undo changes", + "item.edit.metadata.edit.buttons.undo": "Änderungen rückgängig machen", + // "item.edit.metadata.edit.buttons.unedit": "Stop editing", + "item.edit.metadata.edit.buttons.unedit": "Bearbeitung beenden", + // "item.edit.metadata.headers.edit": "Edit", + "item.edit.metadata.headers.edit": "Bearbeiten", + // "item.edit.metadata.headers.field": "Field", + "item.edit.metadata.headers.field": "Feld", + // "item.edit.metadata.headers.language": "Lang", + "item.edit.metadata.headers.language": "Sprache", + // "item.edit.metadata.headers.value": "Value", + "item.edit.metadata.headers.value": "Wert", + // "item.edit.metadata.metadatafield.invalid": "Please choose a valid metadata field", + "item.edit.metadata.metadatafield.invalid": "Bitte wählen Sie ein gültiges Metadatenfeld", + // "item.edit.metadata.notifications.discarded.content": "Your changes were discarded. To reinstate your changes click the 'Undo' button", + "item.edit.metadata.notifications.discarded.content": "Ihre Änderungen wurden verworfen. Um diese wieder anzuwenden, klicken Sie auf den 'Rückgängig machen' Knopf", + // "item.edit.metadata.notifications.discarded.title": "Changed discarded", + "item.edit.metadata.notifications.discarded.title": "Änderungen verworfen", + // "item.edit.metadata.notifications.invalid.content": "Your changes were not saved. Please make sure all fields are valid before you save.", + "item.edit.metadata.notifications.invalid.content": "Ihre Änderungen wurden nicht gespeichert. Stellen Sie sicher, dass alle Felder gültig sind, bevor Sie Abspeichern.", + // "item.edit.metadata.notifications.invalid.title": "Metadata invalid", + "item.edit.metadata.notifications.invalid.title": "Metadaten ungültig", + // "item.edit.metadata.notifications.outdated.content": "The item you're currently working on has been changed by another user. Your current changes are discarded to prevent conflicts", + "item.edit.metadata.notifications.outdated.content": "Die Ressource, an der Sie gerade arbeiten, wurde von einem anderen Benutzer geändert. Ihre aktuellen Änderungen werden nicht angewandt, um Konflikte zu vermeiden.", + // "item.edit.metadata.notifications.outdated.title": "Changed outdated", + "item.edit.metadata.notifications.outdated.title": "Änderung veraltet", + // "item.edit.metadata.notifications.saved.content": "Your changes to this item's metadata were saved.", + "item.edit.metadata.notifications.saved.content": "Ihre Änderungen an den Metadaten der Ressource wurden gespeichert.", + // "item.edit.metadata.notifications.saved.title": "Metadata saved", + "item.edit.metadata.notifications.saved.title": "Metadaten gespeichert", + // "item.edit.metadata.reinstate-button": "Undo", + "item.edit.metadata.reinstate-button": "Rückgängig machen", + // "item.edit.metadata.save-button": "Save", + "item.edit.metadata.save-button": "Speichern", + + // "item.edit.modify.overview.field": "Field", + "item.edit.modify.overview.field": "Feld", + // "item.edit.modify.overview.language": "Language", + "item.edit.modify.overview.language": "Sprache", + // "item.edit.modify.overview.value": "Value", + "item.edit.modify.overview.value": "Wert", + + // "item.edit.move.cancel": "Cancel", + "item.edit.move.cancel": "Abbrechen", + // "item.edit.move.description": "Select the collection you wish to move this item to. To narrow down the list of displayed collections, you can enter a search query in the box.", + "item.edit.move.description": "Select the collection you wish to move this item to. To narrow down the list of displayed collections, you can enter a search query in the box.", + // "item.edit.move.error": "An error occured when attempting to move the item", + "item.edit.move.error": "Ein Fehler ist beim Verschieben der Ressource aufgetreten", + // "item.edit.move.head": "Move item: {{id}}", + "item.edit.move.head": "Ressource verschieben: {{id}}", + // "item.edit.move.inheritpolicies.checkbox": "Inherit policies", + "item.edit.move.inheritpolicies.checkbox": "Rechte erben", + // "item.edit.move.inheritpolicies.description": "Inherit the default policies of the destination collection", + "item.edit.move.inheritpolicies.description": "Standardrechte der Zielsammlung erben", + // "item.edit.move.move": "Move", + "item.edit.move.move": "Verschieben", + // "item.edit.move.processing": "Moving...", + "item.edit.move.processing": "Verschieben...", + // "item.edit.move.search.placeholder": "Enter a search query to look for collections", + "item.edit.move.search.placeholder": "Geben Sie einen Begriff ein, um nach Sammlungen zu suchen", + // "item.edit.move.success": "The item has been moved succesfully", + "item.edit.move.success": "Die Ressource wurde erfolgreich verschoben", + // "item.edit.move.title": "Move item", + "item.edit.move.title": "Ressource verschieben", + + // "item.edit.private.cancel": "Cancel", + "item.edit.private.cancel": "Abbrechen", + // "item.edit.private.confirm": "Make it Private", + "item.edit.private.confirm": "Privat machen", + // "item.edit.private.description": "Are you sure this item should be made private in the archive?", + "item.edit.private.description": "Wollen Sie diese Ressource als privat markieren.", + // "item.edit.private.error": "An error occurred while making the item private", + "item.edit.private.error": "Ein Fehler ist aufgetreten bei dem Versuch, die Ressource privat zu machen", + // "item.edit.private.header": "Make item private: {{ id }}", + "item.edit.private.header": "Ressource: {{ id }} privat machen", + // "item.edit.private.success": "The item is now private", + "item.edit.private.success": "Diese Ressource ist nun privat", + + // "item.edit.public.cancel": "Cancel", + "item.edit.public.cancel": "Abbrechen", + // "item.edit.public.confirm": "Make it Public", + "item.edit.public.confirm": "Öffentlich machen", + // "item.edit.public.description": "Are you sure this item should be made public in the archive?", + "item.edit.public.description": "Sind Sie sicher, dasss diese Ressource im Repositorium öffentlich gemacht werden soll?", + // "item.edit.public.error": "An error occurred while making the item public", + "item.edit.public.error": "Ein Fehler ist aufgetreten, als die Ressource öffentlich gemacht werden sollte.", + // "item.edit.public.header": "Make item public: {{ id }}", + "item.edit.public.header": "Ressource: {{ id }} öffentlich machen", + // "item.edit.public.success": "The item is now public", + "item.edit.public.success": "Die Ressource ist nun öffentlich", + + // "item.edit.reinstate.cancel": "Cancel", + "item.edit.reinstate.cancel": "Abbrechen", + // "item.edit.reinstate.confirm": "Reinstate", + "item.edit.reinstate.confirm": "Reinstantiieren", + // "item.edit.reinstate.description": "Are you sure this item should be reinstated to the archive?", + "item.edit.reinstate.description": "Sind Sie sicher, dass die Ressource reinstantiiert werden soll?", + // "item.edit.reinstate.error": "An error occurred while reinstating the item", + "item.edit.reinstate.error": "Ein Fehler ist bei der Reinstantiierung der Ressource aufgetreten.", + // "item.edit.reinstate.header": "Reinstate item: {{ id }}", + "item.edit.reinstate.header": "Ressource: {{ id }} reinstantiieren", + // "item.edit.reinstate.success": "The item was reinstated successfully", + "item.edit.reinstate.success": "Die Ressource wurde erfolgreich reinstantiiert", + + // "item.edit.relationships.discard-button": "Discard", + "item.edit.relationships.discard-button": "Abbrechen", + // "item.edit.relationships.edit.buttons.remove": "Remove", + "item.edit.relationships.edit.buttons.remove": "Entfernen", + // "item.edit.relationships.edit.buttons.undo": "Undo changes", + "item.edit.relationships.edit.buttons.undo": "Rückgängig machen", + // "item.edit.relationships.notifications.discarded.content": "Your changes were discarded. To reinstate your changes click the 'Undo' button", + "item.edit.relationships.notifications.discarded.content": "Ihre Änderungen wurden verworfen. Um sie dennoch anzuwenden klicken Sie auf den 'Rückgängig machen' Knopf", + // "item.edit.relationships.notifications.discarded.title": "Changes discarded", + "item.edit.relationships.notifications.discarded.title": "Änderungen verworfen", + // "item.edit.relationships.notifications.failed.title": "Error deleting relationship", + "item.edit.relationships.notifications.failed.title": "Fehler beim Löschen der Beziehung", + // "item.edit.relationships.notifications.outdated.content": "The item you're currently working on has been changed by another user. Your current changes are discarded to prevent conflicts", + "item.edit.relationships.notifications.outdated.content": "Die Ressource, die Sie gerade bearbeiten, wurde von einem anderen Benutzer geändert. Ihre aktuellen Änderungen werden verworfen, um Konflikte zu vermeiden.", + // "item.edit.relationships.notifications.outdated.title": "Changes outdated", + "item.edit.relationships.notifications.outdated.title": "Änderungen veraltet", + // "item.edit.relationships.notifications.saved.content": "Your changes to this item's relationships were saved.", + "item.edit.relationships.notifications.saved.content": "Ihre Änderungen an den Beziehungen der Ressource wurden gespeichert.", + // "item.edit.relationships.notifications.saved.title": "Relationships saved", + "item.edit.relationships.notifications.saved.title": "Beziehungen gespeichert", + // "item.edit.relationships.reinstate-button": "Undo", + "item.edit.relationships.reinstate-button": "Rückgängig machen", + // "item.edit.relationships.save-button": "Save", + "item.edit.relationships.save-button": "Speichern", + + // "item.edit.tabs.bitstreams.head": "Item Bitstreams", + "item.edit.tabs.bitstreams.head": "Dateien zur Ressource", + // "item.edit.tabs.bitstreams.title": "Item Edit - Bitstreams", + "item.edit.tabs.bitstreams.title": "Ressource bearbeiten - Dateien", + // "item.edit.tabs.curate.head": "Curate", + "item.edit.tabs.curate.head": "Pflegen", + // "item.edit.tabs.curate.title": "Item Edit - Curate", + "item.edit.tabs.curate.title": "Ressource bearbeiten - Pflegen", + // "item.edit.tabs.metadata.head": "Item Metadata", + "item.edit.tabs.metadata.head": "Metadaten", + // "item.edit.tabs.metadata.title": "Item Edit - Metadata", + "item.edit.tabs.metadata.title": "Ressource bearbeiten - Metadaten", + // "item.edit.tabs.relationships.head": "Item Relationships", + "item.edit.tabs.relationships.head": "Relationen der Ressource", + // "item.edit.tabs.relationships.title": "Item Edit - Relationships", + "item.edit.tabs.relationships.title": "Ressource bearbeiten - Relationen", + // "item.edit.tabs.status.buttons.authorizations.button": "Authorizations...", + "item.edit.tabs.status.buttons.authorizations.button": "Rechte...", + // "item.edit.tabs.status.buttons.authorizations.label": "Edit item's authorization policies", + "item.edit.tabs.status.buttons.authorizations.label": "Rechte der Ressource bearbeiten", + // "item.edit.tabs.status.buttons.delete.button": "Permanently delete", + "item.edit.tabs.status.buttons.delete.button": "Endgültig löschen", + // "item.edit.tabs.status.buttons.delete.label": "Completely expunge item", + "item.edit.tabs.status.buttons.delete.label": "Unwiderruflich löschen", + // "item.edit.tabs.status.buttons.mappedCollections.button": "Mapped collections", + "item.edit.tabs.status.buttons.mappedCollections.button": "Gespiegelte Sammlungen", + // "item.edit.tabs.status.buttons.mappedCollections.label": "Manage mapped collections", + "item.edit.tabs.status.buttons.mappedCollections.label": "Gespiegelte Sammlungen bearbeiten", + // "item.edit.tabs.status.buttons.move.button": "Move...", + "item.edit.tabs.status.buttons.move.button": "Verschieben...", + // "item.edit.tabs.status.buttons.move.label": "Move item to another collection", + "item.edit.tabs.status.buttons.move.label": "Ressource in eine andere Sammlung verschieben", + // "item.edit.tabs.status.buttons.private.button": "Make it private...", + "item.edit.tabs.status.buttons.private.button": "Privat machen...", + // "item.edit.tabs.status.buttons.private.label": "Make item private", + "item.edit.tabs.status.buttons.private.label": "Ressoruce privat machen", + // "item.edit.tabs.status.buttons.public.button": "Make it public...", + "item.edit.tabs.status.buttons.public.button": "Öffentlich machen...", + // "item.edit.tabs.status.buttons.public.label": "Make item public", + "item.edit.tabs.status.buttons.public.label": "Ressource öffentlich machen", + // "item.edit.tabs.status.buttons.reinstate.button": "Reinstate...", + "item.edit.tabs.status.buttons.reinstate.button": "Reinstantiieren...", + // "item.edit.tabs.status.buttons.reinstate.label": "Reinstate item into the repository", + "item.edit.tabs.status.buttons.reinstate.label": "Ressource wieder ins Repositorium einsetzen", + // "item.edit.tabs.status.buttons.withdraw.button": "Withdraw...", + "item.edit.tabs.status.buttons.withdraw.button": "Zurückziehen...", + // "item.edit.tabs.status.buttons.withdraw.label": "Withdraw item from the repository", + "item.edit.tabs.status.buttons.withdraw.label": "Ressource aus dem Repositorium zurückziehen", + // "item.edit.tabs.status.description": "Welcome to the item management page. From here you can withdraw, reinstate, move or delete the item. You may also update or add new metadata / bitstreams on the other tabs.", + "item.edit.tabs.status.description": "Ressource bearbeiten. Von hier können Sie Ressourcen zurückziehen, wiedereinsetzen, verschieben oder Löschen. Des weiteren können die Metadaten und die zugehörigen Dateien bearbeitet werden.", + // "item.edit.tabs.status.head": "Item Status", + "item.edit.tabs.status.head": "Status der Ressource", + // "item.edit.tabs.status.labels.handle": "Handle", + "item.edit.tabs.status.labels.handle": "Handle", + // "item.edit.tabs.status.labels.id": "Item Internal ID", + "item.edit.tabs.status.labels.id": "Interne ID der Ressource", + // "item.edit.tabs.status.labels.itemPage": "Item Page", + "item.edit.tabs.status.labels.itemPage": "Startseite der Ressource", + // "item.edit.tabs.status.labels.lastModified": "Last Modified", + "item.edit.tabs.status.labels.lastModified": "Zuletzt geändert", + // "item.edit.tabs.status.title": "Item Edit - Status", + "item.edit.tabs.status.title": "Ressource Bearbeiten - Status", + // "item.edit.tabs.view.head": "View Item", + "item.edit.tabs.view.head": "Ressource Ansehen", + // "item.edit.tabs.view.title": "Ressource bearbeiten - Ansicht", + + // "item.edit.withdraw.cancel": "Cancel", + "item.edit.withdraw.cancel": "Abbrechen", + // "item.edit.withdraw.confirm": "Withdraw", + "item.edit.withdraw.confirm": "Zurückziehen", + // "item.edit.withdraw.description": "Are you sure this item should be withdrawn from the archive?", + "item.edit.withdraw.description": "Sind Sie sicher, dass Sie diese Ressource aus dem Repositorium zurückziehen wollen?", + // "item.edit.withdraw.error": "An error occurred while withdrawing the item", + "item.edit.withdraw.error": "Ein Fehler ist beim Zurückziehen der Ressource aufgetreten", + // "item.edit.withdraw.header": "Withdraw item: {{ id }}", + "item.edit.withdraw.header": "Ressource: {{ id }} zurückziehen", + // "item.edit.withdraw.success": "The item was withdrawn successfully", + "item.edit.withdraw.success": "Die Ressource wurde erfolgreich zurückgezogen", + + // "item.page.abstract": "Abstract", + "item.page.abstract": "Zusammenfassung", + // "item.page.author": "Authors", + "item.page.author": "AutorInnen", + // "item.page.citation": "Citation", + "item.page.citation": "Zitierform", + // "item.page.collections": "Collections", "item.page.collections": "Sammlungen", + // "item.page.date": "Date", "item.page.date": "Datum", + // "item.page.files": "Files", "item.page.files": "Dateien", + // "item.page.filesection.description": "Description:", "item.page.filesection.description": "Beschreibung:", + // "item.page.filesection.download": "Download", "item.page.filesection.download": "Herunterladen", + // "item.page.filesection.format": "Format:", "item.page.filesection.format": "Format:", + // "item.page.filesection.name": "Name:", "item.page.filesection.name": "Name:", + // "item.page.filesection.size": "Size:", "item.page.filesection.size": "Größe:", - "item.page.link.full": "Vollanzeige", + // "item.page.journal.search.title": "Articles in this journal", + "item.page.journal.search.title": "Artikel in dieser Zeitschrift", + // "item.page.link.full": "Full item page", + "item.page.link.full": "Komplettanzeige", + // "item.page.link.simple": "Simple item page", "item.page.link.simple": "Kurzanzeige", + // "item.page.person.search.title": "Articles by this author", + "item.page.person.search.title": "Veröffentlichungen dieses/r Autor/in", + // "item.page.related-items.view-more": "View more", + "item.page.related-items.view-more": "Mehr anzeigen", + // "item.page.related-items.view-less": "View less", + "item.page.related-items.view-less": "Weniger anzeigen", + // "item.page.subject": "Keywords", + "item.page.subject": "Schlagwörter", + // "item.page.uri": "URI", "item.page.uri": "URI", - "loading.browse-by": "Die Ressourcen werden geladen ...", - "loading.collection": "Die Sammlung wird geladen ...", - "loading.community": "Der Bereich wird geladen ...", - "loading.default": "Am Laden ...", - "loading.item": "Die Ressource wird geladen ...", - "loading.objects": "Am Laden ...", - "loading.recent-submissions": "Die aktuellsten Veröffentlichungen werden geladen ...", - "loading.search-results": "Die Suchergebnisse werden geladen ...", - "loading.sub-collections": "Die untergeordneten Sammlungen werden geladen ...", - "loading.top-level-communities": "Die Hauptbereiche werden geladen ...", + // "item.select.confirm": "Confirm selected", + "item.select.confirm": "Auswahl bestätigen", + // "item.select.empty": "No items to show", + "item.select.empty": "Es gibt keine Ressourcen dazu", + // "item.select.table.author": "Author", + "item.select.table.author": "Autor/in", + // "item.select.table.collection": "Collection", + "item.select.table.collection": "Sammlung", + // "item.select.table.title": "Title", + "item.select.table.title": "Titel", + // "journal.listelement.badge": "Journal", + "journal.listelement.badge": "Zeitschrift", + // "journal.page.description": "Description", + "journal.page.description": "Beschreibung", + // "journal.page.editor": "Editor-in-Chief", + "journal.page.editor": "Chefredakteur", + // "journal.page.issn": "ISSN", + "journal.page.issn": "ISSN", + // "journal.page.publisher": "Publisher", + "journal.page.publisher": "Verlag", + // "journal.page.titleprefix": "Journal: ", + "journal.page.titleprefix": "Zeitschrift: ", + // "journal.search.results.head": "Journal Search Results", + "journal.search.results.head": "Zeitschrift Suchergebenisse", + // "journal.search.title": "DSpace Angular :: Journal Search", + "journal.search.title": "DSpace Angular :: Zeitschriftensuche", + + // "journalissue.listelement.badge": "Journal Issue", + "journalissue.listelement.badge": "Zeitschriftenausgabe", + // "journalissue.page.description": "Description", + "journalissue.page.description": "Beschreibeung", + // "journalissue.page.issuedate": "Issue Date", + "journalissue.page.issuedate": "Erscheinungsdatum", + // "journalissue.page.journal-issn": "Journal ISSN", + "journalissue.page.journal-issn": "ISSN der Zeitschrift", + // "journalissue.page.journal-title": "Journal Title", + "journalissue.page.journal-title": "Titel der Zeitschrift", + // "journalissue.page.keyword": "Keywords", + "journalissue.page.keyword": "Schlagwörter", + // "journalissue.page.number": "Number", + "journalissue.page.number": "Zählung", + // "journalissue.page.titleprefix": "Journal Issue: ", + "journalissue.page.titleprefix": "Zeitschriftenausgabe: ", + + // "journalvolume.listelement.badge": "Journal Volume", + "journalvolume.listelement.badge": "Zeitschriftenband", + // "journalvolume.page.description": "Description", + "journalvolume.page.description": "Beschreibung", + // "journalvolume.page.issuedate": "Issue Date", + "journalvolume.page.issuedate": "Erscheinungsdatum", + // "journalvolume.page.titleprefix": "Journal Volume: ", + "journalvolume.page.titleprefix": "Zeitschriftenband: ", + // "journalvolume.page.volume": "Volume", + "journalvolume.page.volume": "Band", + + // "loading.browse-by": "Loading items...", + "loading.browse-by": "Ressourcen am laden...", + // "loading.browse-by-page": "Loading page...", + "loading.browse-by-page": "Seite am Laden...", + // "loading.collection": "Loading collection...", + "loading.collection": "Sammlung am Laden...", + // "loading.collections": "Loading collections...", + "loading.collections": "Sammlungen am Laden...", + // "loading.community": "Loading community...", + "loading.community": "Bereich am Laden...", + // "loading.default": "Loading...", + "loading.default": "Am Laden...", + // "loading.item": "Loading item...", + "loading.item": "Ressource am Laden...", + // "loading.items": "Loading items...", + "loading.items": "Ressourcen am Laden...", + // "loading.mydspace-results": "Loading items...", + "loading.mydspace-results": "Ressourcen am Laden...", + // "loading.objects": "Loading...", + "loading.objects": "Am Laden...", + // "loading.recent-submissions": "Loading recent submissions...", + "loading.recent-submissions": "Aktuellste Veröffentlichungen am Laden...", + // "loading.search-results": "Loading search results...", + "loading.search-results": "Suchergebnisse am Laden...", + // "loading.sub-collections": "Loading sub-collections...", + "loading.sub-collections": "Untersammlungen am Laden...", + // "loading.sub-communities": "Loading sub-communities...", + "loading.sub-communities": "Teilbereiche am Laden...", + // "loading.top-level-communities": "Loading top-level communities...", + "loading.top-level-communities": "Hauptbereiche am Laden...", + + // "login.form.email": "Email address", "login.form.email": "E-Mail-Adresse", + // "login.form.forgot-password": "Have you forgotten your password?", "login.form.forgot-password": "Haben Sie Ihr Passwort vergessen?", - "login.form.header": "Bitte Loggen Sie sich ein.", - "login.form.new-user": "Sind Sie neu hier? Klicken Sie hier, um sich zu registrieren.", + // "login.form.header": "Please log in to DSpace", + "login.form.header": "Bitte loggen Sie sich ein.", + // "login.form.new-user": "New user? Click here to register.", + "login.form.new-user": "Neu hier? Klicken Sie hier, um sich zu registrieren.", + // "login.form.password": "Password", "login.form.password": "Passwort", + // "login.form.submit": "Log in", "login.form.submit": "Einloggen", + // "login.title": "Login", "login.title": "Einloggen", - "logout.form.header": "Ausloggen aus DSpace", - "logout.form.submit": "Ausloggen", - "logout.title": "Ausloggen", + // "logout.form.header": "Log out from DSpace", + "logout.form.header": "Aus dem Repositorium abmelden", + // "logout.form.submit": "Log out", + "logout.form.submit": "Abmelden", + // "logout.title": "Logout", + "logout.title": "Abmelden", - "nav.home": "Zur Startseite", - "nav.login": "Anmelden", - "nav.logout": "Abmelden", + // "menu.header.admin": "Admin", + "menu.header.admin": "Administration", + // "menu.header.image.logo": "Repository logo", + "menu.header.image.logo": "Logo des Repositorium", - "pagination.results-per-page": "Ergebnisse pro Seite", - "pagination.showing.detail": "{{ range }} bis {{ total }}", - "pagination.showing.label": "Anzeige der Treffer ", - "pagination.sort-direction": "Sortiermöglichkeiten", + // "menu.section.access_control": "Access Control", + "menu.section.access_control": "Zugriffskontrolle", + // "menu.section.access_control_authorizations": "Authorizations", + "menu.section.access_control_authorizations": "Rechte", + // "menu.section.access_control_groups": "Groups", + "menu.section.access_control_groups": "Gruppen", + // "menu.section.access_control_people": "People", + "menu.section.access_control_people": "Personen", + // "menu.section.browse_community": "This Community", + "menu.section.browse_community": "Dieser Bereich", + // "menu.section.browse_community_by_author": "By Author", + "menu.section.browse_community_by_author": "Nach Autor/in", + // "menu.section.browse_community_by_issue_date": "By Issue Date", + "menu.section.browse_community_by_issue_date": "Nach Erscheinungsdateum", + // "menu.section.browse_community_by_title": "By Title", + "menu.section.browse_community_by_title": "Nach Titel", + // "menu.section.browse_global": "All of DSpace", + "menu.section.browse_global": "Das gesamte Repositorium", + // "menu.section.browse_global_by_author": "By Author", + "menu.section.browse_global_by_author": "Nach Autor/in", + // "menu.section.browse_global_by_dateissued": "By Issue Date", + "menu.section.browse_global_by_dateissued": "Nach Erscheinungsjahr", + // "menu.section.browse_global_by_subject": "By Subject", + "menu.section.browse_global_by_subject": "Nach Schlagwort", + // "menu.section.browse_global_by_title": "By Title", + "menu.section.browse_global_by_title": "Nach Titel", + // "menu.section.browse_global_communities_and_collections": "Communities & Collections", + "menu.section.browse_global_communities_and_collections": "Bereiche & Sammlungen", + + // "menu.section.control_panel": "Control Panel", + "menu.section.control_panel": "Kontrollfeld", + // "menu.section.curation_task": "Curation Task", + "menu.section.curation_task": "Datenpflegeroutinen", + + // "menu.section.edit": "Edit", + "menu.section.edit": "Bearbeiten", + // "menu.section.edit_collection": "Collection", + "menu.section.edit_collection": "Sammlung", + // "menu.section.edit_community": "Community", + "menu.section.edit_community": "Bereich", + // "menu.section.edit_item": "Item", + "menu.section.edit_item": "Ressource", + + // "menu.section.export": "Export", + "menu.section.export": "Export", + // "menu.section.export_collection": "Collection", + "menu.section.export_collection": "Sammlung", + // "menu.section.export_community": "Community", + "menu.section.export_community": "Bereich", + // "menu.section.export_item": "Item", + "menu.section.export_item": "Ressoruce", + // "menu.section.export_metadata": "Metadata", + "menu.section.export_metadata": "Metadaten", + + // "menu.section.find": "Find", + "menu.section.find": "Finden", + // "menu.section.find_items": "Items", + "menu.section.find_items": "Ressourcen", + // "menu.section.find_private_items": "Private Items", + "menu.section.find_private_items": "Private Ressourcen", + // "menu.section.find_withdrawn_items": "Withdrawn Items", + "menu.section.find_withdrawn_items": "Zurückgezogene Ressourcen", + + // "menu.section.icon.access_control": "Access Control menu section", + "menu.section.icon.access_control": "Menübereich Zugriffskontrolle", + // "menu.section.icon.control_panel": "Control Panel menu section", + "menu.section.icon.control_panel": "Menübereich Kontrollfeld", + // "menu.section.icon.curation_task": "Curation Task menu section", + "menu.section.icon.curation_task": "Menübereich Datepflegeroutinen", + // "menu.section.icon.edit": "Edit menu section", + "menu.section.icon.edit": "Menübereich bearbeiten", + // "menu.section.icon.export": "Export menu section", + "menu.section.icon.export": "Menübereich Export", + // "menu.section.icon.find": "Find menu section", + "menu.section.icon.find": "Menübereich Suche", + // "menu.section.icon.import": "Import menu section", + "menu.section.icon.import": "Menübereich Import", + // "menu.section.icon.new": "New menu section", + "menu.section.icon.new": "Neuer Menübereich", + // "menu.section.icon.pin": "Pin sidebar", + "menu.section.icon.pin": "Seitenleiste Anheften", + // "menu.section.icon.registries": "Registries menu section", + "menu.section.icon.registries": "Menübereich Referenzlisten", + // "menu.section.icon.statistics_task": "Statistics Task menu section", + "menu.section.icon.statistics_task": "Menübereich Statistikaufgaben", + // "menu.section.icon.unpin": "Unpin sidebar", + "menu.section.icon.unpin": "Seitenbereich Loslösen", + + // "menu.section.import": "Import", + "menu.section.import": "Import", + // "menu.section.import_batch": "Batch Import (ZIP)", + "menu.section.import_batch": "Import (ZIP)", + // "menu.section.import_metadata": "Metadata", + "menu.section.import_metadata": "Metadaten", + + // "menu.section.new": "New", + "menu.section.new": "Neu", + // "menu.section.new_collection": "Collection", + "menu.section.new_collection": "Sammlung", + // "menu.section.new_community": "Community", + "menu.section.new_community": "Bereich", + // "menu.section.new_item": "Item", + "menu.section.new_item": "Ressource", + // "menu.section.new_item_version": "Item Version", + "menu.section.new_item_version": "Ressourcenversion", + + // "menu.section.pin": "Pin sidebar", + "menu.section.pin": "Seitenleiste anheften", + // "menu.section.unpin": "Unpin sidebar", + "menu.section.unpin": "Seitenleiste loslösen", + + // "menu.section.registries": "Registries", + "menu.section.registries": "Referenzlisten", + // "menu.section.registries_format": "Format", + "menu.section.registries_format": "Formate", + // "menu.section.registries_metadata": "Metadata", + "menu.section.registries_metadata": "Metadaten", + + // "menu.section.statistics": "Statistics", + "menu.section.statistics": "Statistiken", + // "menu.section.statistics_task": "Statistics Task", + "menu.section.statistics_task": "Statistikaufgaben", + + // "menu.section.toggle.access_control": "Toggle Access Control section", + "menu.section.toggle.access_control": "Bereich Zugriffskontrolle umschalten", + // "menu.section.toggle.control_panel": "Toggle Control Panel section", + "menu.section.toggle.control_panel": "Bereich Kontrollfeld umschalten", + // "menu.section.toggle.curation_task": "Toggle Curation Task section", + "menu.section.toggle.curation_task": "Bereich Datenpflegeroutinen umschalten", + // "menu.section.toggle.edit": "Toggle Edit section", + "menu.section.toggle.edit": "Bereich Bearbeiten umschalten", + // "menu.section.toggle.export": "Toggle Export section", + "menu.section.toggle.export": "Bereich Export umschalten", + // "menu.section.toggle.find": "Toggle Find section", + "menu.section.toggle.find": "Bereich Suche umschalten", + // "menu.section.toggle.import": "Toggle Import section", + "menu.section.toggle.import": "Bereich Import umschalten", + // "menu.section.toggle.new": "Toggle New section", + "menu.section.toggle.new": "Neuen Bereich umschalten", + // "menu.section.toggle.registries": "Toggle Registries section", + "menu.section.toggle.registries": "Bereich Referenzlisten umschalten", + // "menu.section.toggle.statistics_task": "Toggle Statistics Task section", + "menu.section.toggle.statistics_task": "Bereich Statistikaufgaben umschalten", + + // "mydspace.description": "", + "mydspace.description": "", + // "mydspace.general.text-here": "HERE", + "mydspace.general.text-here": "Hier", + // "mydspace.messages.controller-help": "Select this option to send a message to item's submitter.", + "mydspace.messages.controller-help": "Wählen Sie diese Option, um dem/derjenigen, die die Ressource eingereicht hat, eine Nachricht zu schicken.", + // "mydspace.messages.description-placeholder": "Insert your message here...", + "mydspace.messages.description-placeholder": "Geben Sie Ihre Nachricht hier ein...", + // "mydspace.messages.hide-msg": "Hide message", + "mydspace.messages.hide-msg": "Nachricht ausblenden", + // "mydspace.messages.mark-as-read": "Mark as read", + "mydspace.messages.mark-as-read": "Als gelesen markieren", + // "mydspace.messages.mark-as-unread": "Mark as unread", + "mydspace.messages.mark-as-unread": "Als ungelesen markieren", + // "mydspace.messages.no-content": "No content.", + "mydspace.messages.no-content": "Kein Inhalt.", + // "mydspace.messages.no-messages": "No messages yet.", + "mydspace.messages.no-messages": "Noch keine Nachrichten.", + // "mydspace.messages.send-btn": "Send", + "mydspace.messages.send-btn": "Senden", + // "mydspace.messages.show-msg": "Show message", + "mydspace.messages.show-msg": "Nachricht anzeigen", + // "mydspace.messages.subject-placeholder": "Subject...", + "mydspace.messages.subject-placeholder": "Betreff...", + // "mydspace.messages.submitter-help": "Select this option to send a message to controller.", + "mydspace.messages.submitter-help": "Wählen Sie diese Option, um dem Supervisor eine Nachricht zu schicken.", + // "mydspace.messages.title": "Messages", + "mydspace.messages.title": "Nachrichten", + // "mydspace.messages.to": "To", + "mydspace.messages.to": "An", + // "mydspace.new-submission": "New submission", + "mydspace.new-submission": "Neue Veröffentlichung", + // "mydspace.results.head": "Your submissions", + "mydspace.results.head": "Ihre Veröffentlichungen", + // "mydspace.results.no-abstract": "No Abstract", + "mydspace.results.no-abstract": "Keine Zusammenfassung", + // "mydspace.results.no-authors": "No Authors", + "mydspace.results.no-authors": "Keine AutorInnen", + // "mydspace.results.no-collections": "No Collections", + "mydspace.results.no-collections": "Keine Sammlungen", + // "mydspace.results.no-date": "No Date", + "mydspace.results.no-date": "Kein Datum", + // "mydspace.results.no-files": "No Files", + "mydspace.results.no-files": "Keine Dateien", + // "mydspace.results.no-results": "There were no items to show", + "mydspace.results.no-results": "Es gibt keine Ressourcen anzuzeigen", + // "mydspace.results.no-title": "No title", + "mydspace.results.no-title": "Kein Titel", + // "mydspace.results.no-uri": "No Uri", + "mydspace.results.no-uri": "Keine URI", + // "mydspace.show.workflow": "All tasks", + "mydspace.show.workflow": "Alle Aufgaben", + // "mydspace.show.workspace": "Your Submissions", + "mydspace.show.workspace": "Ihre Veröffentlichungen", + // "mydspace.status.archived": "Archived", + "mydspace.status.archived": "Archiviert", + // "mydspace.status.validation": "Validation", + "mydspace.status.validation": "Validierung", + // "mydspace.status.waiting-for-controller": "Waiting for controller", + "mydspace.status.waiting-for-controller": "Warten auf die Überprüfung", + // "mydspace.status.workflow": "Workflow", + "mydspace.status.workflow": "Geschäftsgang", + // "mydspace.status.workspace": "Workspace", + "mydspace.status.workspace": "Arbeitsbereich", + // "mydspace.title": "MyDSpace", + "mydspace.title": "Mein DSpace", + // "mydspace.upload.upload-failed": "Error creating new workspace. Please verify the content uploaded before retry.", + "mydspace.upload.upload-failed": "Fehler beim Anlegen eines neuen Arbeitsbereiches. Bitte überprüfen Sie den Inhalt bevor Sie es nochmal versuchen.", + // "mydspace.upload.upload-multiple-successful": "{{qty}} new workspace items created.", + "mydspace.upload.upload-multiple-successful": "{{qty}} neue(s) Arbeitsbereichressource(n) angelegt.", + // "mydspace.upload.upload-successful": "New workspace item created. Click {{here}} for edit it.", + "mydspace.upload.upload-successful": "Neue Arbeitsbereichressoruce angelegt. Klicken Sie hier {{here}}, um sie zu bearbeiten.", + // "mydspace.view-btn": "View", + "mydspace.view-btn": "Anzeige", + + // "nav.browse.header": "All of DSpace", + "nav.browse.header": "Das gesamte Repositorium", + // "nav.community-browse.header": "By Community", + "nav.community-browse.header": "Nach Bereich", + // "nav.language": "Language switch", + "nav.language": "Sprachumschalter", + // "nav.login": "Log In", + "nav.login": "Einloggen", + // "nav.logout": "Log Out", + "nav.logout": "Ausloggen", + // "nav.mydspace": "MyDSpace", + "nav.mydspace": "Mein DSpace", + // "nav.search": "Search", + "nav.search": "Suche", + // "nav.statistics.header": "Statistics", + "nav.statistics.header": "Statistiken", + + // "orgunit.listelement.badge": "Organizational Unit", + "orgunit.listelement.badge": "Organisationseinheit", + // "orgunit.page.city": "City", + "orgunit.page.city": "Stadt", + // "orgunit.page.country": "Country", + "orgunit.page.country": "Land", + // "orgunit.page.dateestablished": "Date established", + "orgunit.page.dateestablished": "Ursprungsdatum", + // "orgunit.page.description": "Description", + "orgunit.page.description": "Beschreibung", + // "orgunit.page.id": "ID", + "orgunit.page.id": "ID", + // "orgunit.page.titleprefix": "Organizational Unit: ", + "orgunit.page.titleprefix": "Organisationseinheit: ", + + // "pagination.results-per-page": "Results Per Page", + "pagination.results-per-page": "Anzeige pro Seite", + // "pagination.showing.detail": "{{ range }} of {{ total }}", + "pagination.showing.detail": "{{ range }} von {{ total }}", + // "pagination.showing.label": "Now showing ", + "pagination.showing.label": "Gerade angezeigt ", + // "pagination.sort-direction": "Sort Options", + "pagination.sort-direction": "Sortieroptionen", + + // "person.listelement.badge": "Person", + "person.listelement.badge": "Person", + // "person.page.birthdate": "Birth Date", + "person.page.birthdate": "Geburtsdatum", + // "person.page.email": "Email Address", + "person.page.email": "E-Mail-Adresse", + // "person.page.firstname": "First Name", + "person.page.firstname": "Vorname", + // "person.page.jobtitle": "Job Title", + "person.page.jobtitle": "Berufsbeschreibung", + // "person.page.lastname": "Last Name", + "person.page.lastname": "Nachname", + // "person.page.link.full": "Show all metadata", + "person.page.link.full": "Alle Metadaten anzeigen", + // "person.page.orcid": "ORCID", + "person.page.orcid": "ORCID", + // "person.page.staffid": "Staff ID", + "person.page.staffid": "Personalnummer", + // "person.page.titleprefix": "Person: ", + "person.page.titleprefix": "Person: ", + // "person.search.results.head": "Person Search Results", + "person.search.results.head": "Ergebnisse der Personensuche", + // "person.search.title": "DSpace Angular :: Person Search", + "person.search.title": "DSpace Angular :: Personensuche", + + // "project.listelement.badge": "Research Project", + "project.listelement.badge": "Forschungsprojekt", + // "project.page.contributor": "Contributors", + "project.page.contributor": "Beteiligte", + // "project.page.description": "Description", + "project.page.description": "Beschreibung", + // "project.page.expectedcompletion": "Expected Completion", + "project.page.expectedcompletion": "Erwartetes Abschlussdatum", + // "project.page.funder": "Funders", + "project.page.funder": "Förderer", + // "project.page.id": "ID", + "project.page.id": "ID", + // "project.page.keyword": "Keywords", + "project.page.keyword": "Schlagwörter", + // "project.page.status": "Status", + "project.page.status": "Status", + // "project.page.titleprefix": "Research Project: ", + "project.page.titleprefix": "Forschungsvorhaben: ", + + // "publication.listelement.badge": "Publication", + "publication.listelement.badge": "Veröffentlichung", + // "publication.page.description": "Description", + "publication.page.description": "Beschreibung", + // "publication.page.journal-issn": "Journal ISSN", + "publication.page.journal-issn": "Zeitschrift ISSN", + // "publication.page.journal-title": "Journal Title", + "publication.page.journal-title": "Zeitschriftentitel", + // "publication.page.publisher": "Publisher", + "publication.page.publisher": "Verlag", + // "publication.page.titleprefix": "Publication: ", + "publication.page.titleprefix": "Publikation: ", + // "publication.page.volume-title": "Volume Title", + "publication.page.volume-title": "Bandtitel", + // "publication.search.results.head": "Publication Search Results", + "publication.search.results.head": "Suchergebnisse Publikationen", + // "publication.search.title": "DSpace Angular :: Publication Search", + "publication.search.title": "DSpace Angular :: Publikationssuche", + + // "relationships.isAuthorOf": "Authors", + "relationships.isAuthorOf": "AutorInnen", + // "relationships.isIssueOf": "Journal Issues", + "relationships.isIssueOf": "Zeitschriftenausgaben", + // "relationships.isJournalIssueOf": "Journal Issue", + "relationships.isJournalIssueOf": "Zeitschriftenausgabe", + // "relationships.isJournalOf": "Journals", + "relationships.isJournalOf": "Zeitschriften", + // "relationships.isOrgUnitOf": "Organizational Units", + "relationships.isOrgUnitOf": "Organisationseinheiten", + // "relationships.isPersonOf": "Authors", + "relationships.isPersonOf": "AutorInnen", + // "relationships.isProjectOf": "Research Projects", + "relationships.isProjectOf": "Forschungsvorhaben", + // "relationships.isPublicationOf": "Publications", + "relationships.isPublicationOf": "Publikationen", + // "relationships.isPublicationOfJournalIssue": "Articles", + "relationships.isPublicationOfJournalIssue": "Artikel", + // "relationships.isSingleJournalOf": "Journal", + "relationships.isSingleJournalOf": "Zeitschrift", + // "relationships.isSingleVolumeOf": "Journal Volume", + "relationships.isSingleVolumeOf": "Zeitschriftenband", + // "relationships.isVolumeOf": "Journal Volumes", + "relationships.isVolumeOf": "Zeitschriftenbände", + + // "search.description": "", "search.description": "", + // "search.switch-configuration.title": "Show", + "search.switch-configuration.title": "Zeige", + // "search.title": "DSpace Angular :: Search", "search.title": "DSpace Angular :: Suche", - "search.filters.applied.f.author": "Autor", + // "search.filters.applied.f.author": "Author", + "search.filters.applied.f.author": "AutorIn", + // "search.filters.applied.f.dateIssued.max": "End date", "search.filters.applied.f.dateIssued.max": "Enddatum", + // "search.filters.applied.f.dateIssued.min": "Start date", "search.filters.applied.f.dateIssued.min": "Anfangsdatum", - "search.filters.applied.f.has_content_in_original_bundle": "Besitzt Dateien", + // "search.filters.applied.f.dateSubmitted": "Date submitted", + "search.filters.applied.f.dateSubmitted": "Datum der Einreichung", + // "search.filters.applied.f.entityType": "Item Type", + "search.filters.applied.f.entityType": "Art der Ressource", + // "search.filters.applied.f.has_content_in_original_bundle": "Has files", + "search.filters.applied.f.has_content_in_original_bundle": "Hat Dateien", + // "search.filters.applied.f.itemtype": "Type", + "search.filters.applied.f.itemtype": "Typ", + // "search.filters.applied.f.namedresourcetype": "Status", + "search.filters.applied.f.namedresourcetype": "Status", + // "search.filters.applied.f.subject": "Subject", "search.filters.applied.f.subject": "Thema", + // "search.filters.applied.f.submitter": "Submitter", + "search.filters.applied.f.submitter": "Einreichende(r)", - "search.filters.filter.author.head": "Autor", - "search.filters.filter.author.placeholder": "Autor", + // "search.filters.filter.author.head": "Author", + "search.filters.filter.author.head": "AutorIn", + // "search.filters.filter.author.placeholder": "Author name", + "search.filters.filter.author.placeholder": "Name des/r AutorIn", + // "search.filters.filter.birthDate.head": "Birth Date", + "search.filters.filter.birthDate.head": "Geburtsdatum", + // "search.filters.filter.birthDate.placeholder": "Birth Date", + "search.filters.filter.birthDate.placeholder": "Geburtsdatum", + // "search.filters.filter.creativeDatePublished.head": "Date Published", + "search.filters.filter.creativeDatePublished.head": "Erscheinungsdatum", + // "search.filters.filter.creativeDatePublished.placeholder": "Date Published", + "search.filters.filter.creativeDatePublished.placeholder": "Erscheinungsdatum", + // "search.filters.filter.creativeWorkEditor.head": "Editor", + "search.filters.filter.creativeWorkEditor.head": "Herausgeber", + // "search.filters.filter.creativeWorkEditor.placeholder": "Editor", + "search.filters.filter.creativeWorkEditor.placeholder": "Herausgeber", + // "search.filters.filter.creativeWorkKeywords.head": "Subject", + "search.filters.filter.creativeWorkKeywords.head": "Thema", + // "search.filters.filter.creativeWorkKeywords.placeholder": "Subject", + "search.filters.filter.creativeWorkKeywords.placeholder": "Thema", + // "search.filters.filter.creativeWorkPublisher.head": "Publisher", + "search.filters.filter.creativeWorkPublisher.head": "Verlag", + // "search.filters.filter.creativeWorkPublisher.placeholder": "Publisher", + "search.filters.filter.creativeWorkPublisher.placeholder": "Verlag", + // "search.filters.filter.dateIssued.head": "Date", "search.filters.filter.dateIssued.head": "Datum", - "search.filters.filter.dateIssued.max.placeholder": "Frühestes Datum", - "search.filters.filter.dateIssued.min.placeholder": "Ältestes Datum", - "search.filters.filter.has_content_in_original_bundle.head": "Besitzt Dateien", + // "search.filters.filter.dateIssued.max.placeholder": "Minimum Date", + "search.filters.filter.dateIssued.max.placeholder": "Ältestes Datum", + // "search.filters.filter.dateIssued.min.placeholder": "Maximum Date", + "search.filters.filter.dateIssued.min.placeholder": "Jüngstes Datum", + // "search.filters.filter.dateSubmitted.head": "Date submitted", + "search.filters.filter.dateSubmitted.head": "Datum der Einreichung", + // "search.filters.filter.dateSubmitted.placeholder": "Date submitted", + "search.filters.filter.dateSubmitted.placeholder": "Datum der Einreichung", + // "search.filters.filter.entityType.head": "Item Type", + "search.filters.filter.entityType.head": "Art der Ressource", + // "search.filters.filter.entityType.placeholder": "Item Type", + "search.filters.filter.entityType.placeholder": "Art der Ressoruce", + // "search.filters.filter.has_content_in_original_bundle.head": "Has files", + "search.filters.filter.has_content_in_original_bundle.head": "Enthält Dateien", + // "search.filters.filter.itemtype.head": "Type", + "search.filters.filter.itemtype.head": "Typ", + // "search.filters.filter.itemtype.placeholder": "Type", + "search.filters.filter.itemtype.placeholder": "Typ", + // "search.filters.filter.jobTitle.head": "Job Title", + "search.filters.filter.jobTitle.head": "Berufsbezeichnung", + // "search.filters.filter.jobTitle.placeholder": "Job Title", + "search.filters.filter.jobTitle.placeholder": "Berufsbezeichnung", + // "search.filters.filter.knowsLanguage.head": "Known language", + "search.filters.filter.knowsLanguage.head": "Bekannte Sprache", + // "search.filters.filter.knowsLanguage.placeholder": "Known language", + "search.filters.filter.knowsLanguage.placeholder": "Bekannte Sprache", + // "search.filters.filter.namedresourcetype.head": "Status", + "search.filters.filter.namedresourcetype.head": "Status", + // "search.filters.filter.namedresourcetype.placeholder": "Status", + "search.filters.filter.namedresourcetype.placeholder": "Status", + // "search.filters.filter.objectpeople.head": "People", + "search.filters.filter.objectpeople.head": "Personen", + // "search.filters.filter.objectpeople.placeholder": "People", + "search.filters.filter.objectpeople.placeholder": "Personen", + // "search.filters.filter.organizationAddressCountry.head": "Country", + "search.filters.filter.organizationAddressCountry.head": "Land", + // "search.filters.filter.organizationAddressCountry.placeholder": "Country", + "search.filters.filter.organizationAddressCountry.placeholder": "Land", + // "search.filters.filter.organizationAddressLocality.head": "City", + "search.filters.filter.organizationAddressLocality.head": "Stadt", + // "search.filters.filter.organizationAddressLocality.placeholder": "City", + "search.filters.filter.organizationAddressLocality.placeholder": "Stadt", + // "search.filters.filter.organizationFoundingDate.head": "Date Founded", + "search.filters.filter.organizationFoundingDate.head": "Gründungsdatum", + // "search.filters.filter.organizationFoundingDate.placeholder": "Date Founded", + "search.filters.filter.organizationFoundingDate.placeholder": "Gründungsdatum", + // "search.filters.filter.scope.head": "Scope", "search.filters.filter.scope.head": "Bereich", + // "search.filters.filter.scope.placeholder": "Scope filter", "search.filters.filter.scope.placeholder": "Bereichsfilter", - "search.filters.filter.show-less": "Zeige weniger", - "search.filters.filter.show-more": "Zeige mehr", - "search.filters.filter.subject.head": "Schlagwort", - "search.filters.filter.subject.placeholder": "Schlagwort", + // "search.filters.filter.show-less": "Collapse", + "search.filters.filter.show-less": "Zusammenklappen", + // "search.filters.filter.show-more": "Show more", + "search.filters.filter.show-more": "Mehr anzeigen", + // "search.filters.filter.subject.head": "Subject", + "search.filters.filter.subject.head": "Thema", + // "search.filters.filter.subject.placeholder": "Subject", + "search.filters.filter.subject.placeholder": "Thema", + // "search.filters.filter.submitter.head": "Submitter", + "search.filters.filter.submitter.head": "Einreichende(r)", + // "search.filters.filter.submitter.placeholder": "Submitter", + "search.filters.filter.submitter.placeholder": "Einreichende(r)", + // "search.filters.head": "Filters", "search.filters.head": "Filter", + // "search.filters.reset": "Reset filters", "search.filters.reset": "Filter zurücksetzen", + // "search.form.search": "Search", "search.form.search": "Suche", - "search.form.search_dspace": "DSpace durchsuchen", + // "search.form.search_dspace": "Search DSpace", + "search.form.search_dspace": "Suche in DSpace", + // "search.form.search_mydspace": "Search MyDSpace", + "search.form.search_mydspace": "Suche im persönlichen Arbeitsbereich", + // "search.results.head": "Search Results", "search.results.head": "Suchergebnisse", - "search.results.no-results": "Zu dieser Suche gibt es keine Treffer.", + // "search.results.no-results": "Your search returned no results. Having trouble finding what you're looking for? Try putting", + "search.results.no-results": "Ihre Suche führte zu keinem Ergebnis. Versuchen Sie es mit ", + // "search.results.no-results-link": "quotes around it", + "search.results.no-results-link": "Anführungszeichen", + // "search.sidebar.close": "Back to results", "search.sidebar.close": "Zurück zu den Ergebnissen", + // "search.sidebar.filters.title": "Filters", "search.sidebar.filters.title": "Filter", + // "search.sidebar.open": "Search Tools", "search.sidebar.open": "Suchwerkzeuge", + // "search.sidebar.results": "results", "search.sidebar.results": "Ergebnisse", - "search.sidebar.settings.rpp": "Treffer pro Seite", - "search.sidebar.settings.sort-by": "Sortiere nach", + // "search.sidebar.settings.rpp": "Results per page", + "search.sidebar.settings.rpp": "Ergebnisse pro Seite", + // "search.sidebar.settings.sort-by": "Sort By", + "search.sidebar.settings.sort-by": "Sortieren nach", + // "search.sidebar.settings.title": "Settings", "search.sidebar.settings.title": "Einstellungen", - "search.view-switch.show-grid": "Zeige als Raster", - "search.view-switch.show-list": "Zeige als Liste", + // "search.view-switch.show-detail": "Show detail", + "search.view-switch.show-detail": "Detailanzeige", + // "search.view-switch.show-grid": "Show as grid", + "search.view-switch.show-grid": "Anzeige als Raster", + // "search.view-switch.show-list": "Show as list", + "search.view-switch.show-list": "Anzeige als Liste", + // "sorting.dc.title.ASC": "Title Ascending", "sorting.dc.title.ASC": "Titel aufsteigend", + // "sorting.dc.title.DESC": "Title Descending", "sorting.dc.title.DESC": "Titel absteigend", + // "sorting.score.DESC": "Relevance", "sorting.score.DESC": "Relevanz", + // "submission.edit.title": "Edit Submission", + "submission.edit.title": "Einreichung bearbeiten", + // "submission.general.cannot_submit": "You have not the privilege to make a new submission.", + "submission.general.cannot_submit": "Sie verfügen nicht über die Rechte, eine neue Einreichung zu machen.", + // "submission.general.deposit": "Deposit", + "submission.general.deposit": "Einreichen", + // "submission.general.discard.confirm.cancel": "Cancel", + "submission.general.discard.confirm.cancel": "Abbrechen", + // "submission.general.discard.confirm.info": "This operation can't be undone. Are you sure?", + "submission.general.discard.confirm.info": "Diese Aktion kann nicht rückgängig gemacht werden. Sind Sie sicher?", + // "submission.general.discard.confirm.submit": "Yes, I'm sure", + "submission.general.discard.confirm.submit": "Ja, ich bin sicher", + // "submission.general.discard.confirm.title": "Discard submission", + "submission.general.discard.confirm.title": "Einreichung verwerfen", + // "submission.general.discard.submit": "Discard", + "submission.general.discard.submit": "Verwerfen", + // "submission.general.save": "Save", + "submission.general.save": "Speichern", + // "submission.general.save-later": "Save for later", + "submission.general.save-later": "Für später speichern", + + // "submission.sections.general.add-more": "Add more", + "submission.sections.general.add-more": "Mehr Hinzufügen", + // "submission.sections.general.collection": "Collection", + "submission.sections.general.collection": "Sammlung", + // "submission.sections.general.deposit_error_notice": "There was an issue when submitting the item, please try again later.", + "submission.sections.general.deposit_error_notice": "Beim Einreichen der Ressoruce ist ein Fehler aufgetreten. Bitte versuchen Sie es später noch einmal.", + // "submission.sections.general.deposit_success_notice": "Submission deposited successfully.", + "submission.sections.general.deposit_success_notice": "Veröffentlichung erfolgreich eingereicht", + // "submission.sections.general.discard_error_notice": "There was an issue when discarding the item, please try again later.", + "submission.sections.general.discard_error_notice": "Beim Verwerfen der Einreichung ist ein Fehler aufgetreten. Bitte versuchen Sie es später noch einmal", + // "submission.sections.general.discard_success_notice": "Submission discarded successfully.", + "submission.sections.general.discard_success_notice": "Einreichung erfolgreich verworfen.", + // "submission.sections.general.metadata-extracted": "New metadata have been extracted and added to the {{sectionId}} section.", + "submission.sections.general.metadata-extracted": "Neue Metainformation wurden extrahier unt dem Bereich {{sectionId}} zugeordnet.", + // "submission.sections.general.metadata-extracted-new-section": "New {{sectionId}} section has been added to submission.", + "submission.sections.general.metadata-extracted-new-section": "Neuer Bereich {{sectionId}} wurde zur Einreichung hinzugefügt.", + // "submission.sections.general.no-collection": "No collection found", + "submission.sections.general.no-collection": "Keine Sammlung gefunden", + // "submission.sections.general.no-sections": "No options available", + "submission.sections.general.no-sections": "Es stehen keine Optionen zur Verfügung", + // "submission.sections.general.save_error_notice": "There was an issue when saving the item, please try again later.", + "submission.sections.general.save_error_notice": "Beim Speichern der Ressource ist ein Fehler aufgetreten, bitte versuchen Sie es später noch einmal.", + // "submission.sections.general.save_success_notice": "Submission saved successfully.", + "submission.sections.general.save_success_notice": "Einreichung erfolgreich gespeichert.", + // "submission.sections.general.search-collection": "Search for a collection", + "submission.sections.general.search-collection": "Suche nach einer Sammlung", + // "submission.sections.general.sections_not_valid": "There are incomplete sections.", + "submission.sections.general.sections_not_valid": "Es gibt unvollständige Abschnitte.", + + // "submission.sections.submit.progressbar.cclicense": "Creative commons license", + "submission.sections.submit.progressbar.cclicense": "Creative Commons Lizenz", + // "submission.sections.submit.progressbar.describe.recycle": "Recycle", + "submission.sections.submit.progressbar.describe.recycle": "Wiederverwerten", + // "submission.sections.submit.progressbar.describe.stepcustom": "Describe", + "submission.sections.submit.progressbar.describe.stepcustom": "Beschreiben", + // "submission.sections.submit.progressbar.describe.stepone": "Describe", + "submission.sections.submit.progressbar.describe.stepone": "Beschreiben", + // "submission.sections.submit.progressbar.describe.steptwo": "Describe", + "submission.sections.submit.progressbar.describe.steptwo": "Beschreiben", + // "submission.sections.submit.progressbar.detect-duplicate": "Potential duplicates", + "submission.sections.submit.progressbar.detect-duplicate": "Mögliche Dubletten", + // "submission.sections.submit.progressbar.license": "Deposit license", + "submission.sections.submit.progressbar.license": "Einreichlizenz", + // "submission.sections.submit.progressbar.upload": "Upload files", + "submission.sections.submit.progressbar.upload": "Hochgeladene Dateien", + + // "submission.sections.upload.delete.confirm.cancel": "Cancel", + "submission.sections.upload.delete.confirm.cancel": "Abbrechen", + // "submission.sections.upload.delete.confirm.info": "This operation can't be undone. Are you sure?", + "submission.sections.upload.delete.confirm.info": "Diese Aktion kann nicht rückgängig gemacht werden. Sind Sie sicher?", + // "submission.sections.upload.delete.confirm.submit": "Yes, I'm sure", + "submission.sections.upload.delete.confirm.submit": "Ja, ich bin sicher", + // "submission.sections.upload.delete.confirm.title": "Delete bitstream", + "submission.sections.upload.delete.confirm.title": "Datei löschen", + // "submission.sections.upload.delete.submit": "Delete", + "submission.sections.upload.delete.submit": "Löschen", + // "submission.sections.upload.drop-message": "Drop files to attach them to the item", + "submission.sections.upload.drop-message": "Dateien herüberziehen, um sie der Ressource hinzuzufügen", + // "submission.sections.upload.form.access-condition-label": "Access condition type", + "submission.sections.upload.form.access-condition-label": "Zugriffsbedingung Typ", + // "submission.sections.upload.form.date-required": "Date is required.", + "submission.sections.upload.form.date-required": "Datum erforderlich.", + // "submission.sections.upload.form.from-label": "Access grant from", + "submission.sections.upload.form.from-label": "Zugriff gewährt ab", + // "submission.sections.upload.form.from-placeholder": "From", + "submission.sections.upload.form.from-placeholder": "Ab", + // "submission.sections.upload.form.group-label": "Group", + "submission.sections.upload.form.group-label": "Gruppe", + // "submission.sections.upload.form.group-required": "Group is required.", + "submission.sections.upload.form.group-required": "Gruppe ist erforderlich", + // "submission.sections.upload.form.until-label": "Access grant until", + "submission.sections.upload.form.until-label": "Zugriff gewährt bis", + // "submission.sections.upload.form.until-placeholder": "Until", + "submission.sections.upload.form.until-placeholder": "Bis", + // "submission.sections.upload.header.policy.default.nolist": "Uploaded files in the {{collectionName}} collection will be accessible according to the following group(s):", + "submission.sections.upload.header.policy.default.nolist": "In diese Sammlung {{collectionName}} hochgeladene Dateien werden für folgende(n) Gruppe(n) zugänglich sein:", + // "submission.sections.upload.header.policy.default.withlist": "Please note that uploaded files in the {{collectionName}} collection will be accessible, in addition to what is explicitly decided for the single file, with the following group(s):", + "submission.sections.upload.header.policy.default.withlist": "Bitte beachten Sie, dass in diese Sammlung {{collectionName}} hochgeladene Dateien zugüglich zu dem, was für einzelne Dateien entschieden wurde, für folgende Gruppe(n) zugänglich sein:", + // "submission.sections.upload.info": "Here you will find all the files currently in the item. You can update the fle metadata and access conditions or upload additional files just dragging & dropping them everywhere in the page", + "submission.sections.upload.info": "Hier finden Sie alle Dateien, die aktuell zur Ressource gehören. Sie können die Metadaten und Zugriffsrechte bearbeiten oder weitere Dateien hinzufügen, indem Sie sie einfach irgenwo auf diese Seite ziehen.", + // "submission.sections.upload.no-entry": "No", + "submission.sections.upload.no-entry": "Kein Eintrag", + // "submission.sections.upload.no-file-uploaded": "No file uploaded yet.", + "submission.sections.upload.no-file-uploaded": "Es wurde noch keine Datei hochgeladen", + // "submission.sections.upload.save-metadata": "Save metadata", + "submission.sections.upload.save-metadata": "Metadaten speichern", + // "submission.sections.upload.undo": "Cancel", + "submission.sections.upload.undo": "Abbrechen", + // "submission.sections.upload.upload-failed": "Upload failed", + "submission.sections.upload.upload-failed": "Hochladen fehlgeschlagen", + // "submission.sections.upload.upload-successful": "Upload successful", + "submission.sections.upload.upload-successful": "Hochladen erfolgreich", + + // "submission.submit.title": "Submission", + "submission.submit.title": "Einreichung", + + // "submission.workflow.generic.delete": "Delete", + "submission.workflow.generic.delete": "Löschen", + // "submission.workflow.generic.delete-help": "If you would to discard this item, select \"Delete\". You will then be asked to confirm it.", + "submission.workflow.generic.delete-help": "Wenn Sie die Ressource verwerfen möchten, Wählen Sie \"Löschen\". Sie werden dies noch einmal gefragt, um die Aktion zu bestätigen.", + // "submission.workflow.generic.edit": "Edit", + "submission.workflow.generic.edit": "Bearbeiten", + // "submission.workflow.generic.edit-help": "Select this option to change the item's metadata.", + "submission.workflow.generic.edit-help": "Wählen Sie diese Option, um die Metadaten der Ressource zu bearbeiten.", + // "submission.workflow.generic.view": "View", + "submission.workflow.generic.view": "Anzeige", + // "submission.workflow.generic.view-help": "Select this option to view the item's metadata.", + "submission.workflow.generic.view-help": "Wählen Sie diese Option, um die Metadaten der Ressourcen anzuzeigen", + + // "submission.workflow.tasks.claimed.approve": "Approve", + "submission.workflow.tasks.claimed.approve": "Zustimmen", + // "submission.workflow.tasks.claimed.approve_help": "If you have reviewed the item and it is suitable for inclusion in the collection, select \"Approve\".", + "submission.workflow.tasks.claimed.approve_help": "Wenn Sie die Ressource begutachtet und die Aufnahme in die Sammlung befürworten, wählen Sie \"Zustimmen\".", + // "submission.workflow.tasks.claimed.edit": "Edit", + "submission.workflow.tasks.claimed.edit": "Bearbeiten", + // "submission.workflow.tasks.claimed.edit_help": "Select this option to change the item's metadata.", + "submission.workflow.tasks.claimed.edit_help": "Wählen Sie diese Option, um die Metadaten der Ressource zu bearbeiten.", + // "submission.workflow.tasks.claimed.reject.reason.info": "Please enter your reason for rejecting the submission into the box below, indicating whether the submitter may fix a problem and resubmit.", + "submission.workflow.tasks.claimed.reject.reason.info": "Bitte geben Sie den Grund für die Ablehnung der eingereichten Ressource in das Feld unten ein. Bitte geben Sie an ob und wie der/die Einreichenden das Problem beheben und die Ressource erneut einreichen kann.", + // "submission.workflow.tasks.claimed.reject.reason.placeholder": "Describe the reason of reject", + "submission.workflow.tasks.claimed.reject.reason.placeholder": "Beschreiben Sie den Grund für die Ablehnung", + // "submission.workflow.tasks.claimed.reject.reason.submit": "Reject item", + "submission.workflow.tasks.claimed.reject.reason.submit": "Ressource Ablehnen", + // "submission.workflow.tasks.claimed.reject.reason.title": "Reason", + "submission.workflow.tasks.claimed.reject.reason.title": "Grund", + // "submission.workflow.tasks.claimed.reject.submit": "Reject", + "submission.workflow.tasks.claimed.reject.submit": "Ablehnen", + // "submission.workflow.tasks.claimed.reject_help": "If you have reviewed the item and found it is not suitable for inclusion in the collection, select \"Reject\". You will then be asked to enter a message indicating why the item is unsuitable, and whether the submitter should change something and resubmit.", + "submission.workflow.tasks.claimed.reject_help": "Wenn Sie die Ressource begutachte und als ungeeignet für die Aufnahme in die Sammlung befunden haben, wählen Sie \"Ablehnen\". Sie haben dann die Möglichkeit dem/der Einreichenden, den Grund für die Ablehnung zu erklären und ob es eine Möglichkeit gibt, durch entsprechenden Änderungen die Ressource erneut einzureichen.", + // "submission.workflow.tasks.claimed.return": "Return to pool", + "submission.workflow.tasks.claimed.return": "Zurück in den gemeinsamen Aufgabenbereich", + // "submission.workflow.tasks.claimed.return_help": "Return the task to the pool so that another user may perform the task.", + "submission.workflow.tasks.claimed.return_help": "Aufgabe in den gemeinsamen Aufgabenbereich überführen, so dass ein anderer Bearbeiter die Aufgabe übernehmen kann.", + + // "submission.workflow.tasks.generic.error": "Error occurred during operation...", + "submission.workflow.tasks.generic.error": "Ein Fehler ist aufgetreten...", + // "submission.workflow.tasks.generic.processing": "Processing...", + "submission.workflow.tasks.generic.processing": "Verarbeitung läuft...", + // "submission.workflow.tasks.generic.submitter": "Submitter", + "submission.workflow.tasks.generic.submitter": "Einreichende(r)", + // "submission.workflow.tasks.generic.success": "Operation successful", + "submission.workflow.tasks.generic.success": "Aktion erfolgreich", + + // "submission.workflow.tasks.pool.claim": "Claim", + "submission.workflow.tasks.pool.claim": "Übernehmen", + // "submission.workflow.tasks.pool.claim_help": "Assign this task to yourself.", + "submission.workflow.tasks.pool.claim_help": "Aufgabe übernehmen.", + // "submission.workflow.tasks.pool.hide-detail": "Hide detail", + "submission.workflow.tasks.pool.hide-detail": "Details verbergen", + // "submission.workflow.tasks.pool.show-detail": "Show detail", + "submission.workflow.tasks.pool.show-detail": "Details anzeigen", + + // "title": "DSpace", "title": "DSpace", + + // "uploader.browse": "browse", + "uploader.browse": "stöbern", + // "uploader.drag-message": "Drag & Drop your files here", + "uploader.drag-message": "Ziehen Sie Ihre Dateien hierhin", + // "uploader.or": ", or", + "uploader.or": " oder", + // "uploader.processing": "Processing", + "uploader.processing": "Bearbeitung läuft", + // "uploader.queue-length": "Queue length", + "uploader.queue-length": "Länge der Warteschleife", } diff --git a/resources/i18n/en.json5 b/resources/i18n/en.json5 index dfcb397f4f..caaf169c66 100644 --- a/resources/i18n/en.json5 +++ b/resources/i18n/en.json5 @@ -1,842 +1,1690 @@ { + "404.help": "We can't find the page you're looking for. The page may have been moved or deleted. You can use the button below to get back to the home page. ", + "404.link.home-page": "Take me to the home page", + "404.page-not-found": "page not found", + + "admin.registries.bitstream-formats.create.failure.content": "An error occurred while creating the new bitstream format.", + "admin.registries.bitstream-formats.create.failure.head": "Failure", + "admin.registries.bitstream-formats.create.head": "Create Bitstream format", + "admin.registries.bitstream-formats.create.new": "Add a new bitstream format", + "admin.registries.bitstream-formats.create.success.content": "The new bitstream format was successfully created.", + "admin.registries.bitstream-formats.create.success.head": "Success", + "admin.registries.bitstream-formats.delete.failure.amount": "Failed to remove {{ amount }} format(s)", + "admin.registries.bitstream-formats.delete.failure.head": "Failure", + "admin.registries.bitstream-formats.delete.success.amount": "Successfully removed {{ amount }} format(s)", + "admin.registries.bitstream-formats.delete.success.head": "Success", + "admin.registries.bitstream-formats.description": "This list of bitstream formats provides information about known formats and their support level.", + "admin.registries.bitstream-formats.edit.description.hint": "", + "admin.registries.bitstream-formats.edit.description.label": "Description", + "admin.registries.bitstream-formats.edit.extensions.hint": "Extensions are file extensions that are used to automatically identify the format of uploaded files. You can enter several extensions for each format.", + "admin.registries.bitstream-formats.edit.extensions.label": "File extensions", + "admin.registries.bitstream-formats.edit.extensions.placeholder": "Enter a file extenstion without the dot", + "admin.registries.bitstream-formats.edit.failure.content": "An error occurred while editing the bitstream format.", + "admin.registries.bitstream-formats.edit.failure.head": "Failure", + "admin.registries.bitstream-formats.edit.head": "Bitstream format: {{ format }}", + "admin.registries.bitstream-formats.edit.internal.hint": "Formats marked as internal are are hidden from the user, and used for administrative purposes.", + "admin.registries.bitstream-formats.edit.internal.label": "Internal", + "admin.registries.bitstream-formats.edit.mimetype.hint": "The MIME type associated with this format, does not have to be unique.", + "admin.registries.bitstream-formats.edit.mimetype.label": "MIME Type", + "admin.registries.bitstream-formats.edit.shortDescription.hint": "A unique name for this format, (e.g. Microsoft Word XP or Microsoft Word 2000)", + "admin.registries.bitstream-formats.edit.shortDescription.label": "Name", + "admin.registries.bitstream-formats.edit.success.content": "The bitstream format was successfully edited.", + "admin.registries.bitstream-formats.edit.success.head": "Success", + "admin.registries.bitstream-formats.edit.supportLevel.hint": "The level of support your institution pledges for this format.", + "admin.registries.bitstream-formats.edit.supportLevel.label": "Support level", + "admin.registries.bitstream-formats.head": "Bitstream Format Registry", + "admin.registries.bitstream-formats.no-items": "No bitstream formats to show.", + "admin.registries.bitstream-formats.table.delete": "Delete selected", + "admin.registries.bitstream-formats.table.deselect-all": "Deselect all", + "admin.registries.bitstream-formats.table.internal": "internal", + "admin.registries.bitstream-formats.table.mimetype": "MIME Type", + "admin.registries.bitstream-formats.table.name": "Name", + "admin.registries.bitstream-formats.table.return": "Return", + "admin.registries.bitstream-formats.table.supportLevel.KNOWN": "Known", + "admin.registries.bitstream-formats.table.supportLevel.SUPPORTED": "Supported", + "admin.registries.bitstream-formats.table.supportLevel.UNKNOWN": "Unknown", + "admin.registries.bitstream-formats.table.supportLevel.head": "Support Level", + "admin.registries.bitstream-formats.title": "DSpace Angular :: Bitstream Format Registry", + + "admin.registries.metadata.description": "The metadata registry maintains a list of all metadata fields available in the repository. These fields may be divided amongst multiple schemas. However, DSpace requires the qualified Dublin Core schema.", + "admin.registries.metadata.form.create": "Create metadata schema", + "admin.registries.metadata.form.edit": "Edit metadata schema", + "admin.registries.metadata.form.name": "Name", + "admin.registries.metadata.form.namespace": "Namespace", + "admin.registries.metadata.head": "Metadata Registry", + "admin.registries.metadata.schemas.no-items": "No metadata schemas to show.", + "admin.registries.metadata.schemas.table.delete": "Delete selected", + "admin.registries.metadata.schemas.table.id": "ID", + "admin.registries.metadata.schemas.table.name": "Name", + "admin.registries.metadata.schemas.table.namespace": "Namespace", + "admin.registries.metadata.title": "DSpace Angular :: Metadata Registry", + + "admin.registries.schema.description": "This is the metadata schema for \"{{namespace}}\".", + "admin.registries.schema.fields.head": "Schema metadata fields", + "admin.registries.schema.fields.no-items": "No metadata fields to show.", + "admin.registries.schema.fields.table.delete": "Delete selected", + "admin.registries.schema.fields.table.field": "Field", + "admin.registries.schema.fields.table.scopenote": "Scope Note", + "admin.registries.schema.form.create": "Create metadata field", + "admin.registries.schema.form.edit": "Edit metadata field", + "admin.registries.schema.form.element": "Element", + "admin.registries.schema.form.qualifier": "Qualifier", + "admin.registries.schema.form.scopenote": "Scope Note", + "admin.registries.schema.head": "Metadata Schema", + "admin.registries.schema.notification.created": "Successfully created metadata schema \"{{prefix}}\"", + "admin.registries.schema.notification.deleted.failure": "Failed to delete {{amount}} metadata schemas", + "admin.registries.schema.notification.deleted.success": "Successfully deleted {{amount}} metadata schemas", + "admin.registries.schema.notification.edited": "Successfully edited metadata schema \"{{prefix}}\"", + "admin.registries.schema.notification.failure": "Error", + "admin.registries.schema.notification.field.created": "Successfully created metadata field \"{{field}}\"", + "admin.registries.schema.notification.field.deleted.failure": "Failed to delete {{amount}} metadata fields", + "admin.registries.schema.notification.field.deleted.success": "Successfully deleted {{amount}} metadata fields", + "admin.registries.schema.notification.field.edited": "Successfully edited metadata field \"{{field}}\"", + "admin.registries.schema.notification.success": "Success", + "admin.registries.schema.return": "Return", + "admin.registries.schema.title": "DSpace Angular :: Metadata Schema Registry", + + "auth.errors.invalid-user": "Invalid email address or password.", + "auth.messages.expired": "Your session has expired. Please log in again.", + + "browse.comcol.by.author": "By Author", + "browse.comcol.by.dateissued": "By Issue Date", + "browse.comcol.by.subject": "By Subject", + "browse.comcol.by.title": "By Title", + "browse.comcol.head": "Browse", + "browse.empty": "No items to show.", + "browse.metadata.author": "Author", + "browse.metadata.dateissued": "Issue Date", + "browse.metadata.subject": "Subject", + "browse.metadata.title": "Title", + "browse.startsWith.choose_start": "(Choose start)", + "browse.startsWith.choose_year": "(Choose year)", + "browse.startsWith.jump": "Jump to a point in the index:", + "browse.startsWith.months.april": "April", + "browse.startsWith.months.august": "August", + "browse.startsWith.months.december": "December", + "browse.startsWith.months.february": "February", + "browse.startsWith.months.january": "January", + "browse.startsWith.months.july": "July", + "browse.startsWith.months.june": "June", + "browse.startsWith.months.march": "March", + "browse.startsWith.months.may": "May", + "browse.startsWith.months.none": "(Choose month)", + "browse.startsWith.months.november": "November", + "browse.startsWith.months.october": "October", + "browse.startsWith.months.september": "September", + "browse.startsWith.submit": "Go", + "browse.startsWith.type_date": "Or type in a date (year-month):", + "browse.startsWith.type_text": "Or enter first few letters:", + "browse.title": "Browsing {{ collection }} by {{ field }} {{ value }}", + + "chips.remove": "Remove chip", + + "collection.create.head": "Create a Collection", + "collection.create.sub-head": "Create a Collection for Community {{ parent }}", + "collection.delete.cancel": "Cancel", + "collection.delete.confirm": "Confirm", + "collection.delete.head": "Delete Collection", + "collection.delete.notification.fail": "Collection could not be deleted", + "collection.delete.notification.success": "Successfully deleted collection", + "collection.delete.text": "Are you sure you want to delete collection \"{{ dso }}\"", + + "collection.edit.delete": "Delete this collection", + "collection.edit.head": "Edit Collection", + + "collection.edit.item-mapper.cancel": "Cancel", + "collection.edit.item-mapper.collection": "Collection: \"{{name}}\"", + "collection.edit.item-mapper.confirm": "Map selected items", + "collection.edit.item-mapper.description": "This is the item mapper tool that allows collection administrators to map items from other collections into this collection. You can search for items from other collections and map them, or browse the list of currently mapped items.", + "collection.edit.item-mapper.head": "Item Mapper - Map Items from Other Collections", + "collection.edit.item-mapper.no-search": "Please enter a query to search", + "collection.edit.item-mapper.notifications.map.error.content": "Errors occurred for mapping of {{amount}} items.", + "collection.edit.item-mapper.notifications.map.error.head": "Mapping errors", + "collection.edit.item-mapper.notifications.map.success.content": "Successfully mapped {{amount}} items.", + "collection.edit.item-mapper.notifications.map.success.head": "Mapping completed", + "collection.edit.item-mapper.notifications.unmap.error.content": "Errors occurred for removing the mappings of {{amount}} items.", + "collection.edit.item-mapper.notifications.unmap.error.head": "Remove mapping errors", + "collection.edit.item-mapper.notifications.unmap.success.content": "Successfully removed the mappings of {{amount}} items.", + "collection.edit.item-mapper.notifications.unmap.success.head": "Remove mapping completed", + "collection.edit.item-mapper.remove": "Remove selected item mappings", + "collection.edit.item-mapper.tabs.browse": "Browse mapped items", + "collection.edit.item-mapper.tabs.map": "Map new items", + + "collection.form.abstract": "Short Description", + "collection.form.description": "Introductory text (HTML)", + "collection.form.errors.title.required": "Please enter a collection name", + "collection.form.license": "License", + "collection.form.provenance": "Provenance", + "collection.form.rights": "Copyright text (HTML)", + "collection.form.tableofcontents": "News (HTML)", + "collection.form.title": "Name", + + "collection.page.browse.recent.head": "Recent Submissions", + "collection.page.browse.recent.empty": "No items to show", + "collection.page.handle": "Permanent URI for this collection", + "collection.page.license": "License", + "collection.page.news": "News", + + "collection.select.confirm": "Confirm selected", + "collection.select.empty": "No collections to show", + "collection.select.table.title": "Title", + + "community.create.head": "Create a Community", + "community.create.sub-head": "Create a Sub-Community for Community {{ parent }}", + "community.delete.cancel": "Cancel", + "community.delete.confirm": "Confirm", + "community.delete.head": "Delete Community", + "community.delete.notification.fail": "Community could not be deleted", + "community.delete.notification.success": "Successfully deleted community", + "community.delete.text": "Are you sure you want to delete community \"{{ dso }}\"", + "community.edit.delete": "Delete this community", + "community.edit.head": "Edit Community", + "community.form.abstract": "Short Description", + "community.form.description": "Introductory text (HTML)", + "community.form.errors.title.required": "Please enter a community name", + "community.form.rights": "Copyright text (HTML)", + "community.form.tableofcontents": "News (HTML)", + "community.form.title": "Name", + "community.page.handle": "Permanent URI for this community", + "community.page.license": "License", + "community.page.news": "News", + "community.all-lists.head": "Subcommunities and Collections", + "community.sub-collection-list.head": "Collections of this Community", + "community.sub-community-list.head": "Communities of this Community", + + "dso-selector.create.collection.head": "New collection", + "dso-selector.create.community.head": "New community", + "dso-selector.create.community.sub-level": "Create a new community in", + "dso-selector.create.community.top-level": "Create a new top-level community", + "dso-selector.create.item.head": "New item", + "dso-selector.edit.collection.head": "Edit collection", + "dso-selector.edit.community.head": "Edit community", + "dso-selector.edit.item.head": "Edit item", + "dso-selector.no-results": "No {{ type }} found", + "dso-selector.placeholder": "Search for a {{ type }}", + + "error.browse-by": "Error fetching items", + "error.collection": "Error fetching collection", + "error.collections": "Error fetching collections", + "error.community": "Error fetching community", + + "error.identifier": "No item found for the identifier", + "error.default": "Error", + "error.item": "Error fetching item", + "error.items": "Error fetching items", + "error.objects": "Error fetching objects", + "error.recent-submissions": "Error fetching recent submissions", + "error.search-results": "Error fetching search results", + "error.sub-collections": "Error fetching sub-collections", + "error.sub-communities": "Error fetching sub-communities", + "error.submission.sections.init-form-error": "An error occurred during section initialize, please check your input-form configuration. Details are below :

", + "error.top-level-communities": "Error fetching top-level communities", + "error.validation.license.notgranted": "You must grant this license to complete your submission. If you are unable to grant this license at this time you may save your work and return later or remove the submission.", + "error.validation.pattern": "This input is restricted by the current pattern: {{ pattern }}.", + + "footer.copyright": "copyright © 2002-{{ year }}", + "footer.link.dspace": "DSpace software", + "footer.link.duraspace": "DuraSpace", + + "form.cancel": "Cancel", + "form.clear": "Clear", + "form.clear-help": "Click here to remove the selected value", + "form.edit": "Edit", + "form.edit-help": "Click here to edit the selected value", + "form.first-name": "First name", + "form.group-collapse": "Collapse", + "form.group-collapse-help": "Click here to collapse", + "form.group-expand": "Expand", + "form.group-expand-help": "Click here to expand and add more elements", + "form.last-name": "Last name", + "form.loading": "Loading...", + "form.no-results": "No results found", + "form.no-value": "No value entered", + "form.other-information": {}, + "form.remove": "Remove", + "form.save": "Save", + "form.save-help": "Save changes", + "form.search": "Search", + "form.search-help": "Click here to looking for an existing correspondence", + "form.submit": "Submit", + + "home.description": "", + "home.title": "DSpace Angular :: Home", + "home.top-level-communities.head": "Communities in DSpace", + "home.top-level-communities.help": "Select a community to browse its collections.", + + "item.edit.delete.cancel": "Cancel", + "item.edit.delete.confirm": "Delete", + "item.edit.delete.description": "Are you sure this item should be completely deleted? Caution: At present, no tombstone would be left.", + "item.edit.delete.error": "An error occurred while deleting the item", + "item.edit.delete.header": "Delete item: {{ id }}", + "item.edit.delete.success": "The item has been deleted", + "item.edit.head": "Edit Item", + + "item.edit.item-mapper.buttons.add": "Map item to selected collections", + "item.edit.item-mapper.buttons.remove": "Remove item's mapping for selected collections", + "item.edit.item-mapper.cancel": "Cancel", + "item.edit.item-mapper.description": "This is the item mapper tool that allows administrators to map this item to other collections. You can search for collections and map them, or browse the list of collections the item is currently mapped to.", + "item.edit.item-mapper.head": "Item Mapper - Map Item to Collections", + "item.edit.item-mapper.item": "Item: \"{{name}}\"", + "item.edit.item-mapper.no-search": "Please enter a query to search", + "item.edit.item-mapper.notifications.add.error.content": "Errors occurred for mapping of item to {{amount}} collections.", + "item.edit.item-mapper.notifications.add.error.head": "Mapping errors", + "item.edit.item-mapper.notifications.add.success.content": "Successfully mapped item to {{amount}} collections.", + "item.edit.item-mapper.notifications.add.success.head": "Mapping completed", + "item.edit.item-mapper.notifications.remove.error.content": "Errors occurred for the removal of the mapping to {{amount}} collections.", + "item.edit.item-mapper.notifications.remove.error.head": "Removal of mapping errors", + "item.edit.item-mapper.notifications.remove.success.content": "Successfully removed mapping of item to {{amount}} collections.", + "item.edit.item-mapper.notifications.remove.success.head": "Removal of mapping completed", + "item.edit.item-mapper.tabs.browse": "Browse mapped collections", + "item.edit.item-mapper.tabs.map": "Map new collections", + + "item.edit.metadata.add-button": "Add", + "item.edit.metadata.discard-button": "Discard", + "item.edit.metadata.edit.buttons.edit": "Edit", + "item.edit.metadata.edit.buttons.remove": "Remove", + "item.edit.metadata.edit.buttons.undo": "Undo changes", + "item.edit.metadata.edit.buttons.unedit": "Stop editing", + "item.edit.metadata.headers.edit": "Edit", + "item.edit.metadata.headers.field": "Field", + "item.edit.metadata.headers.language": "Lang", + "item.edit.metadata.headers.value": "Value", + "item.edit.metadata.metadatafield.invalid": "Please choose a valid metadata field", + "item.edit.metadata.notifications.discarded.content": "Your changes were discarded. To reinstate your changes click the 'Undo' button", + "item.edit.metadata.notifications.discarded.title": "Changed discarded", + "item.edit.metadata.notifications.invalid.content": "Your changes were not saved. Please make sure all fields are valid before you save.", + "item.edit.metadata.notifications.invalid.title": "Metadata invalid", + "item.edit.metadata.notifications.outdated.content": "The item you're currently working on has been changed by another user. Your current changes are discarded to prevent conflicts", + "item.edit.metadata.notifications.outdated.title": "Changed outdated", + "item.edit.metadata.notifications.saved.content": "Your changes to this item's metadata were saved.", + "item.edit.metadata.notifications.saved.title": "Metadata saved", + "item.edit.metadata.reinstate-button": "Undo", + "item.edit.metadata.save-button": "Save", + + "item.edit.modify.overview.field": "Field", + "item.edit.modify.overview.language": "Language", + "item.edit.modify.overview.value": "Value", + + "item.edit.move.cancel": "Cancel", + "item.edit.move.description": "Select the collection you wish to move this item to. To narrow down the list of displayed collections, you can enter a search query in the box.", + "item.edit.move.error": "An error occured when attempting to move the item", + "item.edit.move.head": "Move item: {{id}}", + "item.edit.move.inheritpolicies.checkbox": "Inherit policies", + "item.edit.move.inheritpolicies.description": "Inherit the default policies of the destination collection", + "item.edit.move.move": "Move", + "item.edit.move.processing": "Moving...", + "item.edit.move.search.placeholder": "Enter a search query to look for collections", + "item.edit.move.success": "The item has been moved succesfully", + "item.edit.move.title": "Move item", + + "item.edit.private.cancel": "Cancel", + "item.edit.private.confirm": "Make it Private", + "item.edit.private.description": "Are you sure this item should be made private in the archive?", + "item.edit.private.error": "An error occurred while making the item private", + "item.edit.private.header": "Make item private: {{ id }}", + "item.edit.private.success": "The item is now private", + + "item.edit.public.cancel": "Cancel", + "item.edit.public.confirm": "Make it Public", + "item.edit.public.description": "Are you sure this item should be made public in the archive?", + "item.edit.public.error": "An error occurred while making the item public", + "item.edit.public.header": "Make item public: {{ id }}", + "item.edit.public.success": "The item is now public", + + "item.edit.reinstate.cancel": "Cancel", + "item.edit.reinstate.confirm": "Reinstate", + "item.edit.reinstate.description": "Are you sure this item should be reinstated to the archive?", + "item.edit.reinstate.error": "An error occurred while reinstating the item", + "item.edit.reinstate.header": "Reinstate item: {{ id }}", + "item.edit.reinstate.success": "The item was reinstated successfully", + + "item.edit.relationships.discard-button": "Discard", + "item.edit.relationships.edit.buttons.remove": "Remove", + "item.edit.relationships.edit.buttons.undo": "Undo changes", + "item.edit.relationships.notifications.discarded.content": "Your changes were discarded. To reinstate your changes click the 'Undo' button", + "item.edit.relationships.notifications.discarded.title": "Changes discarded", + "item.edit.relationships.notifications.failed.title": "Error deleting relationship", + "item.edit.relationships.notifications.outdated.content": "The item you're currently working on has been changed by another user. Your current changes are discarded to prevent conflicts", + "item.edit.relationships.notifications.outdated.title": "Changes outdated", + "item.edit.relationships.notifications.saved.content": "Your changes to this item's relationships were saved.", + "item.edit.relationships.notifications.saved.title": "Relationships saved", + "item.edit.relationships.reinstate-button": "Undo", + "item.edit.relationships.save-button": "Save", + + "item.edit.tabs.bitstreams.head": "Item Bitstreams", + "item.edit.tabs.bitstreams.title": "Item Edit - Bitstreams", + "item.edit.tabs.curate.head": "Curate", + "item.edit.tabs.curate.title": "Item Edit - Curate", + "item.edit.tabs.metadata.head": "Item Metadata", + "item.edit.tabs.metadata.title": "Item Edit - Metadata", + "item.edit.tabs.relationships.head": "Item Relationships", + "item.edit.tabs.relationships.title": "Item Edit - Relationships", + "item.edit.tabs.status.buttons.authorizations.button": "Authorizations...", + "item.edit.tabs.status.buttons.authorizations.label": "Edit item's authorization policies", + "item.edit.tabs.status.buttons.delete.button": "Permanently delete", + "item.edit.tabs.status.buttons.delete.label": "Completely expunge item", + "item.edit.tabs.status.buttons.mappedCollections.button": "Mapped collections", + "item.edit.tabs.status.buttons.mappedCollections.label": "Manage mapped collections", + "item.edit.tabs.status.buttons.move.button": "Move...", + "item.edit.tabs.status.buttons.move.label": "Move item to another collection", + "item.edit.tabs.status.buttons.private.button": "Make it private...", + "item.edit.tabs.status.buttons.private.label": "Make item private", + "item.edit.tabs.status.buttons.public.button": "Make it public...", + "item.edit.tabs.status.buttons.public.label": "Make item public", + "item.edit.tabs.status.buttons.reinstate.button": "Reinstate...", + "item.edit.tabs.status.buttons.reinstate.label": "Reinstate item into the repository", + "item.edit.tabs.status.buttons.withdraw.button": "Withdraw...", + "item.edit.tabs.status.buttons.withdraw.label": "Withdraw item from the repository", + "item.edit.tabs.status.description": "Welcome to the item management page. From here you can withdraw, reinstate, move or delete the item. You may also update or add new metadata / bitstreams on the other tabs.", + "item.edit.tabs.status.head": "Item Status", + "item.edit.tabs.status.labels.handle": "Handle", + "item.edit.tabs.status.labels.id": "Item Internal ID", + "item.edit.tabs.status.labels.itemPage": "Item Page", + "item.edit.tabs.status.labels.lastModified": "Last Modified", + "item.edit.tabs.status.title": "Item Edit - Status", + "item.edit.tabs.view.head": "View Item", + "item.edit.tabs.view.title": "Item Edit - View", + + "item.edit.withdraw.cancel": "Cancel", + "item.edit.withdraw.confirm": "Withdraw", + "item.edit.withdraw.description": "Are you sure this item should be withdrawn from the archive?", + "item.edit.withdraw.error": "An error occurred while withdrawing the item", + "item.edit.withdraw.header": "Withdraw item: {{ id }}", + "item.edit.withdraw.success": "The item was withdrawn successfully", + + "item.page.abstract": "Abstract", + "item.page.author": "Authors", + "item.page.citation": "Citation", + "item.page.collections": "Collections", + "item.page.date": "Date", + "item.page.files": "Files", + "item.page.filesection.description": "Description:", + "item.page.filesection.download": "Download", + "item.page.filesection.format": "Format:", + "item.page.filesection.name": "Name:", + "item.page.filesection.size": "Size:", + "item.page.journal.search.title": "Articles in this journal", + "item.page.link.full": "Full item page", + "item.page.link.simple": "Simple item page", + "item.page.person.search.title": "Articles by this author", + + "item.page.related-items.view-more": "View more", + + "item.page.related-items.view-less": "View less", + "item.page.subject": "Keywords", + "item.page.uri": "URI", + + "item.select.confirm": "Confirm selected", + "item.select.empty": "No items to show", + "item.select.table.author": "Author", + "item.select.table.collection": "Collection", + "item.select.table.title": "Title", + + "journal.listelement.badge": "Journal", + "journal.page.description": "Description", + "journal.page.editor": "Editor-in-Chief", + "journal.page.issn": "ISSN", + "journal.page.publisher": "Publisher", + "journal.page.titleprefix": "Journal: ", + "journal.search.results.head": "Journal Search Results", + "journal.search.title": "DSpace Angular :: Journal Search", + + "journalissue.listelement.badge": "Journal Issue", + "journalissue.page.description": "Description", + "journalissue.page.issuedate": "Issue Date", + "journalissue.page.journal-issn": "Journal ISSN", + "journalissue.page.journal-title": "Journal Title", + "journalissue.page.keyword": "Keywords", + "journalissue.page.number": "Number", + "journalissue.page.titleprefix": "Journal Issue: ", + + "journalvolume.listelement.badge": "Journal Volume", + "journalvolume.page.description": "Description", + "journalvolume.page.issuedate": "Issue Date", + "journalvolume.page.titleprefix": "Journal Volume: ", + "journalvolume.page.volume": "Volume", + + "loading.browse-by": "Loading items...", + "loading.browse-by-page": "Loading page...", + "loading.collection": "Loading collection...", + "loading.collections": "Loading collections...", + "loading.community": "Loading community...", + "loading.default": "Loading...", + "loading.item": "Loading item...", + "loading.items": "Loading items...", + "loading.mydspace-results": "Loading items...", + "loading.objects": "Loading...", + "loading.recent-submissions": "Loading recent submissions...", + "loading.search-results": "Loading search results...", + "loading.sub-collections": "Loading sub-collections...", + "loading.sub-communities": "Loading sub-communities...", + "loading.top-level-communities": "Loading top-level communities...", + + "login.form.email": "Email address", + "login.form.forgot-password": "Have you forgotten your password?", + "login.form.header": "Please log in to DSpace", + "login.form.new-user": "New user? Click here to register.", + "login.form.password": "Password", + "login.form.submit": "Log in", + "login.title": "Login", + + "logout.form.header": "Log out from DSpace", + "logout.form.submit": "Log out", + "logout.title": "Logout", + + "menu.header.admin": "Admin", + "menu.header.image.logo": "Repository logo", + + "menu.section.access_control": "Access Control", + "menu.section.access_control_authorizations": "Authorizations", + "menu.section.access_control_groups": "Groups", + "menu.section.access_control_people": "People", + + "menu.section.browse_community": "This Community", + "menu.section.browse_community_by_author": "By Author", + "menu.section.browse_community_by_issue_date": "By Issue Date", + "menu.section.browse_community_by_title": "By Title", + "menu.section.browse_global": "All of DSpace", + "menu.section.browse_global_by_author": "By Author", + "menu.section.browse_global_by_dateissued": "By Issue Date", + "menu.section.browse_global_by_subject": "By Subject", + "menu.section.browse_global_by_title": "By Title", + "menu.section.browse_global_communities_and_collections": "Communities & Collections", + + "menu.section.control_panel": "Control Panel", + "menu.section.curation_task": "Curation Task", + + "menu.section.edit": "Edit", + "menu.section.edit_collection": "Collection", + "menu.section.edit_community": "Community", + "menu.section.edit_item": "Item", + + "menu.section.export": "Export", + "menu.section.export_collection": "Collection", + "menu.section.export_community": "Community", + "menu.section.export_item": "Item", + "menu.section.export_metadata": "Metadata", + + "menu.section.find": "Find", + "menu.section.find_items": "Items", + "menu.section.find_private_items": "Private Items", + "menu.section.find_withdrawn_items": "Withdrawn Items", + + "menu.section.icon.access_control": "Access Control menu section", + "menu.section.icon.control_panel": "Control Panel menu section", + "menu.section.icon.curation_task": "Curation Task menu section", + "menu.section.icon.edit": "Edit menu section", + "menu.section.icon.export": "Export menu section", + "menu.section.icon.find": "Find menu section", + "menu.section.icon.import": "Import menu section", + "menu.section.icon.new": "New menu section", + "menu.section.icon.pin": "Pin sidebar", + "menu.section.icon.registries": "Registries menu section", + "menu.section.icon.statistics_task": "Statistics Task menu section", + "menu.section.icon.unpin": "Unpin sidebar", + + "menu.section.import": "Import", + "menu.section.import_batch": "Batch Import (ZIP)", + "menu.section.import_metadata": "Metadata", + + "menu.section.new": "New", + "menu.section.new_collection": "Collection", + "menu.section.new_community": "Community", + "menu.section.new_item": "Item", + "menu.section.new_item_version": "Item Version", + + "menu.section.pin": "Pin sidebar", + "menu.section.unpin": "Unpin sidebar", + + "menu.section.registries": "Registries", + "menu.section.registries_format": "Format", + "menu.section.registries_metadata": "Metadata", + + "menu.section.statistics": "Statistics", + "menu.section.statistics_task": "Statistics Task", + + "menu.section.toggle.access_control": "Toggle Access Control section", + "menu.section.toggle.control_panel": "Toggle Control Panel section", + "menu.section.toggle.curation_task": "Toggle Curation Task section", + "menu.section.toggle.edit": "Toggle Edit section", + "menu.section.toggle.export": "Toggle Export section", + "menu.section.toggle.find": "Toggle Find section", + "menu.section.toggle.import": "Toggle Import section", + "menu.section.toggle.new": "Toggle New section", + "menu.section.toggle.registries": "Toggle Registries section", + "menu.section.toggle.statistics_task": "Toggle Statistics Task section", + + "mydspace.description": "", + "mydspace.general.text-here": "HERE", + "mydspace.messages.controller-help": "Select this option to send a message to item's submitter.", + "mydspace.messages.description-placeholder": "Insert your message here...", + "mydspace.messages.hide-msg": "Hide message", + "mydspace.messages.mark-as-read": "Mark as read", + "mydspace.messages.mark-as-unread": "Mark as unread", + "mydspace.messages.no-content": "No content.", + "mydspace.messages.no-messages": "No messages yet.", + "mydspace.messages.send-btn": "Send", + "mydspace.messages.show-msg": "Show message", + "mydspace.messages.subject-placeholder": "Subject...", + "mydspace.messages.submitter-help": "Select this option to send a message to controller.", + "mydspace.messages.title": "Messages", + "mydspace.messages.to": "To", + "mydspace.new-submission": "New submission", + "mydspace.results.head": "Your submissions", + "mydspace.results.no-abstract": "No Abstract", + "mydspace.results.no-authors": "No Authors", + "mydspace.results.no-collections": "No Collections", + "mydspace.results.no-date": "No Date", + "mydspace.results.no-files": "No Files", + "mydspace.results.no-results": "There were no items to show", + "mydspace.results.no-title": "No title", + "mydspace.results.no-uri": "No Uri", + "mydspace.show.workflow": "All tasks", + "mydspace.show.workspace": "Your Submissions", + "mydspace.status.archived": "Archived", + "mydspace.status.validation": "Validation", + "mydspace.status.waiting-for-controller": "Waiting for controller", + "mydspace.status.workflow": "Workflow", + "mydspace.status.workspace": "Workspace", + "mydspace.title": "MyDSpace", + "mydspace.upload.upload-failed": "Error creating new workspace. Please verify the content uploaded before retry.", + "mydspace.upload.upload-multiple-successful": "{{qty}} new workspace items created.", + "mydspace.upload.upload-successful": "New workspace item created. Click {{here}} for edit it.", + "mydspace.view-btn": "View", + + "nav.browse.header": "All of DSpace", + "nav.community-browse.header": "By Community", + "nav.language": "Language switch", + "nav.login": "Log In", + "nav.logout": "Log Out", + "nav.mydspace": "MyDSpace", + "nav.search": "Search", + "nav.statistics.header": "Statistics", + + "orgunit.listelement.badge": "Organizational Unit", + "orgunit.page.city": "City", + "orgunit.page.country": "Country", + "orgunit.page.dateestablished": "Date established", + "orgunit.page.description": "Description", + "orgunit.page.id": "ID", + "orgunit.page.titleprefix": "Organizational Unit: ", + + "pagination.results-per-page": "Results Per Page", + "pagination.showing.detail": "{{ range }} of {{ total }}", + "pagination.showing.label": "Now showing ", + "pagination.sort-direction": "Sort Options", + + "person.listelement.badge": "Person", + "person.page.birthdate": "Birth Date", + "person.page.email": "Email Address", + "person.page.firstname": "First Name", + "person.page.jobtitle": "Job Title", + "person.page.lastname": "Last Name", + "person.page.link.full": "Show all metadata", + "person.page.orcid": "ORCID", + "person.page.staffid": "Staff ID", + "person.page.titleprefix": "Person: ", + "person.search.results.head": "Person Search Results", + "person.search.title": "DSpace Angular :: Person Search", + + "project.listelement.badge": "Research Project", + "project.page.contributor": "Contributors", + "project.page.description": "Description", + "project.page.expectedcompletion": "Expected Completion", + "project.page.funder": "Funders", + "project.page.id": "ID", + "project.page.keyword": "Keywords", + "project.page.status": "Status", + "project.page.titleprefix": "Research Project: ", + + "publication.listelement.badge": "Publication", + "publication.page.description": "Description", + "publication.page.journal-issn": "Journal ISSN", + "publication.page.journal-title": "Journal Title", + "publication.page.publisher": "Publisher", + "publication.page.titleprefix": "Publication: ", + "publication.page.volume-title": "Volume Title", + "publication.search.results.head": "Publication Search Results", + "publication.search.title": "DSpace Angular :: Publication Search", + + "relationships.isAuthorOf": "Authors", + "relationships.isIssueOf": "Journal Issues", + "relationships.isJournalIssueOf": "Journal Issue", + "relationships.isJournalOf": "Journals", + "relationships.isOrgUnitOf": "Organizational Units", + "relationships.isPersonOf": "Authors", + "relationships.isProjectOf": "Research Projects", + "relationships.isPublicationOf": "Publications", + "relationships.isPublicationOfJournalIssue": "Articles", + "relationships.isSingleJournalOf": "Journal", + "relationships.isSingleVolumeOf": "Journal Volume", + "relationships.isVolumeOf": "Journal Volumes", + + "search.description": "", + "search.switch-configuration.title": "Show", + "search.title": "DSpace Angular :: Search", + + "search.filters.applied.f.author": "Author", + "search.filters.applied.f.dateIssued.max": "End date", + "search.filters.applied.f.dateIssued.min": "Start date", + "search.filters.applied.f.dateSubmitted": "Date submitted", + "search.filters.applied.f.entityType": "Item Type", + "search.filters.applied.f.has_content_in_original_bundle": "Has files", + "search.filters.applied.f.itemtype": "Type", + "search.filters.applied.f.namedresourcetype": "Status", + "search.filters.applied.f.subject": "Subject", + "search.filters.applied.f.submitter": "Submitter", + + "search.filters.filter.author.head": "Author", + "search.filters.filter.author.placeholder": "Author name", + "search.filters.filter.birthDate.head": "Birth Date", + "search.filters.filter.birthDate.placeholder": "Birth Date", + "search.filters.filter.creativeDatePublished.head": "Date Published", + "search.filters.filter.creativeDatePublished.placeholder": "Date Published", + "search.filters.filter.creativeWorkEditor.head": "Editor", + "search.filters.filter.creativeWorkEditor.placeholder": "Editor", + "search.filters.filter.creativeWorkKeywords.head": "Subject", + "search.filters.filter.creativeWorkKeywords.placeholder": "Subject", + "search.filters.filter.creativeWorkPublisher.head": "Publisher", + "search.filters.filter.creativeWorkPublisher.placeholder": "Publisher", + "search.filters.filter.dateIssued.head": "Date", + "search.filters.filter.dateIssued.max.placeholder": "Minimum Date", + "search.filters.filter.dateIssued.min.placeholder": "Maximum Date", + "search.filters.filter.dateSubmitted.head": "Date submitted", + "search.filters.filter.dateSubmitted.placeholder": "Date submitted", + "search.filters.filter.entityType.head": "Item Type", + "search.filters.filter.entityType.placeholder": "Item Type", + "search.filters.filter.has_content_in_original_bundle.head": "Has files", + "search.filters.filter.itemtype.head": "Type", + "search.filters.filter.itemtype.placeholder": "Type", + "search.filters.filter.jobTitle.head": "Job Title", + "search.filters.filter.jobTitle.placeholder": "Job Title", + "search.filters.filter.knowsLanguage.head": "Known language", + "search.filters.filter.knowsLanguage.placeholder": "Known language", + "search.filters.filter.namedresourcetype.head": "Status", + "search.filters.filter.namedresourcetype.placeholder": "Status", + "search.filters.filter.objectpeople.head": "People", + "search.filters.filter.objectpeople.placeholder": "People", + "search.filters.filter.organizationAddressCountry.head": "Country", + "search.filters.filter.organizationAddressCountry.placeholder": "Country", + "search.filters.filter.organizationAddressLocality.head": "City", + "search.filters.filter.organizationAddressLocality.placeholder": "City", + "search.filters.filter.organizationFoundingDate.head": "Date Founded", + "search.filters.filter.organizationFoundingDate.placeholder": "Date Founded", + "search.filters.filter.scope.head": "Scope", + "search.filters.filter.scope.placeholder": "Scope filter", + "search.filters.filter.show-less": "Collapse", + "search.filters.filter.show-more": "Show more", + "search.filters.filter.subject.head": "Subject", + "search.filters.filter.subject.placeholder": "Subject", + "search.filters.filter.submitter.head": "Submitter", + "search.filters.filter.submitter.placeholder": "Submitter", + + "search.filters.head": "Filters", + "search.filters.reset": "Reset filters", + + "search.form.search": "Search", + "search.form.search_dspace": "Search DSpace", + "search.form.search_mydspace": "Search MyDSpace", + + "search.results.head": "Search Results", + "search.results.no-results": "Your search returned no results. Having trouble finding what you're looking for? Try putting", + "search.results.no-results-link": "quotes around it", + + "search.sidebar.close": "Back to results", + "search.sidebar.filters.title": "Filters", + "search.sidebar.open": "Search Tools", + "search.sidebar.results": "results", + "search.sidebar.settings.rpp": "Results per page", + "search.sidebar.settings.sort-by": "Sort By", + "search.sidebar.settings.title": "Settings", + + "search.view-switch.show-detail": "Show detail", + "search.view-switch.show-grid": "Show as grid", + "search.view-switch.show-list": "Show as list", + + "sorting.dc.title.ASC": "Title Ascending", + "sorting.dc.title.DESC": "Title Descending", + "sorting.score.DESC": "Relevance", + + "submission.edit.title": "Edit Submission", + "submission.general.cannot_submit": "You have not the privilege to make a new submission.", + "submission.general.deposit": "Deposit", + "submission.general.discard.confirm.cancel": "Cancel", + "submission.general.discard.confirm.info": "This operation can't be undone. Are you sure?", + "submission.general.discard.confirm.submit": "Yes, I'm sure", + "submission.general.discard.confirm.title": "Discard submission", + "submission.general.discard.submit": "Discard", + "submission.general.save": "Save", + "submission.general.save-later": "Save for later", + + "submission.sections.general.add-more": "Add more", + "submission.sections.general.collection": "Collection", + "submission.sections.general.deposit_error_notice": "There was an issue when submitting the item, please try again later.", + "submission.sections.general.deposit_success_notice": "Submission deposited successfully.", + "submission.sections.general.discard_error_notice": "There was an issue when discarding the item, please try again later.", + "submission.sections.general.discard_success_notice": "Submission discarded successfully.", + "submission.sections.general.metadata-extracted": "New metadata have been extracted and added to the {{sectionId}} section.", + "submission.sections.general.metadata-extracted-new-section": "New {{sectionId}} section has been added to submission.", + "submission.sections.general.no-collection": "No collection found", + "submission.sections.general.no-sections": "No options available", + "submission.sections.general.save_error_notice": "There was an issue when saving the item, please try again later.", + "submission.sections.general.save_success_notice": "Submission saved successfully.", + "submission.sections.general.search-collection": "Search for a collection", + "submission.sections.general.sections_not_valid": "There are incomplete sections.", + + "submission.sections.submit.progressbar.cclicense": "Creative commons license", + "submission.sections.submit.progressbar.describe.recycle": "Recycle", + "submission.sections.submit.progressbar.describe.stepcustom": "Describe", + "submission.sections.submit.progressbar.describe.stepone": "Describe", + "submission.sections.submit.progressbar.describe.steptwo": "Describe", + "submission.sections.submit.progressbar.detect-duplicate": "Potential duplicates", + "submission.sections.submit.progressbar.license": "Deposit license", + "submission.sections.submit.progressbar.upload": "Upload files", + + "submission.sections.upload.delete.confirm.cancel": "Cancel", + "submission.sections.upload.delete.confirm.info": "This operation can't be undone. Are you sure?", + "submission.sections.upload.delete.confirm.submit": "Yes, I'm sure", + "submission.sections.upload.delete.confirm.title": "Delete bitstream", + "submission.sections.upload.delete.submit": "Delete", + "submission.sections.upload.drop-message": "Drop files to attach them to the item", + "submission.sections.upload.form.access-condition-label": "Access condition type", + "submission.sections.upload.form.date-required": "Date is required.", + "submission.sections.upload.form.from-label": "Access grant from", + "submission.sections.upload.form.from-placeholder": "From", + "submission.sections.upload.form.group-label": "Group", + "submission.sections.upload.form.group-required": "Group is required.", + "submission.sections.upload.form.until-label": "Access grant until", + "submission.sections.upload.form.until-placeholder": "Until", + "submission.sections.upload.header.policy.default.nolist": "Uploaded files in the {{collectionName}} collection will be accessible according to the following group(s):", + "submission.sections.upload.header.policy.default.withlist": "Please note that uploaded files in the {{collectionName}} collection will be accessible, in addition to what is explicitly decided for the single file, with the following group(s):", + "submission.sections.upload.info": "Here you will find all the files currently in the item. You can update the fle metadata and access conditions or upload additional files just dragging & dropping them everywhere in the page", + "submission.sections.upload.no-entry": "No", + "submission.sections.upload.no-file-uploaded": "No file uploaded yet.", + "submission.sections.upload.save-metadata": "Save metadata", + "submission.sections.upload.undo": "Cancel", + "submission.sections.upload.upload-failed": "Upload failed", + "submission.sections.upload.upload-successful": "Upload successful", + + "submission.submit.title": "Submission", + + "submission.workflow.generic.delete": "Delete", + "submission.workflow.generic.delete-help": "If you would to discard this item, select \"Delete\". You will then be asked to confirm it.", + "submission.workflow.generic.edit": "Edit", + "submission.workflow.generic.edit-help": "Select this option to change the item's metadata.", + "submission.workflow.generic.view": "View", + "submission.workflow.generic.view-help": "Select this option to view the item's metadata.", + + "submission.workflow.tasks.claimed.approve": "Approve", + "submission.workflow.tasks.claimed.approve_help": "If you have reviewed the item and it is suitable for inclusion in the collection, select \"Approve\".", + "submission.workflow.tasks.claimed.edit": "Edit", + "submission.workflow.tasks.claimed.edit_help": "Select this option to change the item's metadata.", + "submission.workflow.tasks.claimed.reject.reason.info": "Please enter your reason for rejecting the submission into the box below, indicating whether the submitter may fix a problem and resubmit.", + "submission.workflow.tasks.claimed.reject.reason.placeholder": "Describe the reason of reject", + "submission.workflow.tasks.claimed.reject.reason.submit": "Reject item", + "submission.workflow.tasks.claimed.reject.reason.title": "Reason", + "submission.workflow.tasks.claimed.reject.submit": "Reject", + "submission.workflow.tasks.claimed.reject_help": "If you have reviewed the item and found it is not suitable for inclusion in the collection, select \"Reject\". You will then be asked to enter a message indicating why the item is unsuitable, and whether the submitter should change something and resubmit.", + "submission.workflow.tasks.claimed.return": "Return to pool", + "submission.workflow.tasks.claimed.return_help": "Return the task to the pool so that another user may perform the task.", + + "submission.workflow.tasks.generic.error": "Error occurred during operation...", + "submission.workflow.tasks.generic.processing": "Processing...", + "submission.workflow.tasks.generic.submitter": "Submitter", + "submission.workflow.tasks.generic.success": "Operation successful", + + "submission.workflow.tasks.pool.claim": "Claim", + "submission.workflow.tasks.pool.claim_help": "Assign this task to yourself.", + "submission.workflow.tasks.pool.hide-detail": "Hide detail", + "submission.workflow.tasks.pool.show-detail": "Show detail", + + "title": "DSpace", + + "uploader.browse": "browse", + "uploader.drag-message": "Drag & Drop your files here", + "uploader.or": ", or", + "uploader.processing": "Processing", + "uploader.queue-length": "Queue length", + } + diff --git a/resources/i18n/nl.json5 b/resources/i18n/nl.json5 index a195e13e01..b647c0d50d 100644 --- a/resources/i18n/nl.json5 +++ b/resources/i18n/nl.json5 @@ -1,175 +1,3090 @@ { + + // "404.help": "We can't find the page you're looking for. The page may have been moved or deleted. You can use the button below to get back to the home page. ", "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. ", + + // "404.link.home-page": "Take me to the home page", "404.link.home-page": "Terug naar de homepagina", + + // "404.page-not-found": "page not found", "404.page-not-found": "Pagina niet gevonden", - + + + + // "admin.registries.bitstream-formats.create.failure.content": "An error occurred while creating the new bitstream format.", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.create.failure.content": "An error occurred while creating the new bitstream format.", + + // "admin.registries.bitstream-formats.create.failure.head": "Failure", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.create.failure.head": "Failure", + + // "admin.registries.bitstream-formats.create.head": "Create Bitstream format", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.create.head": "Create Bitstream format", + + // "admin.registries.bitstream-formats.create.new": "Add a new bitstream format", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.create.new": "Add a new bitstream format", + + // "admin.registries.bitstream-formats.create.success.content": "The new bitstream format was successfully created.", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.create.success.content": "The new bitstream format was successfully created.", + + // "admin.registries.bitstream-formats.create.success.head": "Success", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.create.success.head": "Success", + + // "admin.registries.bitstream-formats.delete.failure.amount": "Failed to remove {{ amount }} format(s)", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.delete.failure.amount": "Failed to remove {{ amount }} format(s)", + + // "admin.registries.bitstream-formats.delete.failure.head": "Failure", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.delete.failure.head": "Failure", + + // "admin.registries.bitstream-formats.delete.success.amount": "Successfully removed {{ amount }} format(s)", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.delete.success.amount": "Successfully removed {{ amount }} format(s)", + + // "admin.registries.bitstream-formats.delete.success.head": "Success", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.delete.success.head": "Success", + + // "admin.registries.bitstream-formats.description": "This list of bitstream formats provides information about known formats and their support level.", "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.", - "admin.registries.bitstream-formats.formats.table.internal": "intern", - "admin.registries.bitstream-formats.formats.table.mimetype": "MIME Type", - "admin.registries.bitstream-formats.formats.table.name": "Naam", - "admin.registries.bitstream-formats.formats.table.supportLevel.0": "Onbekend", - "admin.registries.bitstream-formats.formats.table.supportLevel.1": "Gekend", - "admin.registries.bitstream-formats.formats.table.supportLevel.2": "Ondersteund", - "admin.registries.bitstream-formats.formats.table.supportLevel.head": "Ondersteuning", + + // "admin.registries.bitstream-formats.edit.description.hint": "", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.description.hint": "", + + // "admin.registries.bitstream-formats.edit.description.label": "Description", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.description.label": "Description", + + // "admin.registries.bitstream-formats.edit.extensions.hint": "Extensions are file extensions that are used to automatically identify the format of uploaded files. You can enter several extensions for each format.", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.extensions.hint": "Extensions are file extensions that are used to automatically identify the format of uploaded files. You can enter several extensions for each format.", + + // "admin.registries.bitstream-formats.edit.extensions.label": "File extensions", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.extensions.label": "File extensions", + + // "admin.registries.bitstream-formats.edit.extensions.placeholder": "Enter a file extenstion without the dot", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.extensions.placeholder": "Enter a file extenstion without the dot", + + // "admin.registries.bitstream-formats.edit.failure.content": "An error occurred while editing the bitstream format.", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.failure.content": "An error occurred while editing the bitstream format.", + + // "admin.registries.bitstream-formats.edit.failure.head": "Failure", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.failure.head": "Failure", + + // "admin.registries.bitstream-formats.edit.head": "Bitstream format: {{ format }}", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.head": "Bitstream format: {{ format }}", + + // "admin.registries.bitstream-formats.edit.internal.hint": "Formats marked as internal are are hidden from the user, and used for administrative purposes.", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.internal.hint": "Formats marked as internal are are hidden from the user, and used for administrative purposes.", + + // "admin.registries.bitstream-formats.edit.internal.label": "Internal", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.internal.label": "Internal", + + // "admin.registries.bitstream-formats.edit.mimetype.hint": "The MIME type associated with this format, does not have to be unique.", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.mimetype.hint": "The MIME type associated with this format, does not have to be unique.", + + // "admin.registries.bitstream-formats.edit.mimetype.label": "MIME Type", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.mimetype.label": "MIME Type", + + // "admin.registries.bitstream-formats.edit.shortDescription.hint": "A unique name for this format, (e.g. Microsoft Word XP or Microsoft Word 2000)", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.shortDescription.hint": "A unique name for this format, (e.g. Microsoft Word XP or Microsoft Word 2000)", + + // "admin.registries.bitstream-formats.edit.shortDescription.label": "Name", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.shortDescription.label": "Name", + + // "admin.registries.bitstream-formats.edit.success.content": "The bitstream format was successfully edited.", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.success.content": "The bitstream format was successfully edited.", + + // "admin.registries.bitstream-formats.edit.success.head": "Success", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.success.head": "Success", + + // "admin.registries.bitstream-formats.edit.supportLevel.hint": "The level of support your institution pledges for this format.", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.supportLevel.hint": "The level of support your institution pledges for this format.", + + // "admin.registries.bitstream-formats.edit.supportLevel.label": "Support level", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.edit.supportLevel.label": "Support level", + + // "admin.registries.bitstream-formats.head": "Bitstream Format Registry", "admin.registries.bitstream-formats.head": "Bitstream Formaat Register", + + // "admin.registries.bitstream-formats.no-items": "No bitstream formats to show.", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.no-items": "No bitstream formats to show.", + + // "admin.registries.bitstream-formats.table.delete": "Delete selected", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.table.delete": "Delete selected", + + // "admin.registries.bitstream-formats.table.deselect-all": "Deselect all", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.table.deselect-all": "Deselect all", + + // "admin.registries.bitstream-formats.table.internal": "internal", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.table.internal": "internal", + + // "admin.registries.bitstream-formats.table.mimetype": "MIME Type", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.table.mimetype": "MIME Type", + + // "admin.registries.bitstream-formats.table.name": "Name", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.table.name": "Name", + + // "admin.registries.bitstream-formats.table.return": "Return", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.table.return": "Return", + + // "admin.registries.bitstream-formats.table.supportLevel.KNOWN": "Known", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.table.supportLevel.KNOWN": "Known", + + // "admin.registries.bitstream-formats.table.supportLevel.SUPPORTED": "Supported", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.table.supportLevel.SUPPORTED": "Supported", + + // "admin.registries.bitstream-formats.table.supportLevel.UNKNOWN": "Unknown", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.table.supportLevel.UNKNOWN": "Unknown", + + // "admin.registries.bitstream-formats.table.supportLevel.head": "Support Level", + // TODO New key - Add a translation + "admin.registries.bitstream-formats.table.supportLevel.head": "Support Level", + + // "admin.registries.bitstream-formats.title": "DSpace Angular :: Bitstream Format Registry", "admin.registries.bitstream-formats.title": "DSpace Angular :: Bitstream Formaat Register", - + + + + // "admin.registries.metadata.description": "The metadata registry maintains a list of all metadata fields available in the repository. These fields may be divided amongst multiple schemas. However, DSpace requires the qualified Dublin Core schema.", "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.form.create": "Create metadata schema", + // TODO New key - Add a translation + "admin.registries.metadata.form.create": "Create metadata schema", + + // "admin.registries.metadata.form.edit": "Edit metadata schema", + // TODO New key - Add a translation + "admin.registries.metadata.form.edit": "Edit metadata schema", + + // "admin.registries.metadata.form.name": "Name", + // TODO New key - Add a translation + "admin.registries.metadata.form.name": "Name", + + // "admin.registries.metadata.form.namespace": "Namespace", + // TODO New key - Add a translation + "admin.registries.metadata.form.namespace": "Namespace", + + // "admin.registries.metadata.head": "Metadata Registry", "admin.registries.metadata.head": "Metadata Register", + + // "admin.registries.metadata.schemas.no-items": "No metadata schemas to show.", "admin.registries.metadata.schemas.no-items": "Er kunnen geen metadataschema's getoond worden.", + + // "admin.registries.metadata.schemas.table.delete": "Delete selected", + // TODO New key - Add a translation + "admin.registries.metadata.schemas.table.delete": "Delete selected", + + // "admin.registries.metadata.schemas.table.id": "ID", "admin.registries.metadata.schemas.table.id": "ID", + + // "admin.registries.metadata.schemas.table.name": "Name", "admin.registries.metadata.schemas.table.name": "Naam", + + // "admin.registries.metadata.schemas.table.namespace": "Namespace", "admin.registries.metadata.schemas.table.namespace": "Naamruimte", + + // "admin.registries.metadata.title": "DSpace Angular :: Metadata Registry", "admin.registries.metadata.title": "DSpace Angular :: Metadata Register", - + + + + // "admin.registries.schema.description": "This is the metadata schema for \"{{namespace}}\".", "admin.registries.schema.description": "Dit is het metadataschema voor \"{{namespace}}\".", + + // "admin.registries.schema.fields.head": "Schema metadata fields", "admin.registries.schema.fields.head": "Schema metadatavelden", + + // "admin.registries.schema.fields.no-items": "No metadata fields to show.", "admin.registries.schema.fields.no-items": "Er kunnen geen metadatavelden getoond worden.", + + // "admin.registries.schema.fields.table.delete": "Delete selected", + // TODO New key - Add a translation + "admin.registries.schema.fields.table.delete": "Delete selected", + + // "admin.registries.schema.fields.table.field": "Field", "admin.registries.schema.fields.table.field": "Veld", + + // "admin.registries.schema.fields.table.scopenote": "Scope Note", "admin.registries.schema.fields.table.scopenote": "Opmerking over bereik", + + // "admin.registries.schema.form.create": "Create metadata field", + // TODO New key - Add a translation + "admin.registries.schema.form.create": "Create metadata field", + + // "admin.registries.schema.form.edit": "Edit metadata field", + // TODO New key - Add a translation + "admin.registries.schema.form.edit": "Edit metadata field", + + // "admin.registries.schema.form.element": "Element", + // TODO New key - Add a translation + "admin.registries.schema.form.element": "Element", + + // "admin.registries.schema.form.qualifier": "Qualifier", + // TODO New key - Add a translation + "admin.registries.schema.form.qualifier": "Qualifier", + + // "admin.registries.schema.form.scopenote": "Scope Note", + // TODO New key - Add a translation + "admin.registries.schema.form.scopenote": "Scope Note", + + // "admin.registries.schema.head": "Metadata Schema", "admin.registries.schema.head": "Metadata Schema", + + // "admin.registries.schema.notification.created": "Successfully created metadata schema \"{{prefix}}\"", + // TODO New key - Add a translation + "admin.registries.schema.notification.created": "Successfully created metadata schema \"{{prefix}}\"", + + // "admin.registries.schema.notification.deleted.failure": "Failed to delete {{amount}} metadata schemas", + // TODO New key - Add a translation + "admin.registries.schema.notification.deleted.failure": "Failed to delete {{amount}} metadata schemas", + + // "admin.registries.schema.notification.deleted.success": "Successfully deleted {{amount}} metadata schemas", + // TODO New key - Add a translation + "admin.registries.schema.notification.deleted.success": "Successfully deleted {{amount}} metadata schemas", + + // "admin.registries.schema.notification.edited": "Successfully edited metadata schema \"{{prefix}}\"", + // TODO New key - Add a translation + "admin.registries.schema.notification.edited": "Successfully edited metadata schema \"{{prefix}}\"", + + // "admin.registries.schema.notification.failure": "Error", + // TODO New key - Add a translation + "admin.registries.schema.notification.failure": "Error", + + // "admin.registries.schema.notification.field.created": "Successfully created metadata field \"{{field}}\"", + // TODO New key - Add a translation + "admin.registries.schema.notification.field.created": "Successfully created metadata field \"{{field}}\"", + + // "admin.registries.schema.notification.field.deleted.failure": "Failed to delete {{amount}} metadata fields", + // TODO New key - Add a translation + "admin.registries.schema.notification.field.deleted.failure": "Failed to delete {{amount}} metadata fields", + + // "admin.registries.schema.notification.field.deleted.success": "Successfully deleted {{amount}} metadata fields", + // TODO New key - Add a translation + "admin.registries.schema.notification.field.deleted.success": "Successfully deleted {{amount}} metadata fields", + + // "admin.registries.schema.notification.field.edited": "Successfully edited metadata field \"{{field}}\"", + // TODO New key - Add a translation + "admin.registries.schema.notification.field.edited": "Successfully edited metadata field \"{{field}}\"", + + // "admin.registries.schema.notification.success": "Success", + // TODO New key - Add a translation + "admin.registries.schema.notification.success": "Success", + + // "admin.registries.schema.return": "Return", + // TODO New key - Add a translation + "admin.registries.schema.return": "Return", + + // "admin.registries.schema.title": "DSpace Angular :: Metadata Schema Registry", "admin.registries.schema.title": "DSpace Angular :: Metadata Schema Register", - + + + + // "auth.errors.invalid-user": "Invalid email address or password.", "auth.errors.invalid-user": "Ongeldig e-mailadres of wachtwoord.", + + // "auth.messages.expired": "Your session has expired. Please log in again.", "auth.messages.expired": "Uw sessie is vervallen. Gelieve opnieuw aan te melden.", - + + + + // "browse.comcol.by.author": "By Author", + // TODO New key - Add a translation + "browse.comcol.by.author": "By Author", + + // "browse.comcol.by.dateissued": "By Issue Date", + // TODO New key - Add a translation + "browse.comcol.by.dateissued": "By Issue Date", + + // "browse.comcol.by.subject": "By Subject", + // TODO New key - Add a translation + "browse.comcol.by.subject": "By Subject", + + // "browse.comcol.by.title": "By Title", + // TODO New key - Add a translation + "browse.comcol.by.title": "By Title", + + // "browse.comcol.head": "Browse", + // TODO New key - Add a translation + "browse.comcol.head": "Browse", + + // "browse.empty": "No items to show.", + // TODO New key - Add a translation + "browse.empty": "No items to show.", + + // "browse.metadata.author": "Author", + // TODO New key - Add a translation + "browse.metadata.author": "Author", + + // "browse.metadata.dateissued": "Issue Date", + // TODO New key - Add a translation + "browse.metadata.dateissued": "Issue Date", + + // "browse.metadata.subject": "Subject", + // TODO New key - Add a translation + "browse.metadata.subject": "Subject", + + // "browse.metadata.title": "Title", + // TODO New key - Add a translation + "browse.metadata.title": "Title", + + // "browse.startsWith.choose_start": "(Choose start)", + // TODO New key - Add a translation + "browse.startsWith.choose_start": "(Choose start)", + + // "browse.startsWith.choose_year": "(Choose year)", + // TODO New key - Add a translation + "browse.startsWith.choose_year": "(Choose year)", + + // "browse.startsWith.jump": "Jump to a point in the index:", + // TODO New key - Add a translation + "browse.startsWith.jump": "Jump to a point in the index:", + + // "browse.startsWith.months.april": "April", + // TODO New key - Add a translation + "browse.startsWith.months.april": "April", + + // "browse.startsWith.months.august": "August", + // TODO New key - Add a translation + "browse.startsWith.months.august": "August", + + // "browse.startsWith.months.december": "December", + // TODO New key - Add a translation + "browse.startsWith.months.december": "December", + + // "browse.startsWith.months.february": "February", + // TODO New key - Add a translation + "browse.startsWith.months.february": "February", + + // "browse.startsWith.months.january": "January", + // TODO New key - Add a translation + "browse.startsWith.months.january": "January", + + // "browse.startsWith.months.july": "July", + // TODO New key - Add a translation + "browse.startsWith.months.july": "July", + + // "browse.startsWith.months.june": "June", + // TODO New key - Add a translation + "browse.startsWith.months.june": "June", + + // "browse.startsWith.months.march": "March", + // TODO New key - Add a translation + "browse.startsWith.months.march": "March", + + // "browse.startsWith.months.may": "May", + // TODO New key - Add a translation + "browse.startsWith.months.may": "May", + + // "browse.startsWith.months.none": "(Choose month)", + // TODO New key - Add a translation + "browse.startsWith.months.none": "(Choose month)", + + // "browse.startsWith.months.november": "November", + // TODO New key - Add a translation + "browse.startsWith.months.november": "November", + + // "browse.startsWith.months.october": "October", + // TODO New key - Add a translation + "browse.startsWith.months.october": "October", + + // "browse.startsWith.months.september": "September", + // TODO New key - Add a translation + "browse.startsWith.months.september": "September", + + // "browse.startsWith.submit": "Go", + // TODO New key - Add a translation + "browse.startsWith.submit": "Go", + + // "browse.startsWith.type_date": "Or type in a date (year-month):", + // TODO New key - Add a translation + "browse.startsWith.type_date": "Or type in a date (year-month):", + + // "browse.startsWith.type_text": "Or enter first few letters:", + // TODO New key - Add a translation + "browse.startsWith.type_text": "Or enter first few letters:", + + // "browse.title": "Browsing {{ collection }} by {{ field }} {{ value }}", "browse.title": "Verken {{ collection }} volgens {{ field }} {{ value }}", - + + + + // "chips.remove": "Remove chip", + // TODO New key - Add a translation + "chips.remove": "Remove chip", + + + + // "collection.create.head": "Create a Collection", + // TODO New key - Add a translation + "collection.create.head": "Create a Collection", + + // "collection.create.sub-head": "Create a Collection for Community {{ parent }}", + // TODO New key - Add a translation + "collection.create.sub-head": "Create a Collection for Community {{ parent }}", + + // "collection.delete.cancel": "Cancel", + // TODO New key - Add a translation + "collection.delete.cancel": "Cancel", + + // "collection.delete.confirm": "Confirm", + // TODO New key - Add a translation + "collection.delete.confirm": "Confirm", + + // "collection.delete.head": "Delete Collection", + // TODO New key - Add a translation + "collection.delete.head": "Delete Collection", + + // "collection.delete.notification.fail": "Collection could not be deleted", + // TODO New key - Add a translation + "collection.delete.notification.fail": "Collection could not be deleted", + + // "collection.delete.notification.success": "Successfully deleted collection", + // TODO New key - Add a translation + "collection.delete.notification.success": "Successfully deleted collection", + + // "collection.delete.text": "Are you sure you want to delete collection \"{{ dso }}\"", + // TODO New key - Add a translation + "collection.delete.text": "Are you sure you want to delete collection \"{{ dso }}\"", + + + + // "collection.edit.delete": "Delete this collection", + // TODO New key - Add a translation + "collection.edit.delete": "Delete this collection", + + // "collection.edit.head": "Edit Collection", + // TODO New key - Add a translation + "collection.edit.head": "Edit Collection", + + + + // "collection.edit.item-mapper.cancel": "Cancel", + // TODO New key - Add a translation + "collection.edit.item-mapper.cancel": "Cancel", + + // "collection.edit.item-mapper.collection": "Collection: \"{{name}}\"", + // TODO New key - Add a translation + "collection.edit.item-mapper.collection": "Collection: \"{{name}}\"", + + // "collection.edit.item-mapper.confirm": "Map selected items", + // TODO New key - Add a translation + "collection.edit.item-mapper.confirm": "Map selected items", + + // "collection.edit.item-mapper.description": "This is the item mapper tool that allows collection administrators to map items from other collections into this collection. You can search for items from other collections and map them, or browse the list of currently mapped items.", + // TODO New key - Add a translation + "collection.edit.item-mapper.description": "This is the item mapper tool that allows collection administrators to map items from other collections into this collection. You can search for items from other collections and map them, or browse the list of currently mapped items.", + + // "collection.edit.item-mapper.head": "Item Mapper - Map Items from Other Collections", + // TODO New key - Add a translation + "collection.edit.item-mapper.head": "Item Mapper - Map Items from Other Collections", + + // "collection.edit.item-mapper.no-search": "Please enter a query to search", + // TODO New key - Add a translation + "collection.edit.item-mapper.no-search": "Please enter a query to search", + + // "collection.edit.item-mapper.notifications.map.error.content": "Errors occurred for mapping of {{amount}} items.", + // TODO New key - Add a translation + "collection.edit.item-mapper.notifications.map.error.content": "Errors occurred for mapping of {{amount}} items.", + + // "collection.edit.item-mapper.notifications.map.error.head": "Mapping errors", + // TODO New key - Add a translation + "collection.edit.item-mapper.notifications.map.error.head": "Mapping errors", + + // "collection.edit.item-mapper.notifications.map.success.content": "Successfully mapped {{amount}} items.", + // TODO New key - Add a translation + "collection.edit.item-mapper.notifications.map.success.content": "Successfully mapped {{amount}} items.", + + // "collection.edit.item-mapper.notifications.map.success.head": "Mapping completed", + // TODO New key - Add a translation + "collection.edit.item-mapper.notifications.map.success.head": "Mapping completed", + + // "collection.edit.item-mapper.notifications.unmap.error.content": "Errors occurred for removing the mappings of {{amount}} items.", + // TODO New key - Add a translation + "collection.edit.item-mapper.notifications.unmap.error.content": "Errors occurred for removing the mappings of {{amount}} items.", + + // "collection.edit.item-mapper.notifications.unmap.error.head": "Remove mapping errors", + // TODO New key - Add a translation + "collection.edit.item-mapper.notifications.unmap.error.head": "Remove mapping errors", + + // "collection.edit.item-mapper.notifications.unmap.success.content": "Successfully removed the mappings of {{amount}} items.", + // TODO New key - Add a translation + "collection.edit.item-mapper.notifications.unmap.success.content": "Successfully removed the mappings of {{amount}} items.", + + // "collection.edit.item-mapper.notifications.unmap.success.head": "Remove mapping completed", + // TODO New key - Add a translation + "collection.edit.item-mapper.notifications.unmap.success.head": "Remove mapping completed", + + // "collection.edit.item-mapper.remove": "Remove selected item mappings", + // TODO New key - Add a translation + "collection.edit.item-mapper.remove": "Remove selected item mappings", + + // "collection.edit.item-mapper.tabs.browse": "Browse mapped items", + // TODO New key - Add a translation + "collection.edit.item-mapper.tabs.browse": "Browse mapped items", + + // "collection.edit.item-mapper.tabs.map": "Map new items", + // TODO New key - Add a translation + "collection.edit.item-mapper.tabs.map": "Map new items", + + + + // "collection.form.abstract": "Short Description", + // TODO New key - Add a translation + "collection.form.abstract": "Short Description", + + // "collection.form.description": "Introductory text (HTML)", + // TODO New key - Add a translation + "collection.form.description": "Introductory text (HTML)", + + // "collection.form.errors.title.required": "Please enter a collection name", + // TODO New key - Add a translation + "collection.form.errors.title.required": "Please enter a collection name", + + // "collection.form.license": "License", + // TODO New key - Add a translation + "collection.form.license": "License", + + // "collection.form.provenance": "Provenance", + // TODO New key - Add a translation + "collection.form.provenance": "Provenance", + + // "collection.form.rights": "Copyright text (HTML)", + // TODO New key - Add a translation + "collection.form.rights": "Copyright text (HTML)", + + // "collection.form.tableofcontents": "News (HTML)", + // TODO New key - Add a translation + "collection.form.tableofcontents": "News (HTML)", + + // "collection.form.title": "Name", + // TODO New key - Add a translation + "collection.form.title": "Name", + + + + // "collection.page.browse.recent.head": "Recent Submissions", "collection.page.browse.recent.head": "Recent toegevoegd", + + // "collection.page.browse.recent.empty": "No items to show", + // TODO New key - Add a translation + "collection.page.browse.recent.empty": "No items to show", + + // "collection.page.handle": "Permanent URI for this collection", + // TODO New key - Add a translation + "collection.page.handle": "Permanent URI for this collection", + + // "collection.page.license": "License", "collection.page.license": "Licentie", + + // "collection.page.news": "News", "collection.page.news": "Nieuws", - + + + + // "collection.select.confirm": "Confirm selected", + // TODO New key - Add a translation + "collection.select.confirm": "Confirm selected", + + // "collection.select.empty": "No collections to show", + // TODO New key - Add a translation + "collection.select.empty": "No collections to show", + + // "collection.select.table.title": "Title", + // TODO New key - Add a translation + "collection.select.table.title": "Title", + + + + // "community.create.head": "Create a Community", + // TODO New key - Add a translation + "community.create.head": "Create a Community", + + // "community.create.sub-head": "Create a Sub-Community for Community {{ parent }}", + // TODO New key - Add a translation + "community.create.sub-head": "Create a Sub-Community for Community {{ parent }}", + + // "community.delete.cancel": "Cancel", + // TODO New key - Add a translation + "community.delete.cancel": "Cancel", + + // "community.delete.confirm": "Confirm", + // TODO New key - Add a translation + "community.delete.confirm": "Confirm", + + // "community.delete.head": "Delete Community", + // TODO New key - Add a translation + "community.delete.head": "Delete Community", + + // "community.delete.notification.fail": "Community could not be deleted", + // TODO New key - Add a translation + "community.delete.notification.fail": "Community could not be deleted", + + // "community.delete.notification.success": "Successfully deleted community", + // TODO New key - Add a translation + "community.delete.notification.success": "Successfully deleted community", + + // "community.delete.text": "Are you sure you want to delete community \"{{ dso }}\"", + // TODO New key - Add a translation + "community.delete.text": "Are you sure you want to delete community \"{{ dso }}\"", + + // "community.edit.delete": "Delete this community", + // TODO New key - Add a translation + "community.edit.delete": "Delete this community", + + // "community.edit.head": "Edit Community", + // TODO New key - Add a translation + "community.edit.head": "Edit Community", + + // "community.form.abstract": "Short Description", + // TODO New key - Add a translation + "community.form.abstract": "Short Description", + + // "community.form.description": "Introductory text (HTML)", + // TODO New key - Add a translation + "community.form.description": "Introductory text (HTML)", + + // "community.form.errors.title.required": "Please enter a community name", + // TODO New key - Add a translation + "community.form.errors.title.required": "Please enter a community name", + + // "community.form.rights": "Copyright text (HTML)", + // TODO New key - Add a translation + "community.form.rights": "Copyright text (HTML)", + + // "community.form.tableofcontents": "News (HTML)", + // TODO New key - Add a translation + "community.form.tableofcontents": "News (HTML)", + + // "community.form.title": "Name", + // TODO New key - Add a translation + "community.form.title": "Name", + + // "community.page.handle": "Permanent URI for this community", + // TODO New key - Add a translation + "community.page.handle": "Permanent URI for this community", + + // "community.page.license": "License", "community.page.license": "Licentie", + + // "community.page.news": "News", "community.page.news": "Nieuws", + + // "community.all-lists.head": "Subcommunities and Collections", + // TODO New key - Add a translation + "community.all-lists.head": "Subcommunities and Collections", + + // "community.sub-collection-list.head": "Collections of this Community", "community.sub-collection-list.head": "Collecties in deze Community", - + + // "community.sub-community-list.head": "Communities of this Community", + // TODO New key - Add a translation + "community.sub-community-list.head": "Communities of this Community", + + + + // "dso-selector.create.collection.head": "New collection", + // TODO New key - Add a translation + "dso-selector.create.collection.head": "New collection", + + // "dso-selector.create.community.head": "New community", + // TODO New key - Add a translation + "dso-selector.create.community.head": "New community", + + // "dso-selector.create.community.sub-level": "Create a new community in", + // TODO New key - Add a translation + "dso-selector.create.community.sub-level": "Create a new community in", + + // "dso-selector.create.community.top-level": "Create a new top-level community", + // TODO New key - Add a translation + "dso-selector.create.community.top-level": "Create a new top-level community", + + // "dso-selector.create.item.head": "New item", + // TODO New key - Add a translation + "dso-selector.create.item.head": "New item", + + // "dso-selector.edit.collection.head": "Edit collection", + // TODO New key - Add a translation + "dso-selector.edit.collection.head": "Edit collection", + + // "dso-selector.edit.community.head": "Edit community", + // TODO New key - Add a translation + "dso-selector.edit.community.head": "Edit community", + + // "dso-selector.edit.item.head": "Edit item", + // TODO New key - Add a translation + "dso-selector.edit.item.head": "Edit item", + + // "dso-selector.no-results": "No {{ type }} found", + // TODO New key - Add a translation + "dso-selector.no-results": "No {{ type }} found", + + // "dso-selector.placeholder": "Search for a {{ type }}", + // TODO New key - Add a translation + "dso-selector.placeholder": "Search for a {{ type }}", + + + + // "error.browse-by": "Error fetching items", "error.browse-by": "Fout bij het ophalen van items", + + // "error.collection": "Error fetching collection", "error.collection": "Fout bij het ophalen van een collectie", + + // "error.collections": "Error fetching collections", + // TODO New key - Add a translation + "error.collections": "Error fetching collections", + + // "error.community": "Error fetching community", "error.community": "Fout bij het ophalen van een community", + // "error.identifier": "No item found for the identifier", + // TODO New key - Add a translation + "error.identifier": "No item found for the identifier", + + // "error.identifier": "No item found for the identifier", + // TODO New key - Add a translation + "error.identifier": "No item found for the identifier", + + // "error.default": "Error", "error.default": "Fout", + + // "error.item": "Error fetching item", "error.item": "Fout bij het ophalen van items", + + // "error.items": "Error fetching items", + // TODO New key - Add a translation + "error.items": "Error fetching items", + + // "error.objects": "Error fetching objects", "error.objects": "Fout bij het ophalen van objecten", + + // "error.recent-submissions": "Error fetching recent submissions", "error.recent-submissions": "Fout bij het ophalen van recent toegevoegde items", + + // "error.search-results": "Error fetching search results", "error.search-results": "Fout bij het ophalen van zoekresultaten", + + // "error.sub-collections": "Error fetching sub-collections", "error.sub-collections": "Fout bij het ophalen van sub-collecties", + + // "error.sub-communities": "Error fetching sub-communities", + // TODO New key - Add a translation + "error.sub-communities": "Error fetching sub-communities", + + // "error.submission.sections.init-form-error": "An error occurred during section initialize, please check your input-form configuration. Details are below :

", + // TODO New key - Add a translation + "error.submission.sections.init-form-error": "An error occurred during section initialize, please check your input-form configuration. Details are below :

", + + // "error.top-level-communities": "Error fetching top-level communities", "error.top-level-communities": "Fout bij het inladen van communities op het hoogste niveau", + + // "error.validation.license.notgranted": "You must grant this license to complete your submission. If you are unable to grant this license at this time you may save your work and return later or remove the submission.", "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.", - "error.validation.pattern": "Deze invoer is niet toegelaten volgens dit patroon: {{ pattern }}.", - + + // "error.validation.pattern": "This input is restricted by the current pattern: {{ pattern }}.", + // TODO New key - Add a translation + "error.validation.pattern": "This input is restricted by the current pattern: {{ pattern }}.", + + + + // "footer.copyright": "copyright © 2002-{{ year }}", "footer.copyright": "copyright © 2002-{{ year }}", + + // "footer.link.dspace": "DSpace software", "footer.link.dspace": "DSpace software", + + // "footer.link.duraspace": "DuraSpace", "footer.link.duraspace": "DuraSpace", - + + + + // "form.cancel": "Cancel", "form.cancel": "Annuleer", + + // "form.clear": "Clear", + // TODO New key - Add a translation + "form.clear": "Clear", + + // "form.clear-help": "Click here to remove the selected value", + // TODO New key - Add a translation + "form.clear-help": "Click here to remove the selected value", + + // "form.edit": "Edit", + // TODO New key - Add a translation + "form.edit": "Edit", + + // "form.edit-help": "Click here to edit the selected value", + // TODO New key - Add a translation + "form.edit-help": "Click here to edit the selected value", + + // "form.first-name": "First name", "form.first-name": "Voornaam", + + // "form.group-collapse": "Collapse", "form.group-collapse": "Inklappen", + + // "form.group-collapse-help": "Click here to collapse", "form.group-collapse-help": "Klik hier op in te klappen", + + // "form.group-expand": "Expand", "form.group-expand": "Uitklappen", + + // "form.group-expand-help": "Click here to expand and add more elements", "form.group-expand-help": "Klik hier om uit te klappen en om meer onderdelen toe te voegen", + + // "form.last-name": "Last name", "form.last-name": "Achternaam", + + // "form.loading": "Loading...", "form.loading": "Inladen...", + + // "form.no-results": "No results found", "form.no-results": "Geen resultaten gevonden", + + // "form.no-value": "No value entered", "form.no-value": "Geen waarde ingevoerd", + + // "form.other-information": {}, + // TODO New key - Add a translation + "form.other-information": {}, + + // "form.remove": "Remove", "form.remove": "Verwijder", + + // "form.save": "Save", + // TODO New key - Add a translation + "form.save": "Save", + + // "form.save-help": "Save changes", + // TODO New key - Add a translation + "form.save-help": "Save changes", + + // "form.search": "Search", "form.search": "Zoek", + + // "form.search-help": "Click here to looking for an existing correspondence", + // TODO New key - Add a translation + "form.search-help": "Click here to looking for an existing correspondence", + + // "form.submit": "Submit", "form.submit": "Verstuur", - + + + + // "home.description": "", "home.description": "", + + // "home.title": "DSpace Angular :: Home", "home.title": "DSpace Angular :: Home", + + // "home.top-level-communities.head": "Communities in DSpace", "home.top-level-communities.head": "Communities in DSpace", + + // "home.top-level-communities.help": "Select a community to browse its collections.", "home.top-level-communities.help": "Selecteer een community om diens collecties te verkennen.", - + + + + // "item.edit.delete.cancel": "Cancel", + // TODO New key - Add a translation + "item.edit.delete.cancel": "Cancel", + + // "item.edit.delete.confirm": "Delete", + // TODO New key - Add a translation + "item.edit.delete.confirm": "Delete", + + // "item.edit.delete.description": "Are you sure this item should be completely deleted? Caution: At present, no tombstone would be left.", + // TODO New key - Add a translation + "item.edit.delete.description": "Are you sure this item should be completely deleted? Caution: At present, no tombstone would be left.", + + // "item.edit.delete.error": "An error occurred while deleting the item", + // TODO New key - Add a translation + "item.edit.delete.error": "An error occurred while deleting the item", + + // "item.edit.delete.header": "Delete item: {{ id }}", + // TODO New key - Add a translation + "item.edit.delete.header": "Delete item: {{ id }}", + + // "item.edit.delete.success": "The item has been deleted", + // TODO New key - Add a translation + "item.edit.delete.success": "The item has been deleted", + + // "item.edit.head": "Edit Item", + // TODO New key - Add a translation + "item.edit.head": "Edit Item", + + + + // "item.edit.item-mapper.buttons.add": "Map item to selected collections", + // TODO New key - Add a translation + "item.edit.item-mapper.buttons.add": "Map item to selected collections", + + // "item.edit.item-mapper.buttons.remove": "Remove item's mapping for selected collections", + // TODO New key - Add a translation + "item.edit.item-mapper.buttons.remove": "Remove item's mapping for selected collections", + + // "item.edit.item-mapper.cancel": "Cancel", + // TODO New key - Add a translation + "item.edit.item-mapper.cancel": "Cancel", + + // "item.edit.item-mapper.description": "This is the item mapper tool that allows administrators to map this item to other collections. You can search for collections and map them, or browse the list of collections the item is currently mapped to.", + // TODO New key - Add a translation + "item.edit.item-mapper.description": "This is the item mapper tool that allows administrators to map this item to other collections. You can search for collections and map them, or browse the list of collections the item is currently mapped to.", + + // "item.edit.item-mapper.head": "Item Mapper - Map Item to Collections", + // TODO New key - Add a translation + "item.edit.item-mapper.head": "Item Mapper - Map Item to Collections", + + // "item.edit.item-mapper.item": "Item: \"{{name}}\"", + // TODO New key - Add a translation + "item.edit.item-mapper.item": "Item: \"{{name}}\"", + + // "item.edit.item-mapper.no-search": "Please enter a query to search", + // TODO New key - Add a translation + "item.edit.item-mapper.no-search": "Please enter a query to search", + + // "item.edit.item-mapper.notifications.add.error.content": "Errors occurred for mapping of item to {{amount}} collections.", + // TODO New key - Add a translation + "item.edit.item-mapper.notifications.add.error.content": "Errors occurred for mapping of item to {{amount}} collections.", + + // "item.edit.item-mapper.notifications.add.error.head": "Mapping errors", + // TODO New key - Add a translation + "item.edit.item-mapper.notifications.add.error.head": "Mapping errors", + + // "item.edit.item-mapper.notifications.add.success.content": "Successfully mapped item to {{amount}} collections.", + // TODO New key - Add a translation + "item.edit.item-mapper.notifications.add.success.content": "Successfully mapped item to {{amount}} collections.", + + // "item.edit.item-mapper.notifications.add.success.head": "Mapping completed", + // TODO New key - Add a translation + "item.edit.item-mapper.notifications.add.success.head": "Mapping completed", + + // "item.edit.item-mapper.notifications.remove.error.content": "Errors occurred for the removal of the mapping to {{amount}} collections.", + // TODO New key - Add a translation + "item.edit.item-mapper.notifications.remove.error.content": "Errors occurred for the removal of the mapping to {{amount}} collections.", + + // "item.edit.item-mapper.notifications.remove.error.head": "Removal of mapping errors", + // TODO New key - Add a translation + "item.edit.item-mapper.notifications.remove.error.head": "Removal of mapping errors", + + // "item.edit.item-mapper.notifications.remove.success.content": "Successfully removed mapping of item to {{amount}} collections.", + // TODO New key - Add a translation + "item.edit.item-mapper.notifications.remove.success.content": "Successfully removed mapping of item to {{amount}} collections.", + + // "item.edit.item-mapper.notifications.remove.success.head": "Removal of mapping completed", + // TODO New key - Add a translation + "item.edit.item-mapper.notifications.remove.success.head": "Removal of mapping completed", + + // "item.edit.item-mapper.tabs.browse": "Browse mapped collections", + // TODO New key - Add a translation + "item.edit.item-mapper.tabs.browse": "Browse mapped collections", + + // "item.edit.item-mapper.tabs.map": "Map new collections", + // TODO New key - Add a translation + "item.edit.item-mapper.tabs.map": "Map new collections", + + + + // "item.edit.metadata.add-button": "Add", + // TODO New key - Add a translation + "item.edit.metadata.add-button": "Add", + + // "item.edit.metadata.discard-button": "Discard", + // TODO New key - Add a translation + "item.edit.metadata.discard-button": "Discard", + + // "item.edit.metadata.edit.buttons.edit": "Edit", + // TODO New key - Add a translation + "item.edit.metadata.edit.buttons.edit": "Edit", + + // "item.edit.metadata.edit.buttons.remove": "Remove", + // TODO New key - Add a translation + "item.edit.metadata.edit.buttons.remove": "Remove", + + // "item.edit.metadata.edit.buttons.undo": "Undo changes", + // TODO New key - Add a translation + "item.edit.metadata.edit.buttons.undo": "Undo changes", + + // "item.edit.metadata.edit.buttons.unedit": "Stop editing", + // TODO New key - Add a translation + "item.edit.metadata.edit.buttons.unedit": "Stop editing", + + // "item.edit.metadata.headers.edit": "Edit", + // TODO New key - Add a translation + "item.edit.metadata.headers.edit": "Edit", + + // "item.edit.metadata.headers.field": "Field", + // TODO New key - Add a translation + "item.edit.metadata.headers.field": "Field", + + // "item.edit.metadata.headers.language": "Lang", + // TODO New key - Add a translation + "item.edit.metadata.headers.language": "Lang", + + // "item.edit.metadata.headers.value": "Value", + // TODO New key - Add a translation + "item.edit.metadata.headers.value": "Value", + + // "item.edit.metadata.metadatafield.invalid": "Please choose a valid metadata field", + // TODO New key - Add a translation + "item.edit.metadata.metadatafield.invalid": "Please choose a valid metadata field", + + // "item.edit.metadata.notifications.discarded.content": "Your changes were discarded. To reinstate your changes click the 'Undo' button", + // TODO New key - Add a translation + "item.edit.metadata.notifications.discarded.content": "Your changes were discarded. To reinstate your changes click the 'Undo' button", + + // "item.edit.metadata.notifications.discarded.title": "Changed discarded", + // TODO New key - Add a translation + "item.edit.metadata.notifications.discarded.title": "Changed discarded", + + // "item.edit.metadata.notifications.invalid.content": "Your changes were not saved. Please make sure all fields are valid before you save.", + // TODO New key - Add a translation + "item.edit.metadata.notifications.invalid.content": "Your changes were not saved. Please make sure all fields are valid before you save.", + + // "item.edit.metadata.notifications.invalid.title": "Metadata invalid", + // TODO New key - Add a translation + "item.edit.metadata.notifications.invalid.title": "Metadata invalid", + + // "item.edit.metadata.notifications.outdated.content": "The item you're currently working on has been changed by another user. Your current changes are discarded to prevent conflicts", + // TODO New key - Add a translation + "item.edit.metadata.notifications.outdated.content": "The item you're currently working on has been changed by another user. Your current changes are discarded to prevent conflicts", + + // "item.edit.metadata.notifications.outdated.title": "Changed outdated", + // TODO New key - Add a translation + "item.edit.metadata.notifications.outdated.title": "Changed outdated", + + // "item.edit.metadata.notifications.saved.content": "Your changes to this item's metadata were saved.", + // TODO New key - Add a translation + "item.edit.metadata.notifications.saved.content": "Your changes to this item's metadata were saved.", + + // "item.edit.metadata.notifications.saved.title": "Metadata saved", + // TODO New key - Add a translation + "item.edit.metadata.notifications.saved.title": "Metadata saved", + + // "item.edit.metadata.reinstate-button": "Undo", + // TODO New key - Add a translation + "item.edit.metadata.reinstate-button": "Undo", + + // "item.edit.metadata.save-button": "Save", + // TODO New key - Add a translation + "item.edit.metadata.save-button": "Save", + + + + // "item.edit.modify.overview.field": "Field", + // TODO New key - Add a translation + "item.edit.modify.overview.field": "Field", + + // "item.edit.modify.overview.language": "Language", + // TODO New key - Add a translation + "item.edit.modify.overview.language": "Language", + + // "item.edit.modify.overview.value": "Value", + // TODO New key - Add a translation + "item.edit.modify.overview.value": "Value", + + + + // "item.edit.move.cancel": "Cancel", + // TODO New key - Add a translation + "item.edit.move.cancel": "Cancel", + + // "item.edit.move.description": "Select the collection you wish to move this item to. To narrow down the list of displayed collections, you can enter a search query in the box.", + // TODO New key - Add a translation + "item.edit.move.description": "Select the collection you wish to move this item to. To narrow down the list of displayed collections, you can enter a search query in the box.", + + // "item.edit.move.error": "An error occured when attempting to move the item", + // TODO New key - Add a translation + "item.edit.move.error": "An error occured when attempting to move the item", + + // "item.edit.move.head": "Move item: {{id}}", + // TODO New key - Add a translation + "item.edit.move.head": "Move item: {{id}}", + + // "item.edit.move.inheritpolicies.checkbox": "Inherit policies", + // TODO New key - Add a translation + "item.edit.move.inheritpolicies.checkbox": "Inherit policies", + + // "item.edit.move.inheritpolicies.description": "Inherit the default policies of the destination collection", + // TODO New key - Add a translation + "item.edit.move.inheritpolicies.description": "Inherit the default policies of the destination collection", + + // "item.edit.move.move": "Move", + // TODO New key - Add a translation + "item.edit.move.move": "Move", + + // "item.edit.move.processing": "Moving...", + // TODO New key - Add a translation + "item.edit.move.processing": "Moving...", + + // "item.edit.move.search.placeholder": "Enter a search query to look for collections", + // TODO New key - Add a translation + "item.edit.move.search.placeholder": "Enter a search query to look for collections", + + // "item.edit.move.success": "The item has been moved succesfully", + // TODO New key - Add a translation + "item.edit.move.success": "The item has been moved succesfully", + + // "item.edit.move.title": "Move item", + // TODO New key - Add a translation + "item.edit.move.title": "Move item", + + + + // "item.edit.private.cancel": "Cancel", + // TODO New key - Add a translation + "item.edit.private.cancel": "Cancel", + + // "item.edit.private.confirm": "Make it Private", + // TODO New key - Add a translation + "item.edit.private.confirm": "Make it Private", + + // "item.edit.private.description": "Are you sure this item should be made private in the archive?", + // TODO New key - Add a translation + "item.edit.private.description": "Are you sure this item should be made private in the archive?", + + // "item.edit.private.error": "An error occurred while making the item private", + // TODO New key - Add a translation + "item.edit.private.error": "An error occurred while making the item private", + + // "item.edit.private.header": "Make item private: {{ id }}", + // TODO New key - Add a translation + "item.edit.private.header": "Make item private: {{ id }}", + + // "item.edit.private.success": "The item is now private", + // TODO New key - Add a translation + "item.edit.private.success": "The item is now private", + + + + // "item.edit.public.cancel": "Cancel", + // TODO New key - Add a translation + "item.edit.public.cancel": "Cancel", + + // "item.edit.public.confirm": "Make it Public", + // TODO New key - Add a translation + "item.edit.public.confirm": "Make it Public", + + // "item.edit.public.description": "Are you sure this item should be made public in the archive?", + // TODO New key - Add a translation + "item.edit.public.description": "Are you sure this item should be made public in the archive?", + + // "item.edit.public.error": "An error occurred while making the item public", + // TODO New key - Add a translation + "item.edit.public.error": "An error occurred while making the item public", + + // "item.edit.public.header": "Make item public: {{ id }}", + // TODO New key - Add a translation + "item.edit.public.header": "Make item public: {{ id }}", + + // "item.edit.public.success": "The item is now public", + // TODO New key - Add a translation + "item.edit.public.success": "The item is now public", + + + + // "item.edit.reinstate.cancel": "Cancel", + // TODO New key - Add a translation + "item.edit.reinstate.cancel": "Cancel", + + // "item.edit.reinstate.confirm": "Reinstate", + // TODO New key - Add a translation + "item.edit.reinstate.confirm": "Reinstate", + + // "item.edit.reinstate.description": "Are you sure this item should be reinstated to the archive?", + // TODO New key - Add a translation + "item.edit.reinstate.description": "Are you sure this item should be reinstated to the archive?", + + // "item.edit.reinstate.error": "An error occurred while reinstating the item", + // TODO New key - Add a translation + "item.edit.reinstate.error": "An error occurred while reinstating the item", + + // "item.edit.reinstate.header": "Reinstate item: {{ id }}", + // TODO New key - Add a translation + "item.edit.reinstate.header": "Reinstate item: {{ id }}", + + // "item.edit.reinstate.success": "The item was reinstated successfully", + // TODO New key - Add a translation + "item.edit.reinstate.success": "The item was reinstated successfully", + + + + // "item.edit.relationships.discard-button": "Discard", + // TODO New key - Add a translation + "item.edit.relationships.discard-button": "Discard", + + // "item.edit.relationships.edit.buttons.remove": "Remove", + // TODO New key - Add a translation + "item.edit.relationships.edit.buttons.remove": "Remove", + + // "item.edit.relationships.edit.buttons.undo": "Undo changes", + // TODO New key - Add a translation + "item.edit.relationships.edit.buttons.undo": "Undo changes", + + // "item.edit.relationships.notifications.discarded.content": "Your changes were discarded. To reinstate your changes click the 'Undo' button", + // TODO New key - Add a translation + "item.edit.relationships.notifications.discarded.content": "Your changes were discarded. To reinstate your changes click the 'Undo' button", + + // "item.edit.relationships.notifications.discarded.title": "Changes discarded", + // TODO New key - Add a translation + "item.edit.relationships.notifications.discarded.title": "Changes discarded", + + // "item.edit.relationships.notifications.failed.title": "Error deleting relationship", + // TODO New key - Add a translation + "item.edit.relationships.notifications.failed.title": "Error deleting relationship", + + // "item.edit.relationships.notifications.outdated.content": "The item you're currently working on has been changed by another user. Your current changes are discarded to prevent conflicts", + // TODO New key - Add a translation + "item.edit.relationships.notifications.outdated.content": "The item you're currently working on has been changed by another user. Your current changes are discarded to prevent conflicts", + + // "item.edit.relationships.notifications.outdated.title": "Changes outdated", + // TODO New key - Add a translation + "item.edit.relationships.notifications.outdated.title": "Changes outdated", + + // "item.edit.relationships.notifications.saved.content": "Your changes to this item's relationships were saved.", + // TODO New key - Add a translation + "item.edit.relationships.notifications.saved.content": "Your changes to this item's relationships were saved.", + + // "item.edit.relationships.notifications.saved.title": "Relationships saved", + // TODO New key - Add a translation + "item.edit.relationships.notifications.saved.title": "Relationships saved", + + // "item.edit.relationships.reinstate-button": "Undo", + // TODO New key - Add a translation + "item.edit.relationships.reinstate-button": "Undo", + + // "item.edit.relationships.save-button": "Save", + // TODO New key - Add a translation + "item.edit.relationships.save-button": "Save", + + + + // "item.edit.tabs.bitstreams.head": "Item Bitstreams", + // TODO New key - Add a translation + "item.edit.tabs.bitstreams.head": "Item Bitstreams", + + // "item.edit.tabs.bitstreams.title": "Item Edit - Bitstreams", + // TODO New key - Add a translation + "item.edit.tabs.bitstreams.title": "Item Edit - Bitstreams", + + // "item.edit.tabs.curate.head": "Curate", + // TODO New key - Add a translation + "item.edit.tabs.curate.head": "Curate", + + // "item.edit.tabs.curate.title": "Item Edit - Curate", + // TODO New key - Add a translation + "item.edit.tabs.curate.title": "Item Edit - Curate", + + // "item.edit.tabs.metadata.head": "Item Metadata", + // TODO New key - Add a translation + "item.edit.tabs.metadata.head": "Item Metadata", + + // "item.edit.tabs.metadata.title": "Item Edit - Metadata", + // TODO New key - Add a translation + "item.edit.tabs.metadata.title": "Item Edit - Metadata", + + // "item.edit.tabs.relationships.head": "Item Relationships", + // TODO New key - Add a translation + "item.edit.tabs.relationships.head": "Item Relationships", + + // "item.edit.tabs.relationships.title": "Item Edit - Relationships", + // TODO New key - Add a translation + "item.edit.tabs.relationships.title": "Item Edit - Relationships", + + // "item.edit.tabs.status.buttons.authorizations.button": "Authorizations...", + // TODO New key - Add a translation + "item.edit.tabs.status.buttons.authorizations.button": "Authorizations...", + + // "item.edit.tabs.status.buttons.authorizations.label": "Edit item's authorization policies", + // TODO New key - Add a translation + "item.edit.tabs.status.buttons.authorizations.label": "Edit item's authorization policies", + + // "item.edit.tabs.status.buttons.delete.button": "Permanently delete", + // TODO New key - Add a translation + "item.edit.tabs.status.buttons.delete.button": "Permanently delete", + + // "item.edit.tabs.status.buttons.delete.label": "Completely expunge item", + // TODO New key - Add a translation + "item.edit.tabs.status.buttons.delete.label": "Completely expunge item", + + // "item.edit.tabs.status.buttons.mappedCollections.button": "Mapped collections", + // TODO New key - Add a translation + "item.edit.tabs.status.buttons.mappedCollections.button": "Mapped collections", + + // "item.edit.tabs.status.buttons.mappedCollections.label": "Manage mapped collections", + // TODO New key - Add a translation + "item.edit.tabs.status.buttons.mappedCollections.label": "Manage mapped collections", + + // "item.edit.tabs.status.buttons.move.button": "Move...", + // TODO New key - Add a translation + "item.edit.tabs.status.buttons.move.button": "Move...", + + // "item.edit.tabs.status.buttons.move.label": "Move item to another collection", + // TODO New key - Add a translation + "item.edit.tabs.status.buttons.move.label": "Move item to another collection", + + // "item.edit.tabs.status.buttons.private.button": "Make it private...", + // TODO New key - Add a translation + "item.edit.tabs.status.buttons.private.button": "Make it private...", + + // "item.edit.tabs.status.buttons.private.label": "Make item private", + // TODO New key - Add a translation + "item.edit.tabs.status.buttons.private.label": "Make item private", + + // "item.edit.tabs.status.buttons.public.button": "Make it public...", + // TODO New key - Add a translation + "item.edit.tabs.status.buttons.public.button": "Make it public...", + + // "item.edit.tabs.status.buttons.public.label": "Make item public", + // TODO New key - Add a translation + "item.edit.tabs.status.buttons.public.label": "Make item public", + + // "item.edit.tabs.status.buttons.reinstate.button": "Reinstate...", + // TODO New key - Add a translation + "item.edit.tabs.status.buttons.reinstate.button": "Reinstate...", + + // "item.edit.tabs.status.buttons.reinstate.label": "Reinstate item into the repository", + // TODO New key - Add a translation + "item.edit.tabs.status.buttons.reinstate.label": "Reinstate item into the repository", + + // "item.edit.tabs.status.buttons.withdraw.button": "Withdraw...", + // TODO New key - Add a translation + "item.edit.tabs.status.buttons.withdraw.button": "Withdraw...", + + // "item.edit.tabs.status.buttons.withdraw.label": "Withdraw item from the repository", + // TODO New key - Add a translation + "item.edit.tabs.status.buttons.withdraw.label": "Withdraw item from the repository", + + // "item.edit.tabs.status.description": "Welcome to the item management page. From here you can withdraw, reinstate, move or delete the item. You may also update or add new metadata / bitstreams on the other tabs.", + // TODO New key - Add a translation + "item.edit.tabs.status.description": "Welcome to the item management page. From here you can withdraw, reinstate, move or delete the item. You may also update or add new metadata / bitstreams on the other tabs.", + + // "item.edit.tabs.status.head": "Item Status", + // TODO New key - Add a translation + "item.edit.tabs.status.head": "Item Status", + + // "item.edit.tabs.status.labels.handle": "Handle", + // TODO New key - Add a translation + "item.edit.tabs.status.labels.handle": "Handle", + + // "item.edit.tabs.status.labels.id": "Item Internal ID", + // TODO New key - Add a translation + "item.edit.tabs.status.labels.id": "Item Internal ID", + + // "item.edit.tabs.status.labels.itemPage": "Item Page", + // TODO New key - Add a translation + "item.edit.tabs.status.labels.itemPage": "Item Page", + + // "item.edit.tabs.status.labels.lastModified": "Last Modified", + // TODO New key - Add a translation + "item.edit.tabs.status.labels.lastModified": "Last Modified", + + // "item.edit.tabs.status.title": "Item Edit - Status", + // TODO New key - Add a translation + "item.edit.tabs.status.title": "Item Edit - Status", + + // "item.edit.tabs.view.head": "View Item", + // TODO New key - Add a translation + "item.edit.tabs.view.head": "View Item", + + // "item.edit.tabs.view.title": "Item Edit - View", + // TODO New key - Add a translation + "item.edit.tabs.view.title": "Item Edit - View", + + + + // "item.edit.withdraw.cancel": "Cancel", + // TODO New key - Add a translation + "item.edit.withdraw.cancel": "Cancel", + + // "item.edit.withdraw.confirm": "Withdraw", + // TODO New key - Add a translation + "item.edit.withdraw.confirm": "Withdraw", + + // "item.edit.withdraw.description": "Are you sure this item should be withdrawn from the archive?", + // TODO New key - Add a translation + "item.edit.withdraw.description": "Are you sure this item should be withdrawn from the archive?", + + // "item.edit.withdraw.error": "An error occurred while withdrawing the item", + // TODO New key - Add a translation + "item.edit.withdraw.error": "An error occurred while withdrawing the item", + + // "item.edit.withdraw.header": "Withdraw item: {{ id }}", + // TODO New key - Add a translation + "item.edit.withdraw.header": "Withdraw item: {{ id }}", + + // "item.edit.withdraw.success": "The item was withdrawn successfully", + // TODO New key - Add a translation + "item.edit.withdraw.success": "The item was withdrawn successfully", + + + + // "item.page.abstract": "Abstract", "item.page.abstract": "Abstract", + + // "item.page.author": "Authors", "item.page.author": "Auteur", + + // "item.page.citation": "Citation", + // TODO New key - Add a translation + "item.page.citation": "Citation", + + // "item.page.collections": "Collections", "item.page.collections": "Collecties", + + // "item.page.date": "Date", "item.page.date": "Datum", + + // "item.page.files": "Files", "item.page.files": "Bestanden", - "item.page.filesection.description": "Beschrijving:", + + // "item.page.filesection.description": "Description:", + // TODO New key - Add a translation + "item.page.filesection.description": "Description:", + + // "item.page.filesection.download": "Download", "item.page.filesection.download": "Download", - "item.page.filesection.format": "Formaat:", - "item.page.filesection.name": "Naam:", - "item.page.filesection.size": "Grootte:", + + // "item.page.filesection.format": "Format:", + // TODO New key - Add a translation + "item.page.filesection.format": "Format:", + + // "item.page.filesection.name": "Name:", + // TODO New key - Add a translation + "item.page.filesection.name": "Name:", + + // "item.page.filesection.size": "Size:", + // TODO New key - Add a translation + "item.page.filesection.size": "Size:", + + // "item.page.journal.search.title": "Articles in this journal", + // TODO New key - Add a translation + "item.page.journal.search.title": "Articles in this journal", + + // "item.page.link.full": "Full item page", "item.page.link.full": "Volledige itemweergave", + + // "item.page.link.simple": "Simple item page", "item.page.link.simple": "Eenvoudige itemweergave", + + // "item.page.person.search.title": "Articles by this author", + // TODO New key - Add a translation + "item.page.person.search.title": "Articles by this author", + + // "item.page.related-items.view-more": "View more", + // TODO New key - Add a translation + "item.page.related-items.view-more": "View more", + + // "item.page.related-items.view-less": "View less", + // TODO New key - Add a translation + "item.page.related-items.view-less": "View less", + + // "item.page.subject": "Keywords", + // TODO New key - Add a translation + "item.page.subject": "Keywords", + + // "item.page.uri": "URI", "item.page.uri": "URI", - + + + + // "item.select.confirm": "Confirm selected", + // TODO New key - Add a translation + "item.select.confirm": "Confirm selected", + + // "item.select.empty": "No items to show", + // TODO New key - Add a translation + "item.select.empty": "No items to show", + + // "item.select.table.author": "Author", + // TODO New key - Add a translation + "item.select.table.author": "Author", + + // "item.select.table.collection": "Collection", + // TODO New key - Add a translation + "item.select.table.collection": "Collection", + + // "item.select.table.title": "Title", + // TODO New key - Add a translation + "item.select.table.title": "Title", + + + + // "journal.listelement.badge": "Journal", + // TODO New key - Add a translation + "journal.listelement.badge": "Journal", + + // "journal.page.description": "Description", + // TODO New key - Add a translation + "journal.page.description": "Description", + + // "journal.page.editor": "Editor-in-Chief", + // TODO New key - Add a translation + "journal.page.editor": "Editor-in-Chief", + + // "journal.page.issn": "ISSN", + // TODO New key - Add a translation + "journal.page.issn": "ISSN", + + // "journal.page.publisher": "Publisher", + // TODO New key - Add a translation + "journal.page.publisher": "Publisher", + + // "journal.page.titleprefix": "Journal: ", + // TODO New key - Add a translation + "journal.page.titleprefix": "Journal: ", + + // "journal.search.results.head": "Journal Search Results", + // TODO New key - Add a translation + "journal.search.results.head": "Journal Search Results", + + // "journal.search.title": "DSpace Angular :: Journal Search", + // TODO New key - Add a translation + "journal.search.title": "DSpace Angular :: Journal Search", + + + + // "journalissue.listelement.badge": "Journal Issue", + // TODO New key - Add a translation + "journalissue.listelement.badge": "Journal Issue", + + // "journalissue.page.description": "Description", + // TODO New key - Add a translation + "journalissue.page.description": "Description", + + // "journalissue.page.issuedate": "Issue Date", + // TODO New key - Add a translation + "journalissue.page.issuedate": "Issue Date", + + // "journalissue.page.journal-issn": "Journal ISSN", + // TODO New key - Add a translation + "journalissue.page.journal-issn": "Journal ISSN", + + // "journalissue.page.journal-title": "Journal Title", + // TODO New key - Add a translation + "journalissue.page.journal-title": "Journal Title", + + // "journalissue.page.keyword": "Keywords", + // TODO New key - Add a translation + "journalissue.page.keyword": "Keywords", + + // "journalissue.page.number": "Number", + // TODO New key - Add a translation + "journalissue.page.number": "Number", + + // "journalissue.page.titleprefix": "Journal Issue: ", + // TODO New key - Add a translation + "journalissue.page.titleprefix": "Journal Issue: ", + + + + // "journalvolume.listelement.badge": "Journal Volume", + // TODO New key - Add a translation + "journalvolume.listelement.badge": "Journal Volume", + + // "journalvolume.page.description": "Description", + // TODO New key - Add a translation + "journalvolume.page.description": "Description", + + // "journalvolume.page.issuedate": "Issue Date", + // TODO New key - Add a translation + "journalvolume.page.issuedate": "Issue Date", + + // "journalvolume.page.titleprefix": "Journal Volume: ", + // TODO New key - Add a translation + "journalvolume.page.titleprefix": "Journal Volume: ", + + // "journalvolume.page.volume": "Volume", + // TODO New key - Add a translation + "journalvolume.page.volume": "Volume", + + + + // "loading.browse-by": "Loading items...", "loading.browse-by": "Items worden ingeladen...", + + // "loading.browse-by-page": "Loading page...", + // TODO New key - Add a translation + "loading.browse-by-page": "Loading page...", + + // "loading.collection": "Loading collection...", "loading.collection": "Collectie wordt ingeladen...", + + // "loading.collections": "Loading collections...", + // TODO New key - Add a translation + "loading.collections": "Loading collections...", + + // "loading.community": "Loading community...", "loading.community": "Community wordt ingeladen...", + + // "loading.default": "Loading...", "loading.default": "Laden...", + + // "loading.item": "Loading item...", "loading.item": "Item wordt ingeladen...", + + // "loading.items": "Loading items...", + // TODO New key - Add a translation + "loading.items": "Loading items...", + + // "loading.mydspace-results": "Loading items...", + // TODO New key - Add a translation + "loading.mydspace-results": "Loading items...", + + // "loading.objects": "Loading...", "loading.objects": "Laden...", + + // "loading.recent-submissions": "Loading recent submissions...", "loading.recent-submissions": "Recent toegevoegde items worden ingeladen...", + + // "loading.search-results": "Loading search results...", "loading.search-results": "Zoekresultaten worden ingeladen...", + + // "loading.sub-collections": "Loading sub-collections...", "loading.sub-collections": "De sub-collecties worden ingeladen...", + + // "loading.sub-communities": "Loading sub-communities...", + // TODO New key - Add a translation + "loading.sub-communities": "Loading sub-communities...", + + // "loading.top-level-communities": "Loading top-level communities...", "loading.top-level-communities": "Inladen van de Communities op het hoogste niveau...", - + + + + // "login.form.email": "Email address", "login.form.email": "Email adres", + + // "login.form.forgot-password": "Have you forgotten your password?", "login.form.forgot-password": "Bent u uw wachtwoord vergeten?", + + // "login.form.header": "Please log in to DSpace", "login.form.header": "Gelieve in te loggen in DSpace", + + // "login.form.new-user": "New user? Click here to register.", "login.form.new-user": "Nieuwe gebruiker? Gelieve u hier te registreren", + + // "login.form.password": "Password", "login.form.password": "Wachtwoord", + + // "login.form.submit": "Log in", "login.form.submit": "Aanmelden", + + // "login.title": "Login", "login.title": "Aanmelden", - + + + + // "logout.form.header": "Log out from DSpace", "logout.form.header": "Afmelden in DSpace", + + // "logout.form.submit": "Log out", "logout.form.submit": "Afmelden", + + // "logout.title": "Logout", "logout.title": "Afmelden", - - "nav.home": "Home", + + + + // "menu.header.admin": "Admin", + // TODO New key - Add a translation + "menu.header.admin": "Admin", + + // "menu.header.image.logo": "Repository logo", + // TODO New key - Add a translation + "menu.header.image.logo": "Repository logo", + + + + // "menu.section.access_control": "Access Control", + // TODO New key - Add a translation + "menu.section.access_control": "Access Control", + + // "menu.section.access_control_authorizations": "Authorizations", + // TODO New key - Add a translation + "menu.section.access_control_authorizations": "Authorizations", + + // "menu.section.access_control_groups": "Groups", + // TODO New key - Add a translation + "menu.section.access_control_groups": "Groups", + + // "menu.section.access_control_people": "People", + // TODO New key - Add a translation + "menu.section.access_control_people": "People", + + + + // "menu.section.browse_community": "This Community", + // TODO New key - Add a translation + "menu.section.browse_community": "This Community", + + // "menu.section.browse_community_by_author": "By Author", + // TODO New key - Add a translation + "menu.section.browse_community_by_author": "By Author", + + // "menu.section.browse_community_by_issue_date": "By Issue Date", + // TODO New key - Add a translation + "menu.section.browse_community_by_issue_date": "By Issue Date", + + // "menu.section.browse_community_by_title": "By Title", + // TODO New key - Add a translation + "menu.section.browse_community_by_title": "By Title", + + // "menu.section.browse_global": "All of DSpace", + // TODO New key - Add a translation + "menu.section.browse_global": "All of DSpace", + + // "menu.section.browse_global_by_author": "By Author", + // TODO New key - Add a translation + "menu.section.browse_global_by_author": "By Author", + + // "menu.section.browse_global_by_dateissued": "By Issue Date", + // TODO New key - Add a translation + "menu.section.browse_global_by_dateissued": "By Issue Date", + + // "menu.section.browse_global_by_subject": "By Subject", + // TODO New key - Add a translation + "menu.section.browse_global_by_subject": "By Subject", + + // "menu.section.browse_global_by_title": "By Title", + // TODO New key - Add a translation + "menu.section.browse_global_by_title": "By Title", + + // "menu.section.browse_global_communities_and_collections": "Communities & Collections", + // TODO New key - Add a translation + "menu.section.browse_global_communities_and_collections": "Communities & Collections", + + + + // "menu.section.control_panel": "Control Panel", + // TODO New key - Add a translation + "menu.section.control_panel": "Control Panel", + + // "menu.section.curation_task": "Curation Task", + // TODO New key - Add a translation + "menu.section.curation_task": "Curation Task", + + + + // "menu.section.edit": "Edit", + // TODO New key - Add a translation + "menu.section.edit": "Edit", + + // "menu.section.edit_collection": "Collection", + // TODO New key - Add a translation + "menu.section.edit_collection": "Collection", + + // "menu.section.edit_community": "Community", + // TODO New key - Add a translation + "menu.section.edit_community": "Community", + + // "menu.section.edit_item": "Item", + // TODO New key - Add a translation + "menu.section.edit_item": "Item", + + + + // "menu.section.export": "Export", + // TODO New key - Add a translation + "menu.section.export": "Export", + + // "menu.section.export_collection": "Collection", + // TODO New key - Add a translation + "menu.section.export_collection": "Collection", + + // "menu.section.export_community": "Community", + // TODO New key - Add a translation + "menu.section.export_community": "Community", + + // "menu.section.export_item": "Item", + // TODO New key - Add a translation + "menu.section.export_item": "Item", + + // "menu.section.export_metadata": "Metadata", + // TODO New key - Add a translation + "menu.section.export_metadata": "Metadata", + + + + // "menu.section.find": "Find", + // TODO New key - Add a translation + "menu.section.find": "Find", + + // "menu.section.find_items": "Items", + // TODO New key - Add a translation + "menu.section.find_items": "Items", + + // "menu.section.find_private_items": "Private Items", + // TODO New key - Add a translation + "menu.section.find_private_items": "Private Items", + + // "menu.section.find_withdrawn_items": "Withdrawn Items", + // TODO New key - Add a translation + "menu.section.find_withdrawn_items": "Withdrawn Items", + + + + // "menu.section.icon.access_control": "Access Control menu section", + // TODO New key - Add a translation + "menu.section.icon.access_control": "Access Control menu section", + + // "menu.section.icon.control_panel": "Control Panel menu section", + // TODO New key - Add a translation + "menu.section.icon.control_panel": "Control Panel menu section", + + // "menu.section.icon.curation_task": "Curation Task menu section", + // TODO New key - Add a translation + "menu.section.icon.curation_task": "Curation Task menu section", + + // "menu.section.icon.edit": "Edit menu section", + // TODO New key - Add a translation + "menu.section.icon.edit": "Edit menu section", + + // "menu.section.icon.export": "Export menu section", + // TODO New key - Add a translation + "menu.section.icon.export": "Export menu section", + + // "menu.section.icon.find": "Find menu section", + // TODO New key - Add a translation + "menu.section.icon.find": "Find menu section", + + // "menu.section.icon.import": "Import menu section", + // TODO New key - Add a translation + "menu.section.icon.import": "Import menu section", + + // "menu.section.icon.new": "New menu section", + // TODO New key - Add a translation + "menu.section.icon.new": "New menu section", + + // "menu.section.icon.pin": "Pin sidebar", + // TODO New key - Add a translation + "menu.section.icon.pin": "Pin sidebar", + + // "menu.section.icon.registries": "Registries menu section", + // TODO New key - Add a translation + "menu.section.icon.registries": "Registries menu section", + + // "menu.section.icon.statistics_task": "Statistics Task menu section", + // TODO New key - Add a translation + "menu.section.icon.statistics_task": "Statistics Task menu section", + + // "menu.section.icon.unpin": "Unpin sidebar", + // TODO New key - Add a translation + "menu.section.icon.unpin": "Unpin sidebar", + + + + // "menu.section.import": "Import", + // TODO New key - Add a translation + "menu.section.import": "Import", + + // "menu.section.import_batch": "Batch Import (ZIP)", + // TODO New key - Add a translation + "menu.section.import_batch": "Batch Import (ZIP)", + + // "menu.section.import_metadata": "Metadata", + // TODO New key - Add a translation + "menu.section.import_metadata": "Metadata", + + + + // "menu.section.new": "New", + // TODO New key - Add a translation + "menu.section.new": "New", + + // "menu.section.new_collection": "Collection", + // TODO New key - Add a translation + "menu.section.new_collection": "Collection", + + // "menu.section.new_community": "Community", + // TODO New key - Add a translation + "menu.section.new_community": "Community", + + // "menu.section.new_item": "Item", + // TODO New key - Add a translation + "menu.section.new_item": "Item", + + // "menu.section.new_item_version": "Item Version", + // TODO New key - Add a translation + "menu.section.new_item_version": "Item Version", + + + + // "menu.section.pin": "Pin sidebar", + // TODO New key - Add a translation + "menu.section.pin": "Pin sidebar", + + // "menu.section.unpin": "Unpin sidebar", + // TODO New key - Add a translation + "menu.section.unpin": "Unpin sidebar", + + + + // "menu.section.registries": "Registries", + // TODO New key - Add a translation + "menu.section.registries": "Registries", + + // "menu.section.registries_format": "Format", + // TODO New key - Add a translation + "menu.section.registries_format": "Format", + + // "menu.section.registries_metadata": "Metadata", + // TODO New key - Add a translation + "menu.section.registries_metadata": "Metadata", + + + + // "menu.section.statistics": "Statistics", + // TODO New key - Add a translation + "menu.section.statistics": "Statistics", + + // "menu.section.statistics_task": "Statistics Task", + // TODO New key - Add a translation + "menu.section.statistics_task": "Statistics Task", + + + + // "menu.section.toggle.access_control": "Toggle Access Control section", + // TODO New key - Add a translation + "menu.section.toggle.access_control": "Toggle Access Control section", + + // "menu.section.toggle.control_panel": "Toggle Control Panel section", + // TODO New key - Add a translation + "menu.section.toggle.control_panel": "Toggle Control Panel section", + + // "menu.section.toggle.curation_task": "Toggle Curation Task section", + // TODO New key - Add a translation + "menu.section.toggle.curation_task": "Toggle Curation Task section", + + // "menu.section.toggle.edit": "Toggle Edit section", + // TODO New key - Add a translation + "menu.section.toggle.edit": "Toggle Edit section", + + // "menu.section.toggle.export": "Toggle Export section", + // TODO New key - Add a translation + "menu.section.toggle.export": "Toggle Export section", + + // "menu.section.toggle.find": "Toggle Find section", + // TODO New key - Add a translation + "menu.section.toggle.find": "Toggle Find section", + + // "menu.section.toggle.import": "Toggle Import section", + // TODO New key - Add a translation + "menu.section.toggle.import": "Toggle Import section", + + // "menu.section.toggle.new": "Toggle New section", + // TODO New key - Add a translation + "menu.section.toggle.new": "Toggle New section", + + // "menu.section.toggle.registries": "Toggle Registries section", + // TODO New key - Add a translation + "menu.section.toggle.registries": "Toggle Registries section", + + // "menu.section.toggle.statistics_task": "Toggle Statistics Task section", + // TODO New key - Add a translation + "menu.section.toggle.statistics_task": "Toggle Statistics Task section", + + + + // "mydspace.description": "", + // TODO New key - Add a translation + "mydspace.description": "", + + // "mydspace.general.text-here": "HERE", + // TODO New key - Add a translation + "mydspace.general.text-here": "HERE", + + // "mydspace.messages.controller-help": "Select this option to send a message to item's submitter.", + // TODO New key - Add a translation + "mydspace.messages.controller-help": "Select this option to send a message to item's submitter.", + + // "mydspace.messages.description-placeholder": "Insert your message here...", + // TODO New key - Add a translation + "mydspace.messages.description-placeholder": "Insert your message here...", + + // "mydspace.messages.hide-msg": "Hide message", + // TODO New key - Add a translation + "mydspace.messages.hide-msg": "Hide message", + + // "mydspace.messages.mark-as-read": "Mark as read", + // TODO New key - Add a translation + "mydspace.messages.mark-as-read": "Mark as read", + + // "mydspace.messages.mark-as-unread": "Mark as unread", + // TODO New key - Add a translation + "mydspace.messages.mark-as-unread": "Mark as unread", + + // "mydspace.messages.no-content": "No content.", + // TODO New key - Add a translation + "mydspace.messages.no-content": "No content.", + + // "mydspace.messages.no-messages": "No messages yet.", + // TODO New key - Add a translation + "mydspace.messages.no-messages": "No messages yet.", + + // "mydspace.messages.send-btn": "Send", + // TODO New key - Add a translation + "mydspace.messages.send-btn": "Send", + + // "mydspace.messages.show-msg": "Show message", + // TODO New key - Add a translation + "mydspace.messages.show-msg": "Show message", + + // "mydspace.messages.subject-placeholder": "Subject...", + // TODO New key - Add a translation + "mydspace.messages.subject-placeholder": "Subject...", + + // "mydspace.messages.submitter-help": "Select this option to send a message to controller.", + // TODO New key - Add a translation + "mydspace.messages.submitter-help": "Select this option to send a message to controller.", + + // "mydspace.messages.title": "Messages", + // TODO New key - Add a translation + "mydspace.messages.title": "Messages", + + // "mydspace.messages.to": "To", + // TODO New key - Add a translation + "mydspace.messages.to": "To", + + // "mydspace.new-submission": "New submission", + // TODO New key - Add a translation + "mydspace.new-submission": "New submission", + + // "mydspace.results.head": "Your submissions", + // TODO New key - Add a translation + "mydspace.results.head": "Your submissions", + + // "mydspace.results.no-abstract": "No Abstract", + // TODO New key - Add a translation + "mydspace.results.no-abstract": "No Abstract", + + // "mydspace.results.no-authors": "No Authors", + // TODO New key - Add a translation + "mydspace.results.no-authors": "No Authors", + + // "mydspace.results.no-collections": "No Collections", + // TODO New key - Add a translation + "mydspace.results.no-collections": "No Collections", + + // "mydspace.results.no-date": "No Date", + // TODO New key - Add a translation + "mydspace.results.no-date": "No Date", + + // "mydspace.results.no-files": "No Files", + // TODO New key - Add a translation + "mydspace.results.no-files": "No Files", + + // "mydspace.results.no-results": "There were no items to show", + // TODO New key - Add a translation + "mydspace.results.no-results": "There were no items to show", + + // "mydspace.results.no-title": "No title", + // TODO New key - Add a translation + "mydspace.results.no-title": "No title", + + // "mydspace.results.no-uri": "No Uri", + // TODO New key - Add a translation + "mydspace.results.no-uri": "No Uri", + + // "mydspace.show.workflow": "All tasks", + // TODO New key - Add a translation + "mydspace.show.workflow": "All tasks", + + // "mydspace.show.workspace": "Your Submissions", + // TODO New key - Add a translation + "mydspace.show.workspace": "Your Submissions", + + // "mydspace.status.archived": "Archived", + // TODO New key - Add a translation + "mydspace.status.archived": "Archived", + + // "mydspace.status.validation": "Validation", + // TODO New key - Add a translation + "mydspace.status.validation": "Validation", + + // "mydspace.status.waiting-for-controller": "Waiting for controller", + // TODO New key - Add a translation + "mydspace.status.waiting-for-controller": "Waiting for controller", + + // "mydspace.status.workflow": "Workflow", + // TODO New key - Add a translation + "mydspace.status.workflow": "Workflow", + + // "mydspace.status.workspace": "Workspace", + // TODO New key - Add a translation + "mydspace.status.workspace": "Workspace", + + // "mydspace.title": "MyDSpace", + // TODO New key - Add a translation + "mydspace.title": "MyDSpace", + + // "mydspace.upload.upload-failed": "Error creating new workspace. Please verify the content uploaded before retry.", + // TODO New key - Add a translation + "mydspace.upload.upload-failed": "Error creating new workspace. Please verify the content uploaded before retry.", + + // "mydspace.upload.upload-multiple-successful": "{{qty}} new workspace items created.", + // TODO New key - Add a translation + "mydspace.upload.upload-multiple-successful": "{{qty}} new workspace items created.", + + // "mydspace.upload.upload-successful": "New workspace item created. Click {{here}} for edit it.", + // TODO New key - Add a translation + "mydspace.upload.upload-successful": "New workspace item created. Click {{here}} for edit it.", + + // "mydspace.view-btn": "View", + // TODO New key - Add a translation + "mydspace.view-btn": "View", + + + + // "nav.browse.header": "All of DSpace", + // TODO New key - Add a translation + "nav.browse.header": "All of DSpace", + + // "nav.community-browse.header": "By Community", + // TODO New key - Add a translation + "nav.community-browse.header": "By Community", + + // "nav.language": "Language switch", + // TODO New key - Add a translation + "nav.language": "Language switch", + + // "nav.login": "Log In", "nav.login": "Log In", + + // "nav.logout": "Log Out", "nav.logout": "Log Uit", - + + // "nav.mydspace": "MyDSpace", + // TODO New key - Add a translation + "nav.mydspace": "MyDSpace", + + // "nav.search": "Search", + // TODO New key - Add a translation + "nav.search": "Search", + + // "nav.statistics.header": "Statistics", + // TODO New key - Add a translation + "nav.statistics.header": "Statistics", + + + + // "orgunit.listelement.badge": "Organizational Unit", + // TODO New key - Add a translation + "orgunit.listelement.badge": "Organizational Unit", + + // "orgunit.page.city": "City", + // TODO New key - Add a translation + "orgunit.page.city": "City", + + // "orgunit.page.country": "Country", + // TODO New key - Add a translation + "orgunit.page.country": "Country", + + // "orgunit.page.dateestablished": "Date established", + // TODO New key - Add a translation + "orgunit.page.dateestablished": "Date established", + + // "orgunit.page.description": "Description", + // TODO New key - Add a translation + "orgunit.page.description": "Description", + + // "orgunit.page.id": "ID", + // TODO New key - Add a translation + "orgunit.page.id": "ID", + + // "orgunit.page.titleprefix": "Organizational Unit: ", + // TODO New key - Add a translation + "orgunit.page.titleprefix": "Organizational Unit: ", + + + + // "pagination.results-per-page": "Results Per Page", "pagination.results-per-page": "Resultaten per pagina", + + // "pagination.showing.detail": "{{ range }} of {{ total }}", "pagination.showing.detail": "{{ range }} van {{ total }}", + + // "pagination.showing.label": "Now showing ", "pagination.showing.label": "Resultaten ", + + // "pagination.sort-direction": "Sort Options", "pagination.sort-direction": "Sorteermogelijkheden", - + + + + // "person.listelement.badge": "Person", + // TODO New key - Add a translation + "person.listelement.badge": "Person", + + // "person.page.birthdate": "Birth Date", + // TODO New key - Add a translation + "person.page.birthdate": "Birth Date", + + // "person.page.email": "Email Address", + // TODO New key - Add a translation + "person.page.email": "Email Address", + + // "person.page.firstname": "First Name", + // TODO New key - Add a translation + "person.page.firstname": "First Name", + + // "person.page.jobtitle": "Job Title", + // TODO New key - Add a translation + "person.page.jobtitle": "Job Title", + + // "person.page.lastname": "Last Name", + // TODO New key - Add a translation + "person.page.lastname": "Last Name", + + // "person.page.link.full": "Show all metadata", + // TODO New key - Add a translation + "person.page.link.full": "Show all metadata", + + // "person.page.orcid": "ORCID", + // TODO New key - Add a translation + "person.page.orcid": "ORCID", + + // "person.page.staffid": "Staff ID", + // TODO New key - Add a translation + "person.page.staffid": "Staff ID", + + // "person.page.titleprefix": "Person: ", + // TODO New key - Add a translation + "person.page.titleprefix": "Person: ", + + // "person.search.results.head": "Person Search Results", + // TODO New key - Add a translation + "person.search.results.head": "Person Search Results", + + // "person.search.title": "DSpace Angular :: Person Search", + // TODO New key - Add a translation + "person.search.title": "DSpace Angular :: Person Search", + + + + // "project.listelement.badge": "Research Project", + // TODO New key - Add a translation + "project.listelement.badge": "Research Project", + + // "project.page.contributor": "Contributors", + // TODO New key - Add a translation + "project.page.contributor": "Contributors", + + // "project.page.description": "Description", + // TODO New key - Add a translation + "project.page.description": "Description", + + // "project.page.expectedcompletion": "Expected Completion", + // TODO New key - Add a translation + "project.page.expectedcompletion": "Expected Completion", + + // "project.page.funder": "Funders", + // TODO New key - Add a translation + "project.page.funder": "Funders", + + // "project.page.id": "ID", + // TODO New key - Add a translation + "project.page.id": "ID", + + // "project.page.keyword": "Keywords", + // TODO New key - Add a translation + "project.page.keyword": "Keywords", + + // "project.page.status": "Status", + // TODO New key - Add a translation + "project.page.status": "Status", + + // "project.page.titleprefix": "Research Project: ", + // TODO New key - Add a translation + "project.page.titleprefix": "Research Project: ", + + + + // "publication.listelement.badge": "Publication", + // TODO New key - Add a translation + "publication.listelement.badge": "Publication", + + // "publication.page.description": "Description", + // TODO New key - Add a translation + "publication.page.description": "Description", + + // "publication.page.journal-issn": "Journal ISSN", + // TODO New key - Add a translation + "publication.page.journal-issn": "Journal ISSN", + + // "publication.page.journal-title": "Journal Title", + // TODO New key - Add a translation + "publication.page.journal-title": "Journal Title", + + // "publication.page.publisher": "Publisher", + // TODO New key - Add a translation + "publication.page.publisher": "Publisher", + + // "publication.page.titleprefix": "Publication: ", + // TODO New key - Add a translation + "publication.page.titleprefix": "Publication: ", + + // "publication.page.volume-title": "Volume Title", + // TODO New key - Add a translation + "publication.page.volume-title": "Volume Title", + + // "publication.search.results.head": "Publication Search Results", + // TODO New key - Add a translation + "publication.search.results.head": "Publication Search Results", + + // "publication.search.title": "DSpace Angular :: Publication Search", + // TODO New key - Add a translation + "publication.search.title": "DSpace Angular :: Publication Search", + + + + // "relationships.isAuthorOf": "Authors", + // TODO New key - Add a translation + "relationships.isAuthorOf": "Authors", + + // "relationships.isIssueOf": "Journal Issues", + // TODO New key - Add a translation + "relationships.isIssueOf": "Journal Issues", + + // "relationships.isJournalIssueOf": "Journal Issue", + // TODO New key - Add a translation + "relationships.isJournalIssueOf": "Journal Issue", + + // "relationships.isJournalOf": "Journals", + // TODO New key - Add a translation + "relationships.isJournalOf": "Journals", + + // "relationships.isOrgUnitOf": "Organizational Units", + // TODO New key - Add a translation + "relationships.isOrgUnitOf": "Organizational Units", + + // "relationships.isPersonOf": "Authors", + // TODO New key - Add a translation + "relationships.isPersonOf": "Authors", + + // "relationships.isProjectOf": "Research Projects", + // TODO New key - Add a translation + "relationships.isProjectOf": "Research Projects", + + // "relationships.isPublicationOf": "Publications", + // TODO New key - Add a translation + "relationships.isPublicationOf": "Publications", + + // "relationships.isPublicationOfJournalIssue": "Articles", + // TODO New key - Add a translation + "relationships.isPublicationOfJournalIssue": "Articles", + + // "relationships.isSingleJournalOf": "Journal", + // TODO New key - Add a translation + "relationships.isSingleJournalOf": "Journal", + + // "relationships.isSingleVolumeOf": "Journal Volume", + // TODO New key - Add a translation + "relationships.isSingleVolumeOf": "Journal Volume", + + // "relationships.isVolumeOf": "Journal Volumes", + // TODO New key - Add a translation + "relationships.isVolumeOf": "Journal Volumes", + + + + // "search.description": "", "search.description": "", + + // "search.switch-configuration.title": "Show", + // TODO New key - Add a translation + "search.switch-configuration.title": "Show", + + // "search.title": "DSpace Angular :: Search", "search.title": "DSpace Angular :: Zoek", - + + + + // "search.filters.applied.f.author": "Author", "search.filters.applied.f.author": "Auteur", + + // "search.filters.applied.f.dateIssued.max": "End date", "search.filters.applied.f.dateIssued.max": "Einddatum", + + // "search.filters.applied.f.dateIssued.min": "Start date", "search.filters.applied.f.dateIssued.min": "Startdatum", + + // "search.filters.applied.f.dateSubmitted": "Date submitted", + // TODO New key - Add a translation + "search.filters.applied.f.dateSubmitted": "Date submitted", + + // "search.filters.applied.f.entityType": "Item Type", + // TODO New key - Add a translation + "search.filters.applied.f.entityType": "Item Type", + + // "search.filters.applied.f.has_content_in_original_bundle": "Has files", "search.filters.applied.f.has_content_in_original_bundle": "Heeft bestanden", + + // "search.filters.applied.f.itemtype": "Type", + // TODO New key - Add a translation + "search.filters.applied.f.itemtype": "Type", + + // "search.filters.applied.f.namedresourcetype": "Status", + // TODO New key - Add a translation + "search.filters.applied.f.namedresourcetype": "Status", + + // "search.filters.applied.f.subject": "Subject", "search.filters.applied.f.subject": "Sleutelwoord", + + // "search.filters.applied.f.submitter": "Submitter", + // TODO New key - Add a translation + "search.filters.applied.f.submitter": "Submitter", + + + + // "search.filters.filter.author.head": "Author", "search.filters.filter.author.head": "Auteur", + + // "search.filters.filter.author.placeholder": "Author name", "search.filters.filter.author.placeholder": "Auteursnaam", + + // "search.filters.filter.birthDate.head": "Birth Date", + // TODO New key - Add a translation + "search.filters.filter.birthDate.head": "Birth Date", + + // "search.filters.filter.birthDate.placeholder": "Birth Date", + // TODO New key - Add a translation + "search.filters.filter.birthDate.placeholder": "Birth Date", + + // "search.filters.filter.creativeDatePublished.head": "Date Published", + // TODO New key - Add a translation + "search.filters.filter.creativeDatePublished.head": "Date Published", + + // "search.filters.filter.creativeDatePublished.placeholder": "Date Published", + // TODO New key - Add a translation + "search.filters.filter.creativeDatePublished.placeholder": "Date Published", + + // "search.filters.filter.creativeWorkEditor.head": "Editor", + // TODO New key - Add a translation + "search.filters.filter.creativeWorkEditor.head": "Editor", + + // "search.filters.filter.creativeWorkEditor.placeholder": "Editor", + // TODO New key - Add a translation + "search.filters.filter.creativeWorkEditor.placeholder": "Editor", + + // "search.filters.filter.creativeWorkKeywords.head": "Subject", + // TODO New key - Add a translation + "search.filters.filter.creativeWorkKeywords.head": "Subject", + + // "search.filters.filter.creativeWorkKeywords.placeholder": "Subject", + // TODO New key - Add a translation + "search.filters.filter.creativeWorkKeywords.placeholder": "Subject", + + // "search.filters.filter.creativeWorkPublisher.head": "Publisher", + // TODO New key - Add a translation + "search.filters.filter.creativeWorkPublisher.head": "Publisher", + + // "search.filters.filter.creativeWorkPublisher.placeholder": "Publisher", + // TODO New key - Add a translation + "search.filters.filter.creativeWorkPublisher.placeholder": "Publisher", + + // "search.filters.filter.dateIssued.head": "Date", "search.filters.filter.dateIssued.head": "Datum", + + // "search.filters.filter.dateIssued.max.placeholder": "Minimum Date", "search.filters.filter.dateIssued.max.placeholder": "Vroegste Datum", + + // "search.filters.filter.dateIssued.min.placeholder": "Maximum Date", "search.filters.filter.dateIssued.min.placeholder": "Laatste Datum", + + // "search.filters.filter.dateSubmitted.head": "Date submitted", + // TODO New key - Add a translation + "search.filters.filter.dateSubmitted.head": "Date submitted", + + // "search.filters.filter.dateSubmitted.placeholder": "Date submitted", + // TODO New key - Add a translation + "search.filters.filter.dateSubmitted.placeholder": "Date submitted", + + // "search.filters.filter.entityType.head": "Item Type", + // TODO New key - Add a translation + "search.filters.filter.entityType.head": "Item Type", + + // "search.filters.filter.entityType.placeholder": "Item Type", + // TODO New key - Add a translation + "search.filters.filter.entityType.placeholder": "Item Type", + + // "search.filters.filter.has_content_in_original_bundle.head": "Has files", "search.filters.filter.has_content_in_original_bundle.head": "Heeft bestanden", + + // "search.filters.filter.itemtype.head": "Type", + // TODO New key - Add a translation + "search.filters.filter.itemtype.head": "Type", + + // "search.filters.filter.itemtype.placeholder": "Type", + // TODO New key - Add a translation + "search.filters.filter.itemtype.placeholder": "Type", + + // "search.filters.filter.jobTitle.head": "Job Title", + // TODO New key - Add a translation + "search.filters.filter.jobTitle.head": "Job Title", + + // "search.filters.filter.jobTitle.placeholder": "Job Title", + // TODO New key - Add a translation + "search.filters.filter.jobTitle.placeholder": "Job Title", + + // "search.filters.filter.knowsLanguage.head": "Known language", + // TODO New key - Add a translation + "search.filters.filter.knowsLanguage.head": "Known language", + + // "search.filters.filter.knowsLanguage.placeholder": "Known language", + // TODO New key - Add a translation + "search.filters.filter.knowsLanguage.placeholder": "Known language", + + // "search.filters.filter.namedresourcetype.head": "Status", + // TODO New key - Add a translation + "search.filters.filter.namedresourcetype.head": "Status", + + // "search.filters.filter.namedresourcetype.placeholder": "Status", + // TODO New key - Add a translation + "search.filters.filter.namedresourcetype.placeholder": "Status", + + // "search.filters.filter.objectpeople.head": "People", + // TODO New key - Add a translation + "search.filters.filter.objectpeople.head": "People", + + // "search.filters.filter.objectpeople.placeholder": "People", + // TODO New key - Add a translation + "search.filters.filter.objectpeople.placeholder": "People", + + // "search.filters.filter.organizationAddressCountry.head": "Country", + // TODO New key - Add a translation + "search.filters.filter.organizationAddressCountry.head": "Country", + + // "search.filters.filter.organizationAddressCountry.placeholder": "Country", + // TODO New key - Add a translation + "search.filters.filter.organizationAddressCountry.placeholder": "Country", + + // "search.filters.filter.organizationAddressLocality.head": "City", + // TODO New key - Add a translation + "search.filters.filter.organizationAddressLocality.head": "City", + + // "search.filters.filter.organizationAddressLocality.placeholder": "City", + // TODO New key - Add a translation + "search.filters.filter.organizationAddressLocality.placeholder": "City", + + // "search.filters.filter.organizationFoundingDate.head": "Date Founded", + // TODO New key - Add a translation + "search.filters.filter.organizationFoundingDate.head": "Date Founded", + + // "search.filters.filter.organizationFoundingDate.placeholder": "Date Founded", + // TODO New key - Add a translation + "search.filters.filter.organizationFoundingDate.placeholder": "Date Founded", + + // "search.filters.filter.scope.head": "Scope", "search.filters.filter.scope.head": "Bereik", + + // "search.filters.filter.scope.placeholder": "Scope filter", "search.filters.filter.scope.placeholder": "Bereikfilter", + + // "search.filters.filter.show-less": "Collapse", "search.filters.filter.show-less": "Inklappen", + + // "search.filters.filter.show-more": "Show more", "search.filters.filter.show-more": "Toon meer", + + // "search.filters.filter.subject.head": "Subject", "search.filters.filter.subject.head": "Onderwerp", + + // "search.filters.filter.subject.placeholder": "Subject", "search.filters.filter.subject.placeholder": "Onderwerp", - + + // "search.filters.filter.submitter.head": "Submitter", + // TODO New key - Add a translation + "search.filters.filter.submitter.head": "Submitter", + + // "search.filters.filter.submitter.placeholder": "Submitter", + // TODO New key - Add a translation + "search.filters.filter.submitter.placeholder": "Submitter", + + + + // "search.filters.head": "Filters", "search.filters.head": "Filters", + + // "search.filters.reset": "Reset filters", "search.filters.reset": "Filters verwijderen", - + + + + // "search.form.search": "Search", "search.form.search": "Zoek", + + // "search.form.search_dspace": "Search DSpace", "search.form.search_dspace": "Zoek in DSpace", - + + // "search.form.search_mydspace": "Search MyDSpace", + // TODO New key - Add a translation + "search.form.search_mydspace": "Search MyDSpace", + + + + // "search.results.head": "Search Results", "search.results.head": "Zoekresultaten", + + // "search.results.no-results": "Your search returned no results. Having trouble finding what you're looking for? Try putting", "search.results.no-results": "Er waren geen resultaten voor deze zoekopdracht", - + + // "search.results.no-results-link": "quotes around it", + // TODO New key - Add a translation + "search.results.no-results-link": "quotes around it", + + + + // "search.sidebar.close": "Back to results", "search.sidebar.close": "Terug naar de resultaten", + + // "search.sidebar.filters.title": "Filters", "search.sidebar.filters.title": "Filters", + + // "search.sidebar.open": "Search Tools", "search.sidebar.open": "Zoek Tools", + + // "search.sidebar.results": "results", "search.sidebar.results": "resultaten", + + // "search.sidebar.settings.rpp": "Results per page", "search.sidebar.settings.rpp": "Resultaten per pagina", + + // "search.sidebar.settings.sort-by": "Sort By", "search.sidebar.settings.sort-by": "Sorteer volgens", + + // "search.sidebar.settings.title": "Settings", "search.sidebar.settings.title": "Instellingen", - + + + + // "search.view-switch.show-detail": "Show detail", + // TODO New key - Add a translation + "search.view-switch.show-detail": "Show detail", + + // "search.view-switch.show-grid": "Show as grid", "search.view-switch.show-grid": "Toon in raster", + + // "search.view-switch.show-list": "Show as list", "search.view-switch.show-list": "Toon als lijst", - + + + + // "sorting.dc.title.ASC": "Title Ascending", "sorting.dc.title.ASC": "Oplopend op titel", + + // "sorting.dc.title.DESC": "Title Descending", "sorting.dc.title.DESC": "Aflopend op titel", + + // "sorting.score.DESC": "Relevance", "sorting.score.DESC": "Relevantie", - + + + + // "submission.edit.title": "Edit Submission", + // TODO New key - Add a translation + "submission.edit.title": "Edit Submission", + + // "submission.general.cannot_submit": "You have not the privilege to make a new submission.", + // TODO New key - Add a translation + "submission.general.cannot_submit": "You have not the privilege to make a new submission.", + + // "submission.general.deposit": "Deposit", + // TODO New key - Add a translation + "submission.general.deposit": "Deposit", + + // "submission.general.discard.confirm.cancel": "Cancel", + // TODO New key - Add a translation + "submission.general.discard.confirm.cancel": "Cancel", + + // "submission.general.discard.confirm.info": "This operation can't be undone. Are you sure?", + // TODO New key - Add a translation + "submission.general.discard.confirm.info": "This operation can't be undone. Are you sure?", + + // "submission.general.discard.confirm.submit": "Yes, I'm sure", + // TODO New key - Add a translation + "submission.general.discard.confirm.submit": "Yes, I'm sure", + + // "submission.general.discard.confirm.title": "Discard submission", + // TODO New key - Add a translation + "submission.general.discard.confirm.title": "Discard submission", + + // "submission.general.discard.submit": "Discard", + // TODO New key - Add a translation + "submission.general.discard.submit": "Discard", + + // "submission.general.save": "Save", + // TODO New key - Add a translation + "submission.general.save": "Save", + + // "submission.general.save-later": "Save for later", + // TODO New key - Add a translation + "submission.general.save-later": "Save for later", + + + + // "submission.sections.general.add-more": "Add more", + // TODO New key - Add a translation + "submission.sections.general.add-more": "Add more", + + // "submission.sections.general.collection": "Collection", + // TODO New key - Add a translation + "submission.sections.general.collection": "Collection", + + // "submission.sections.general.deposit_error_notice": "There was an issue when submitting the item, please try again later.", + // TODO New key - Add a translation + "submission.sections.general.deposit_error_notice": "There was an issue when submitting the item, please try again later.", + + // "submission.sections.general.deposit_success_notice": "Submission deposited successfully.", + // TODO New key - Add a translation + "submission.sections.general.deposit_success_notice": "Submission deposited successfully.", + + // "submission.sections.general.discard_error_notice": "There was an issue when discarding the item, please try again later.", + // TODO New key - Add a translation + "submission.sections.general.discard_error_notice": "There was an issue when discarding the item, please try again later.", + + // "submission.sections.general.discard_success_notice": "Submission discarded successfully.", + // TODO New key - Add a translation + "submission.sections.general.discard_success_notice": "Submission discarded successfully.", + + // "submission.sections.general.metadata-extracted": "New metadata have been extracted and added to the {{sectionId}} section.", + // TODO New key - Add a translation + "submission.sections.general.metadata-extracted": "New metadata have been extracted and added to the {{sectionId}} section.", + + // "submission.sections.general.metadata-extracted-new-section": "New {{sectionId}} section has been added to submission.", + // TODO New key - Add a translation + "submission.sections.general.metadata-extracted-new-section": "New {{sectionId}} section has been added to submission.", + + // "submission.sections.general.no-collection": "No collection found", + // TODO New key - Add a translation + "submission.sections.general.no-collection": "No collection found", + + // "submission.sections.general.no-sections": "No options available", + // TODO New key - Add a translation + "submission.sections.general.no-sections": "No options available", + + // "submission.sections.general.save_error_notice": "There was an issue when saving the item, please try again later.", + // TODO New key - Add a translation + "submission.sections.general.save_error_notice": "There was an issue when saving the item, please try again later.", + + // "submission.sections.general.save_success_notice": "Submission saved successfully.", + // TODO New key - Add a translation + "submission.sections.general.save_success_notice": "Submission saved successfully.", + + // "submission.sections.general.search-collection": "Search for a collection", + // TODO New key - Add a translation + "submission.sections.general.search-collection": "Search for a collection", + + // "submission.sections.general.sections_not_valid": "There are incomplete sections.", + // TODO New key - Add a translation + "submission.sections.general.sections_not_valid": "There are incomplete sections.", + + + + // "submission.sections.submit.progressbar.cclicense": "Creative commons license", + // TODO New key - Add a translation + "submission.sections.submit.progressbar.cclicense": "Creative commons license", + + // "submission.sections.submit.progressbar.describe.recycle": "Recycle", + // TODO New key - Add a translation + "submission.sections.submit.progressbar.describe.recycle": "Recycle", + + // "submission.sections.submit.progressbar.describe.stepcustom": "Describe", + // TODO New key - Add a translation + "submission.sections.submit.progressbar.describe.stepcustom": "Describe", + + // "submission.sections.submit.progressbar.describe.stepone": "Describe", + // TODO New key - Add a translation + "submission.sections.submit.progressbar.describe.stepone": "Describe", + + // "submission.sections.submit.progressbar.describe.steptwo": "Describe", + // TODO New key - Add a translation + "submission.sections.submit.progressbar.describe.steptwo": "Describe", + + // "submission.sections.submit.progressbar.detect-duplicate": "Potential duplicates", + // TODO New key - Add a translation + "submission.sections.submit.progressbar.detect-duplicate": "Potential duplicates", + + // "submission.sections.submit.progressbar.license": "Deposit license", + // TODO New key - Add a translation + "submission.sections.submit.progressbar.license": "Deposit license", + + // "submission.sections.submit.progressbar.upload": "Upload files", + // TODO New key - Add a translation + "submission.sections.submit.progressbar.upload": "Upload files", + + + + // "submission.sections.upload.delete.confirm.cancel": "Cancel", + // TODO New key - Add a translation + "submission.sections.upload.delete.confirm.cancel": "Cancel", + + // "submission.sections.upload.delete.confirm.info": "This operation can't be undone. Are you sure?", + // TODO New key - Add a translation + "submission.sections.upload.delete.confirm.info": "This operation can't be undone. Are you sure?", + + // "submission.sections.upload.delete.confirm.submit": "Yes, I'm sure", + // TODO New key - Add a translation + "submission.sections.upload.delete.confirm.submit": "Yes, I'm sure", + + // "submission.sections.upload.delete.confirm.title": "Delete bitstream", + // TODO New key - Add a translation + "submission.sections.upload.delete.confirm.title": "Delete bitstream", + + // "submission.sections.upload.delete.submit": "Delete", + // TODO New key - Add a translation + "submission.sections.upload.delete.submit": "Delete", + + // "submission.sections.upload.drop-message": "Drop files to attach them to the item", + // TODO New key - Add a translation + "submission.sections.upload.drop-message": "Drop files to attach them to the item", + + // "submission.sections.upload.form.access-condition-label": "Access condition type", + // TODO New key - Add a translation + "submission.sections.upload.form.access-condition-label": "Access condition type", + + // "submission.sections.upload.form.date-required": "Date is required.", + // TODO New key - Add a translation + "submission.sections.upload.form.date-required": "Date is required.", + + // "submission.sections.upload.form.from-label": "Access grant from", + // TODO New key - Add a translation + "submission.sections.upload.form.from-label": "Access grant from", + + // "submission.sections.upload.form.from-placeholder": "From", + // TODO New key - Add a translation + "submission.sections.upload.form.from-placeholder": "From", + + // "submission.sections.upload.form.group-label": "Group", + // TODO New key - Add a translation + "submission.sections.upload.form.group-label": "Group", + + // "submission.sections.upload.form.group-required": "Group is required.", + // TODO New key - Add a translation + "submission.sections.upload.form.group-required": "Group is required.", + + // "submission.sections.upload.form.until-label": "Access grant until", + // TODO New key - Add a translation + "submission.sections.upload.form.until-label": "Access grant until", + + // "submission.sections.upload.form.until-placeholder": "Until", + // TODO New key - Add a translation + "submission.sections.upload.form.until-placeholder": "Until", + + // "submission.sections.upload.header.policy.default.nolist": "Uploaded files in the {{collectionName}} collection will be accessible according to the following group(s):", + // TODO New key - Add a translation + "submission.sections.upload.header.policy.default.nolist": "Uploaded files in the {{collectionName}} collection will be accessible according to the following group(s):", + + // "submission.sections.upload.header.policy.default.withlist": "Please note that uploaded files in the {{collectionName}} collection will be accessible, in addition to what is explicitly decided for the single file, with the following group(s):", + // TODO New key - Add a translation + "submission.sections.upload.header.policy.default.withlist": "Please note that uploaded files in the {{collectionName}} collection will be accessible, in addition to what is explicitly decided for the single file, with the following group(s):", + + // "submission.sections.upload.info": "Here you will find all the files currently in the item. You can update the fle metadata and access conditions or upload additional files just dragging & dropping them everywhere in the page", + // TODO New key - Add a translation + "submission.sections.upload.info": "Here you will find all the files currently in the item. You can update the fle metadata and access conditions or upload additional files just dragging & dropping them everywhere in the page", + + // "submission.sections.upload.no-entry": "No", + // TODO New key - Add a translation + "submission.sections.upload.no-entry": "No", + + // "submission.sections.upload.no-file-uploaded": "No file uploaded yet.", + // TODO New key - Add a translation + "submission.sections.upload.no-file-uploaded": "No file uploaded yet.", + + // "submission.sections.upload.save-metadata": "Save metadata", + // TODO New key - Add a translation + "submission.sections.upload.save-metadata": "Save metadata", + + // "submission.sections.upload.undo": "Cancel", + // TODO New key - Add a translation + "submission.sections.upload.undo": "Cancel", + + // "submission.sections.upload.upload-failed": "Upload failed", + // TODO New key - Add a translation + "submission.sections.upload.upload-failed": "Upload failed", + + // "submission.sections.upload.upload-successful": "Upload successful", + // TODO New key - Add a translation + "submission.sections.upload.upload-successful": "Upload successful", + + + + // "submission.submit.title": "Submission", + // TODO New key - Add a translation + "submission.submit.title": "Submission", + + + + // "submission.workflow.generic.delete": "Delete", + // TODO New key - Add a translation + "submission.workflow.generic.delete": "Delete", + + // "submission.workflow.generic.delete-help": "If you would to discard this item, select \"Delete\". You will then be asked to confirm it.", + // TODO New key - Add a translation + "submission.workflow.generic.delete-help": "If you would to discard this item, select \"Delete\". You will then be asked to confirm it.", + + // "submission.workflow.generic.edit": "Edit", + // TODO New key - Add a translation + "submission.workflow.generic.edit": "Edit", + + // "submission.workflow.generic.edit-help": "Select this option to change the item's metadata.", + // TODO New key - Add a translation + "submission.workflow.generic.edit-help": "Select this option to change the item's metadata.", + + // "submission.workflow.generic.view": "View", + // TODO New key - Add a translation + "submission.workflow.generic.view": "View", + + // "submission.workflow.generic.view-help": "Select this option to view the item's metadata.", + // TODO New key - Add a translation + "submission.workflow.generic.view-help": "Select this option to view the item's metadata.", + + + + // "submission.workflow.tasks.claimed.approve": "Approve", + // TODO New key - Add a translation + "submission.workflow.tasks.claimed.approve": "Approve", + + // "submission.workflow.tasks.claimed.approve_help": "If you have reviewed the item and it is suitable for inclusion in the collection, select \"Approve\".", + // TODO New key - Add a translation + "submission.workflow.tasks.claimed.approve_help": "If you have reviewed the item and it is suitable for inclusion in the collection, select \"Approve\".", + + // "submission.workflow.tasks.claimed.edit": "Edit", + // TODO New key - Add a translation + "submission.workflow.tasks.claimed.edit": "Edit", + + // "submission.workflow.tasks.claimed.edit_help": "Select this option to change the item's metadata.", + // TODO New key - Add a translation + "submission.workflow.tasks.claimed.edit_help": "Select this option to change the item's metadata.", + + // "submission.workflow.tasks.claimed.reject.reason.info": "Please enter your reason for rejecting the submission into the box below, indicating whether the submitter may fix a problem and resubmit.", + // TODO New key - Add a translation + "submission.workflow.tasks.claimed.reject.reason.info": "Please enter your reason for rejecting the submission into the box below, indicating whether the submitter may fix a problem and resubmit.", + + // "submission.workflow.tasks.claimed.reject.reason.placeholder": "Describe the reason of reject", + // TODO New key - Add a translation + "submission.workflow.tasks.claimed.reject.reason.placeholder": "Describe the reason of reject", + + // "submission.workflow.tasks.claimed.reject.reason.submit": "Reject item", + // TODO New key - Add a translation + "submission.workflow.tasks.claimed.reject.reason.submit": "Reject item", + + // "submission.workflow.tasks.claimed.reject.reason.title": "Reason", + // TODO New key - Add a translation + "submission.workflow.tasks.claimed.reject.reason.title": "Reason", + + // "submission.workflow.tasks.claimed.reject.submit": "Reject", + // TODO New key - Add a translation + "submission.workflow.tasks.claimed.reject.submit": "Reject", + + // "submission.workflow.tasks.claimed.reject_help": "If you have reviewed the item and found it is not suitable for inclusion in the collection, select \"Reject\". You will then be asked to enter a message indicating why the item is unsuitable, and whether the submitter should change something and resubmit.", + // TODO New key - Add a translation + "submission.workflow.tasks.claimed.reject_help": "If you have reviewed the item and found it is not suitable for inclusion in the collection, select \"Reject\". You will then be asked to enter a message indicating why the item is unsuitable, and whether the submitter should change something and resubmit.", + + // "submission.workflow.tasks.claimed.return": "Return to pool", + // TODO New key - Add a translation + "submission.workflow.tasks.claimed.return": "Return to pool", + + // "submission.workflow.tasks.claimed.return_help": "Return the task to the pool so that another user may perform the task.", + // TODO New key - Add a translation + "submission.workflow.tasks.claimed.return_help": "Return the task to the pool so that another user may perform the task.", + + + + // "submission.workflow.tasks.generic.error": "Error occurred during operation...", + // TODO New key - Add a translation + "submission.workflow.tasks.generic.error": "Error occurred during operation...", + + // "submission.workflow.tasks.generic.processing": "Processing...", + // TODO New key - Add a translation + "submission.workflow.tasks.generic.processing": "Processing...", + + // "submission.workflow.tasks.generic.submitter": "Submitter", + // TODO New key - Add a translation + "submission.workflow.tasks.generic.submitter": "Submitter", + + // "submission.workflow.tasks.generic.success": "Operation successful", + // TODO New key - Add a translation + "submission.workflow.tasks.generic.success": "Operation successful", + + + + // "submission.workflow.tasks.pool.claim": "Claim", + // TODO New key - Add a translation + "submission.workflow.tasks.pool.claim": "Claim", + + // "submission.workflow.tasks.pool.claim_help": "Assign this task to yourself.", + // TODO New key - Add a translation + "submission.workflow.tasks.pool.claim_help": "Assign this task to yourself.", + + // "submission.workflow.tasks.pool.hide-detail": "Hide detail", + // TODO New key - Add a translation + "submission.workflow.tasks.pool.hide-detail": "Hide detail", + + // "submission.workflow.tasks.pool.show-detail": "Show detail", + // TODO New key - Add a translation + "submission.workflow.tasks.pool.show-detail": "Show detail", + + + + // "title": "DSpace", "title": "DSpace", -} + + + + // "uploader.browse": "browse", + // TODO New key - Add a translation + "uploader.browse": "browse", + + // "uploader.drag-message": "Drag & Drop your files here", + // TODO New key - Add a translation + "uploader.drag-message": "Drag & Drop your files here", + + // "uploader.or": ", or", + // TODO New key - Add a translation + "uploader.or": ", or", + + // "uploader.processing": "Processing", + // TODO New key - Add a translation + "uploader.processing": "Processing", + + // "uploader.queue-length": "Queue length", + // TODO New key - Add a translation + "uploader.queue-length": "Queue length", + + + + +} \ No newline at end of file diff --git a/scripts/sync-i18n-files.js b/scripts/sync-i18n-files.js new file mode 100755 index 0000000000..b1e8062a67 --- /dev/null +++ b/scripts/sync-i18n-files.js @@ -0,0 +1,342 @@ +#!/usr/bin/env node +const commander = require('commander'); +const fs = require('fs'); +const JSON5 = require('json5'); +const _cliProgress = require('cli-progress'); +const _ = require('lodash'); +const {projectRoot} = require('../webpack/helpers'); + +const program = new commander.Command(); +program.version('1.0.0', '-v, --version'); + +const NEW_MESSAGE_TODO = '// TODO New key - Add a translation'; +const MESSAGE_CHANGED_TODO = '// TODO Source message changed - Revise the translation'; +const COMMENTS_CHANGED_TODO = '// TODO Source comments changed - Revise the translation'; + +const DEFAULT_SOURCE_FILE_LOCATION = 'resources/i18n/en.json5'; +const LANGUAGE_FILES_LOCATION = 'resources/i18n'; + +parseCliInput(); + +/** + * Parses the CLI input given by the user + * If no parameters are set (standard usage) -> source file is default (set to DEFAULT_SOURCE_FILE_LOCATION) and all + * other language files in the LANGUAGE_FILES_LOCATION are synced with this one in-place + * (replaced with newly synced file) + * If only target-file -t is set -> either -i in-place or -o output-file must be set + * Source file can be set with -s if it should be something else than DEFAULT_SOURCE_FILE_LOCATION + * + * If any of the paths to files/dirs given by user are not valid, an error message is printed and script gets aborted + */ +function parseCliInput() { + program + .option('-d, --output-dir ', 'output dir when running script on all language files; mutually exclusive with -o') + .option('-t, --target-file ', 'target file we compare with and where completed output ends up if -o is not configured and -i is') + .option('-i, --edit-in-place', 'edit-in-place; store output straight in target file; mutually exclusive with -o') + .option('-s, --source-file ', 'source file to be parsed for translation', projectRoot(DEFAULT_SOURCE_FILE_LOCATION)) + .option('-o, --output-file ', 'where output of script ends up; mutually exclusive with -i') + .usage('([-d ] [-s ]) || (-t (-i | -o ) [-s ])') + .parse(process.argv); + + if (!program.targetFile) { + fs.readdirSync(projectRoot(LANGUAGE_FILES_LOCATION)).forEach(file => { + if (!program.sourceFile.toString().endsWith(file)) { + const targetFileLocation = projectRoot(LANGUAGE_FILES_LOCATION + "/" + file); + console.log('Syncing file at: ' + targetFileLocation + ' with source file at: ' + program.sourceFile); + if (program.outputDir) { + if (!fs.existsSync(program.outputDir)) { + fs.mkdirSync(program.outputDir); + } + const outputFileLocation = program.outputDir + "/" + file; + console.log('Output location: ' + outputFileLocation); + syncFileWithSource(targetFileLocation, outputFileLocation); + } else { + console.log('Replacing in target location'); + syncFileWithSource(targetFileLocation, targetFileLocation); + } + } + }); + } else { + if (program.targetFile && !checkIfPathToFileIsValid(program.targetFile)) { + console.error('Directory path of target file is not valid.'); + console.log(program.outputHelp()); + process.exit(1); + } + if (program.targetFile && checkIfFileExists(program.targetFile) && !(program.editInPlace || program.outputFile)) { + console.error('This target file already exists, if you want to overwrite this add option -i, or add an -o output location'); + console.log(program.outputHelp()); + process.exit(1); + } + if (!checkIfFileExists(program.sourceFile)) { + console.error('Path of source file is not valid.'); + console.log(program.outputHelp()); + process.exit(1); + } + if (program.outputFile && !checkIfPathToFileIsValid(program.outputFile)) { + console.error('Directory path of output file is not valid.'); + console.log(program.outputHelp()); + process.exit(1); + } + + syncFileWithSource(program.targetFile, getOutputFileLocationIfExistsElseTargetFileLocation(program.targetFile)); + } +} + +/** + * Creates chunk lists for both the source and the target files (for example en.json5 and nl.json5 respectively) + * > Creates output chunks by comparing the source chunk with corresponding target chunk (based on key of translation) + * > Writes the output chunks to a new valid lang.json5 file, either replacing the target file (-i in-place) + * or sending it to an output file specified by the user + * @param pathToTargetFile Valid path to target file to generate target chunks from + * @param pathToOutputFile Valid path to output file to write output chunks to + */ +function syncFileWithSource(pathToTargetFile, pathToOutputFile) { + const progressBar = new _cliProgress.SingleBar({}, _cliProgress.Presets.shades_classic); + progressBar.start(100, 0); + + const sourceLines = []; + const targetLines = []; + const existingTargetFile = readFileIfExists(pathToTargetFile); + existingTargetFile.toString().split("\n").forEach((function (line) { + targetLines.push(line.trim()); + })); + progressBar.update(10); + const sourceFile = readFileIfExists(program.sourceFile); + sourceFile.toString().split("\n").forEach((function (line) { + sourceLines.push(line.trim()); + })); + progressBar.update(20); + const sourceChunks = createChunks(sourceLines, progressBar, false); + const targetChunks = createChunks(targetLines, progressBar, true); + + const outputChunks = compareChunksAndCreateOutput(sourceChunks, targetChunks, progressBar); + + const file = fs.createWriteStream(pathToOutputFile); + file.on('error', function (err) { + console.error('Something went wrong writing to output file at: ' + pathToOutputFile + err) + }); + file.on('open', function() { + file.write("{\n"); + outputChunks.forEach(function (chunk) { + progressBar.increment(); + chunk.split("\n").forEach(function (line) { + file.write(" " + line + "\n"); + }); + }); + file.write("\n}"); + file.end(); + }); + file.on('finish', function() { + const osName = process.platform; + if (osName.startsWith("win")) { + replaceLineEndingsToCRLF(pathToOutputFile); + } + }); + + progressBar.update(100); + progressBar.stop(); +} + +/** + * For each of the source chunks: + * - Determine if it's a new key-value => Add it to output, with source comments, source key-value commented, a message indicating it's new and the source-key value uncommented + * - If it's not new, compare it with the corresponding target chunk and log the differences, see createNewChunkComparingSourceAndTarget + * @param sourceChunks All the source chunks, split per key-value pair group + * @param targetChunks All the target chunks, split per key-value pair group + * @param progressBar The progressbar for the CLI + * @return {Array} All the output chunks, split per key-value pair group + */ +function compareChunksAndCreateOutput(sourceChunks, targetChunks, progressBar) { + const outputChunks = []; + sourceChunks.map((sourceChunk) => { + progressBar.increment(); + if (sourceChunk.trim().length !== 0) { + let newChunk = []; + const sourceList = sourceChunk.split("\n"); + const keyValueSource = sourceList[sourceList.length - 1]; + const keySource = getSubStringBeforeLastString(keyValueSource, ":"); + const commentSource = getSubStringBeforeLastString(sourceChunk, keyValueSource); + + const correspondingTargetChunk = targetChunks.find((targetChunk) => { + return targetChunk.includes(keySource); + }); + + // Create new chunk with: the source comments, the commented source key-value, the todos and either the old target key-value pair or if it's a new pair, the source key-value pair + newChunk.push(removeWhiteLines(commentSource)); + newChunk.push("// " + keyValueSource); + if (correspondingTargetChunk === undefined) { + newChunk.push(NEW_MESSAGE_TODO); + newChunk.push(keyValueSource); + } else { + createNewChunkComparingSourceAndTarget(correspondingTargetChunk, sourceChunk, commentSource, keyValueSource, newChunk); + } + + outputChunks.push(newChunk.filter(Boolean).join("\n")); + } else { + outputChunks.push(sourceChunk); + } + }); + return outputChunks; +} + +/** + * If a corresponding target chunk is found: + * - If old key value is not found in comments > Assumed it is new key + * - If the target comments do not contain the source comments (because they have changed since last time) => Add comments changed message + * - If the key-value in the target comments is not the same as the source key-value (because it changes since last time) => Add message changed message + * - Add the old todos if they haven't been added already + * - End with the original target key-value + */ +function createNewChunkComparingSourceAndTarget(correspondingTargetChunk, sourceChunk, commentSource, keyValueSource, newChunk) { + let commentsOfSourceHaveChanged = false; + let messageOfSourceHasChanged = false; + + const targetList = correspondingTargetChunk.split("\n"); + const oldKeyValueInTargetComments = getSubStringWithRegex(correspondingTargetChunk, "\\s*\\/\\/\\s*\".*"); + const keyValueTarget = targetList[targetList.length - 1]; + + if (oldKeyValueInTargetComments != null) { + const oldKeyValueUncommented = getSubStringWithRegex(oldKeyValueInTargetComments[0], "\".*")[0]; + + if (!(_.isEmpty(correspondingTargetChunk) && _.isEmpty(commentSource)) && !removeWhiteLines(correspondingTargetChunk).includes(removeWhiteLines(commentSource.trim()))) { + commentsOfSourceHaveChanged = true; + newChunk.push(COMMENTS_CHANGED_TODO); + } + const parsedOldKey = JSON5.stringify("{" + oldKeyValueUncommented + "}"); + const parsedSourceKey = JSON5.stringify("{" + keyValueSource + "}"); + if (!_.isEqual(parsedOldKey, parsedSourceKey)) { + messageOfSourceHasChanged = true; + newChunk.push(MESSAGE_CHANGED_TODO); + } + addOldTodosIfNeeded(targetList, newChunk, commentsOfSourceHaveChanged, messageOfSourceHasChanged); + } + newChunk.push(keyValueTarget); +} + +// Adds old todos found in target comments if they've not been added already +function addOldTodosIfNeeded(targetList, newChunk, commentsOfSourceHaveChanged, messageOfSourceHasChanged) { + targetList.map((targetLine) => { + const foundTODO = getSubStringWithRegex(targetLine, "\\s*//\\s*TODO.*"); + if (foundTODO != null) { + const todo = foundTODO[0]; + if (!((todo.includes(COMMENTS_CHANGED_TODO) && commentsOfSourceHaveChanged) + || (todo.includes(MESSAGE_CHANGED_TODO) && messageOfSourceHasChanged))) { + newChunk.push(todo); + } + } + }); +} + +/** + * Creates chunks from an array of lines, each chunk contains either an empty line or a grouping of comments with their corresponding key-value pair + * @param lines Array of lines, to be grouped into chunks + * @param progressBar Progressbar of the CLI + * @return {Array} Array of chunks, grouped by key-value and their corresponding comments or an empty line + */ +function createChunks(lines, progressBar, creatingTarget) { + const chunks = []; + let nextChunk = []; + let onMultiLineComment = false; + lines.map((line) => { + progressBar.increment(); + if (line.length === 0) { + chunks.push(line); + } + if (isOneLineCommentLine(line)) { + nextChunk.push(line); + } + if (onMultiLineComment) { + nextChunk.push(line); + if (isEndOfMultiLineComment(line)) { + onMultiLineComment = false; + } + } + if (isStartOfMultiLineComment(line)) { + nextChunk.push(line); + onMultiLineComment = true; + } + if (isKeyValuePair(line)) { + nextChunk.push(line); + const newMessageLineIfExists = nextChunk.find((lineInChunk) => lineInChunk.trim().startsWith(NEW_MESSAGE_TODO)); + if (newMessageLineIfExists === undefined || !creatingTarget) { + chunks.push(nextChunk.join("\n")); + } + nextChunk = []; + } + }); + return chunks; +} + +function readFileIfExists(pathToFile) { + if (checkIfFileExists(pathToFile)) { + try { + return fs.readFileSync(pathToFile, 'utf8'); + } catch (e) { + console.error('Error:', e.stack); + } + } + return null; +} + +function isOneLineCommentLine(line) { + return (line.startsWith("//")); +} + +function isStartOfMultiLineComment(line) { + return (line.startsWith("/*")); +} + +function isEndOfMultiLineComment(line) { + return (line.endsWith("*/")); +} + +function isKeyValuePair(line) { + return (line.startsWith("\"")); +} + + +function getSubStringWithRegex(string, regex) { + return string.match(regex); +} + +function getSubStringBeforeLastString(string, char) { + const lastCharIndex = string.lastIndexOf(char); + return string.substr(0, lastCharIndex); +} + + +function getOutputFileLocationIfExistsElseTargetFileLocation(targetLocation) { + if (program.outputFile) { + return program.outputFile; + } + return targetLocation; +} + +function checkIfPathToFileIsValid(pathToCheck) { + if (!pathToCheck.includes("/")) { + return true; + } + return checkIfFileExists(getPathOfDirectory(pathToCheck)); +} + +function checkIfFileExists(pathToCheck) { + return fs.existsSync(pathToCheck); +} + +function getPathOfDirectory(pathToCheck) { + return getSubStringBeforeLastString(pathToCheck, "/"); +} + +function removeWhiteLines(string) { + return string.replace(/^(?=\n)$|^\s*|\s*$|\n\n+/gm, "") +} + +/** + * Replaces UNIX \n LF line endings to windows \r\n CRLF line endings. + * @param filePath Path to file whose line endings are being converted + */ +function replaceLineEndingsToCRLF(filePath) { + const data = readFileIfExists(filePath); + const result = data.replace(/\n/g,"\r\n"); + fs.writeFileSync(filePath, result, 'utf8'); +} diff --git a/src/app/+browse-by/+browse-by-date-page/browse-by-date-page.component.spec.ts b/src/app/+browse-by/+browse-by-date-page/browse-by-date-page.component.spec.ts index a507e8e585..a1951a6d5a 100644 --- a/src/app/+browse-by/+browse-by-date-page/browse-by-date-page.component.spec.ts +++ b/src/app/+browse-by/+browse-by-date-page/browse-by-date-page.component.spec.ts @@ -11,7 +11,6 @@ import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.serv import { MockRouter } from '../../shared/mocks/mock-router'; import { ChangeDetectorRef, NO_ERRORS_SCHEMA } from '@angular/core'; import { of as observableOf } from 'rxjs/internal/observable/of'; -import { RemoteData } from '../../core/data/remote-data'; import { ActivatedRouteStub } from '../../shared/testing/active-router-stub'; import { Community } from '../../core/shared/community.model'; import { Item } from '../../core/shared/item.model'; diff --git a/src/app/+browse-by/+browse-by-date-page/browse-by-date-page.component.ts b/src/app/+browse-by/+browse-by-date-page/browse-by-date-page.component.ts index 98d0cc9cd1..34f9ff200e 100644 --- a/src/app/+browse-by/+browse-by-date-page/browse-by-date-page.component.ts +++ b/src/app/+browse-by/+browse-by-date-page/browse-by-date-page.component.ts @@ -82,7 +82,8 @@ export class BrowseByDatePageComponent extends BrowseByMetadataPageComponent { const date = firstItemRD.payload.firstMetadataValue(metadataField); if (hasValue(date)) { const dateObj = new Date(date); - lowerLimit = dateObj.getFullYear(); + // TODO: it appears that getFullYear (based on local time) is sometimes unreliable. Switching to UTC. + lowerLimit = dateObj.getUTCFullYear(); } } const options = []; diff --git a/src/app/+item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.spec.ts b/src/app/+item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.spec.ts index 3293711d73..54cb2837a2 100644 --- a/src/app/+item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.spec.ts +++ b/src/app/+item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.spec.ts @@ -97,7 +97,7 @@ describe('EditRelationshipListComponent', () => { relationshipService = jasmine.createSpyObj('relationshipService', { - getRelatedItemsByLabel: observableOf([author1, author2]), + getRelatedItemsByLabel: observableOf(new RemoteData(false, false, true, null, new PaginatedList(new PageInfo(), [author1, author2]))), } ); diff --git a/src/app/+item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.ts b/src/app/+item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.ts index 765d6484d4..3a145c99e0 100644 --- a/src/app/+item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.ts +++ b/src/app/+item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.ts @@ -4,8 +4,10 @@ import { Observable } from 'rxjs/internal/Observable'; import { FieldUpdate, FieldUpdates } from '../../../../core/data/object-updates/object-updates.reducer'; import { RelationshipService } from '../../../../core/data/relationship.service'; import { Item } from '../../../../core/shared/item.model'; -import { switchMap } from 'rxjs/operators'; +import { map, switchMap } from 'rxjs/operators'; import { hasValue } from '../../../../shared/empty.util'; +import { RemoteData } from '../../../../core/data/remote-data'; +import { PaginatedList } from '../../../../core/data/paginated-list'; @Component({ selector: 'ds-edit-relationship-list', @@ -63,7 +65,7 @@ export class EditRelationshipListComponent implements OnInit, OnChanges { * Transform the item's relationships of a specific type into related items * @param label The relationship type's label */ - public getRelatedItemsByLabel(label: string): Observable { + public getRelatedItemsByLabel(label: string): Observable>> { return this.relationshipService.getRelatedItemsByLabel(this.item, label); } @@ -73,7 +75,7 @@ export class EditRelationshipListComponent implements OnInit, OnChanges { */ public getUpdatesByLabel(label: string): Observable { return this.getRelatedItemsByLabel(label).pipe( - switchMap((items: Item[]) => this.objectUpdatesService.getFieldUpdatesExclusive(this.url, items)) + switchMap((itemsRD) => this.objectUpdatesService.getFieldUpdatesExclusive(this.url, itemsRD.payload.page)) ) } diff --git a/src/app/+item-page/edit-item-page/item-relationships/edit-relationship/edit-relationship.component.html b/src/app/+item-page/edit-item-page/item-relationships/edit-relationship/edit-relationship.component.html index e25c3c204f..03040ce8e0 100644 --- a/src/app/+item-page/edit-item-page/item-relationships/edit-relationship/edit-relationship.component.html +++ b/src/app/+item-page/edit-item-page/item-relationships/edit-relationship/edit-relationship.component.html @@ -1,6 +1,6 @@
- +
diff --git a/src/app/+item-page/edit-item-page/item-relationships/edit-relationship/edit-relationship.component.spec.ts b/src/app/+item-page/edit-item-page/item-relationships/edit-relationship/edit-relationship.component.spec.ts index e98da94c9d..54fce0a68e 100644 --- a/src/app/+item-page/edit-item-page/item-relationships/edit-relationship/edit-relationship.component.spec.ts +++ b/src/app/+item-page/edit-item-page/item-relationships/edit-relationship/edit-relationship.component.spec.ts @@ -5,7 +5,6 @@ import { ObjectUpdatesService } from '../../../../core/data/object-updates/objec import { NO_ERRORS_SCHEMA } from '@angular/core'; import { EditRelationshipComponent } from './edit-relationship.component'; import { RelationshipType } from '../../../../core/shared/item-relationships/relationship-type.model'; -import { ResourceType } from '../../../../core/shared/resource-type'; import { Relationship } from '../../../../core/shared/item-relationships/relationship.model'; import { RemoteData } from '../../../../core/data/remote-data'; import { Item } from '../../../../core/shared/item.model'; diff --git a/src/app/+item-page/edit-item-page/item-relationships/edit-relationship/edit-relationship.component.ts b/src/app/+item-page/edit-item-page/item-relationships/edit-relationship/edit-relationship.component.ts index 497b06775a..302ebf68a7 100644 --- a/src/app/+item-page/edit-item-page/item-relationships/edit-relationship/edit-relationship.component.ts +++ b/src/app/+item-page/edit-item-page/item-relationships/edit-relationship/edit-relationship.component.ts @@ -4,7 +4,7 @@ import { cloneDeep } from 'lodash'; import { Item } from '../../../../core/shared/item.model'; import { ObjectUpdatesService } from '../../../../core/data/object-updates/object-updates.service'; import { FieldChangeType } from '../../../../core/data/object-updates/object-updates.actions'; -import { ItemViewMode } from '../../../../shared/items/item-type-decorator'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; @Component({ // tslint:disable-next-line:component-selector @@ -31,7 +31,7 @@ export class EditRelationshipComponent implements OnChanges { /** * The view-mode we're currently on */ - viewMode = ItemViewMode.Element; + viewMode = ViewMode.ListElement; constructor(private objectUpdatesService: ObjectUpdatesService) { } diff --git a/src/app/+item-page/full/full-item-page.component.spec.ts b/src/app/+item-page/full/full-item-page.component.spec.ts index 2f151b4997..e276d69a69 100644 --- a/src/app/+item-page/full/full-item-page.component.spec.ts +++ b/src/app/+item-page/full/full-item-page.component.spec.ts @@ -23,7 +23,7 @@ import { } from '../../shared/testing/utils'; const mockItem: Item = Object.assign(new Item(), { - bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), + bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), metadata: { 'dc.title': [ { diff --git a/src/app/+item-page/simple/field-components/specific-field/generic/generic-item-page-field.component.ts b/src/app/+item-page/simple/field-components/specific-field/generic/generic-item-page-field.component.ts index ee7d27a11f..3b8d261dcc 100644 --- a/src/app/+item-page/simple/field-components/specific-field/generic/generic-item-page-field.component.ts +++ b/src/app/+item-page/simple/field-components/specific-field/generic/generic-item-page-field.component.ts @@ -10,7 +10,7 @@ import { ItemPageFieldComponent } from '../item-page-field.component'; /** * This component can be used to represent metadata on a simple item page. * It is the most generic way of displaying metadata values - * It expects 4 parameters: The item, a seperator, the metadata keys and an i18n key + * It expects 4 parameters: The item, a separator, the metadata keys and an i18n key */ export class GenericItemPageFieldComponent extends ItemPageFieldComponent { diff --git a/src/app/+item-page/simple/field-components/specific-field/item-page-field.component.spec.ts b/src/app/+item-page/simple/field-components/specific-field/item-page-field.component.spec.ts index 1b7acb2e3b..faf3862063 100644 --- a/src/app/+item-page/simple/field-components/specific-field/item-page-field.component.spec.ts +++ b/src/app/+item-page/simple/field-components/specific-field/item-page-field.component.spec.ts @@ -4,12 +4,9 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { Item } from '../../../../core/shared/item.model'; import { PaginatedList } from '../../../../core/data/paginated-list'; import { MockTranslateLoader } from '../../../../shared/mocks/mock-translate-loader'; -import { Observable } from 'rxjs'; import { PageInfo } from '../../../../core/shared/page-info.model'; -import { RemoteData } from '../../../../core/data/remote-data'; import { ItemPageFieldComponent } from './item-page-field.component'; import { MetadataValuesComponent } from '../../../field-components/metadata-values/metadata-values.component'; -import { of as observableOf } from 'rxjs'; import { MetadataMap, MetadataValue } from '../../../../core/shared/metadata.models'; import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils'; @@ -53,7 +50,7 @@ describe('ItemPageFieldComponent', () => { export function mockItemWithMetadataFieldAndValue(field: string, value: string): Item { const item = Object.assign(new Item(), { - bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), + bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), metadata: new MetadataMap() }); item.metadata[field] = [{ diff --git a/src/app/+item-page/simple/item-page.component.html b/src/app/+item-page/simple/item-page.component.html index b6de496dc4..501e3e161e 100644 --- a/src/app/+item-page/simple/item-page.component.html +++ b/src/app/+item-page/simple/item-page.component.html @@ -1,7 +1,7 @@
- +
diff --git a/src/app/+item-page/simple/item-page.component.ts b/src/app/+item-page/simple/item-page.component.ts index 89d5977583..10deef23e4 100644 --- a/src/app/+item-page/simple/item-page.component.ts +++ b/src/app/+item-page/simple/item-page.component.ts @@ -1,21 +1,18 @@ - -import { mergeMap, filter, map, take, tap } from 'rxjs/operators'; +import { map } from 'rxjs/operators'; import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { Observable } from 'rxjs'; import { ItemDataService } from '../../core/data/item-data.service'; import { RemoteData } from '../../core/data/remote-data'; -import { Bitstream } from '../../core/shared/bitstream.model'; import { Item } from '../../core/shared/item.model'; import { MetadataService } from '../../core/metadata/metadata.service'; import { fadeInOut } from '../../shared/animations/fade'; -import { hasValue } from '../../shared/empty.util'; import { redirectToPageNotFoundOn404 } from '../../core/shared/operators'; -import { ItemViewMode } from '../../shared/items/item-type-decorator'; +import { ViewMode } from '../../core/shared/view-mode.model'; /** * This component renders a simple item page. @@ -44,7 +41,7 @@ export class ItemPageComponent implements OnInit { /** * The view-mode we're currently on */ - viewMode = ItemViewMode.Full; + viewMode = ViewMode.StandalonePage; constructor( private route: ActivatedRoute, @@ -53,6 +50,9 @@ export class ItemPageComponent implements OnInit { private metadataService: MetadataService, ) { } + /** + * Initialize instance variables + */ ngOnInit(): void { this.itemRD$ = this.route.data.pipe( map((data) => data.item as RemoteData), diff --git a/src/app/+item-page/simple/item-types/publication/publication.component.html b/src/app/+item-page/simple/item-types/publication/publication.component.html index abf5225c27..3cd4d0aa69 100644 --- a/src/app/+item-page/simple/item-types/publication/publication.component.html +++ b/src/app/+item-page/simple/item-types/publication/publication.component.html @@ -1,67 +1,72 @@

- {{'publication.page.titleprefix' | translate}} + {{'publication.page.titleprefix' | translate}}

- + - - - - + + + - - -
+ [parentItem]="object" + [itemType]="'Person'" + [metadataField]="'dc.contributor.author'" + [label]="'relationships.isAuthorOf' | translate"> - - + - - - - + + diff --git a/src/app/+item-page/simple/item-types/publication/publication.component.spec.ts b/src/app/+item-page/simple/item-types/publication/publication.component.spec.ts index 59400fa2b9..0ff6612440 100644 --- a/src/app/+item-page/simple/item-types/publication/publication.component.spec.ts +++ b/src/app/+item-page/simple/item-types/publication/publication.component.spec.ts @@ -3,19 +3,16 @@ import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; import { MockTranslateLoader } from '../../../../shared/mocks/mock-translate-loader'; import { GenericItemPageFieldComponent } from '../../field-components/specific-field/generic/generic-item-page-field.component'; import { TruncatePipe } from '../../../../shared/utils/truncate.pipe'; -import { ITEM } from '../../../../shared/items/switcher/item-type-switcher.component'; import { ItemDataService } from '../../../../core/data/item-data.service'; import { SearchFixedFilterService } from '../../../../+search-page/search-filters/search-filter/search-fixed-filter.service'; import { TruncatableService } from '../../../../shared/truncatable/truncatable.service'; import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; import { Item } from '../../../../core/shared/item.model'; -import { RemoteData } from '../../../../core/data/remote-data'; import { PaginatedList } from '../../../../core/data/paginated-list'; import { PageInfo } from '../../../../core/shared/page-info.model'; import { By } from '@angular/platform-browser'; import { createRelationshipsObservable } from '../shared/item.component.spec'; import { PublicationComponent } from './publication.component'; -import { of as observableOf } from 'rxjs'; import { MetadataMap } from '../../../../core/shared/metadata.models'; import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils'; @@ -45,7 +42,6 @@ describe('PublicationComponent', () => { })], declarations: [PublicationComponent, GenericItemPageFieldComponent, TruncatePipe], providers: [ - {provide: ITEM, useValue: mockItem}, {provide: ItemDataService, useValue: {}}, {provide: SearchFixedFilterService, useValue: searchFixedFilterServiceStub}, {provide: TruncatableService, useValue: {}} @@ -60,6 +56,7 @@ describe('PublicationComponent', () => { beforeEach(async(() => { fixture = TestBed.createComponent(PublicationComponent); comp = fixture.componentInstance; + comp.object = mockItem; fixture.detectChanges(); })); diff --git a/src/app/+item-page/simple/item-types/publication/publication.component.ts b/src/app/+item-page/simple/item-types/publication/publication.component.ts index 81e2726e0c..a8c7539e64 100644 --- a/src/app/+item-page/simple/item-types/publication/publication.component.ts +++ b/src/app/+item-page/simple/item-types/publication/publication.component.ts @@ -1,62 +1,20 @@ -import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; -import { Observable } from 'rxjs'; -import { Item } from '../../../../core/shared/item.model'; -import { - DEFAULT_ITEM_TYPE, ItemViewMode, - rendersItemType -} from '../../../../shared/items/item-type-decorator'; +import { ChangeDetectionStrategy, Component } from '@angular/core'; import { ItemComponent } from '../shared/item.component'; -import { MetadataRepresentation } from '../../../../core/shared/metadata-representation/metadata-representation.model'; -import { getRelatedItemsByTypeLabel } from '../shared/item-relationships-utils'; +import { listableObjectComponent } from '../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { Item } from '../../../../core/shared/item.model'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; -@rendersItemType('Publication', ItemViewMode.Full) -@rendersItemType(DEFAULT_ITEM_TYPE, ItemViewMode.Full) +/** + * Component that represents a publication Item page + */ + +@listableObjectComponent('Publication', ViewMode.StandalonePage) +@listableObjectComponent(Item, ViewMode.StandalonePage) @Component({ selector: 'ds-publication', styleUrls: ['./publication.component.scss'], templateUrl: './publication.component.html', changeDetection: ChangeDetectionStrategy.OnPush, }) -export class PublicationComponent extends ItemComponent implements OnInit { - /** - * The authors related to this publication - */ - authors$: Observable; - - /** - * The projects related to this publication - */ - projects$: Observable; - - /** - * The organisation units related to this publication - */ - orgUnits$: Observable; - - /** - * The journal issues related to this publication - */ - journalIssues$: Observable; - - ngOnInit(): void { - super.ngOnInit(); - - if (this.resolvedRelsAndTypes$) { - - this.authors$ = this.buildRepresentations('Person', 'dc.contributor.author'); - - this.projects$ = this.resolvedRelsAndTypes$.pipe( - getRelatedItemsByTypeLabel(this.item.id, 'isProjectOfPublication') - ); - - this.orgUnits$ = this.resolvedRelsAndTypes$.pipe( - getRelatedItemsByTypeLabel(this.item.id, 'isOrgUnitOfPublication') - ); - - this.journalIssues$ = this.resolvedRelsAndTypes$.pipe( - getRelatedItemsByTypeLabel(this.item.id, 'isJournalIssueOfPublication') - ); - - } - } +export class PublicationComponent extends ItemComponent { } diff --git a/src/app/+item-page/simple/item-types/shared/item-relationships-utils.ts b/src/app/+item-page/simple/item-types/shared/item-relationships-utils.ts index 228b52d7c7..b40b1a17b6 100644 --- a/src/app/+item-page/simple/item-types/shared/item-relationships-utils.ts +++ b/src/app/+item-page/simple/item-types/shared/item-relationships-utils.ts @@ -1,18 +1,14 @@ -import { ItemMetadataRepresentation } from '../../../../core/shared/metadata-representation/item/item-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 { MetadataValue } from '../../../../core/shared/metadata.models'; import { getRemoteDataPayload, getSucceededRemoteData } from '../../../../core/shared/operators'; import { hasNoValue, hasValue } from '../../../../shared/empty.util'; import { Observable } from 'rxjs/internal/Observable'; import { Relationship } from '../../../../core/shared/item-relationships/relationship.model'; import { RelationshipType } from '../../../../core/shared/item-relationships/relationship-type.model'; -import { distinctUntilChanged, filter, flatMap, map, switchMap, tap } from 'rxjs/operators'; -import { of as observableOf, zip as observableZip, combineLatest as observableCombineLatest } from 'rxjs'; -import { ItemDataService } from '../../../../core/data/item-data.service'; +import { distinctUntilChanged, flatMap, map, switchMap } from 'rxjs/operators'; +import { zip as observableZip, combineLatest as observableCombineLatest } from 'rxjs'; import { Item } from '../../../../core/shared/item.model'; import { RemoteData } from '../../../../core/data/remote-data'; import { RelationshipService } from '../../../../core/data/relationship.service'; +import { PaginatedList } from '../../../../core/data/paginated-list'; /** * Operator for comparing arrays using a mapping function @@ -100,53 +96,37 @@ export const relationsToItems = (thisId: string) => ); /** - * 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) + * Operator for turning a paginated list of relationships into a paginated list of the relevant items + * The result is wrapped in the original RemoteData and PaginatedList + * @param {string} thisId The item's id of which the relations belong to + * @returns {(source: Observable) => Observable} */ -export const getRelatedItemsByTypeLabel = (thisId: string, label: string) => - (source: Observable<[Relationship[], RelationshipType[]]>): Observable => +export const paginatedRelationsToItems = (thisId: string) => + (source: Observable>>): Observable>> => source.pipe( - filterRelationsByTypeLabel(label, thisId), - relationsToItems(thisId) - ); - -/** - * 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 itemType The type of relation this list resembles (for creating representations) - * @param metadata The list of original Metadatum objects - */ -export const relationsToRepresentations = (parentId: string, itemType: string, metadata: MetadataValue[]) => - (source: Observable): Observable => - 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( - map(([leftItem, rightItem]) => { - if (leftItem.payload.id === parentId) { - return rightItem.payload; - } else if (rightItem.payload.id === parentId) { - return leftItem.payload; - } - }), - map((item: Item) => Object.assign(new ItemMetadataRepresentation(metadatum), item)) - ); + getSucceededRemoteData(), + switchMap((relationshipsRD: RemoteData>) => { + return observableZip( + ...relationshipsRD.payload.page.map((rel: Relationship) => observableCombineLatest(rel.leftItem, rel.rightItem)) + ).pipe( + map((arr) => + arr + .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; } - } else { - return observableOf(Object.assign(new MetadatumRepresentation(itemType), metadatum)); - } - }) + }) + .filter((item: Item) => hasValue(item)) + ), + distinctUntilChanged(compareArraysUsingIds()), + map((relatedItems: Item[]) => + Object.assign(relationshipsRD, { payload: Object.assign(relationshipsRD.payload, { page: relatedItems } )}) + ) ) - ) + }) ); /** diff --git a/src/app/+item-page/simple/item-types/shared/item.component.spec.ts b/src/app/+item-page/simple/item-types/shared/item.component.spec.ts index 4414d9a713..add2fb1e17 100644 --- a/src/app/+item-page/simple/item-types/shared/item.component.spec.ts +++ b/src/app/+item-page/simple/item-types/shared/item.component.spec.ts @@ -7,17 +7,14 @@ import { ItemDataService } from '../../../../core/data/item-data.service'; import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; import { MockTranslateLoader } from '../../../../shared/mocks/mock-translate-loader'; import { ChangeDetectionStrategy, DebugElement, NO_ERRORS_SCHEMA } from '@angular/core'; -import { ITEM } from '../../../../shared/items/switcher/item-type-switcher.component'; import { TruncatePipe } from '../../../../shared/utils/truncate.pipe'; import { isNotEmpty } from '../../../../shared/empty.util'; import { SearchFixedFilterService } from '../../../../+search-page/search-filters/search-filter/search-fixed-filter.service'; import { RelationshipType } from '../../../../core/shared/item-relationships/relationship-type.model'; import { PaginatedList } from '../../../../core/data/paginated-list'; -import { RemoteData } from '../../../../core/data/remote-data'; import { Relationship } from '../../../../core/shared/item-relationships/relationship.model'; import { PageInfo } from '../../../../core/shared/page-info.model'; import { ItemComponent } from './item.component'; -import { of as observableOf } from 'rxjs'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { VarDirective } from '../../../../shared/utils/var.directive'; import { Observable } from 'rxjs/internal/Observable'; @@ -56,7 +53,6 @@ export function getItemPageFieldsTest(mockItem: Item, component) { })], declarations: [component, GenericItemPageFieldComponent, TruncatePipe], providers: [ - {provide: ITEM, useValue: mockItem}, {provide: ItemDataService, useValue: {}}, {provide: SearchFixedFilterService, useValue: searchFixedFilterServiceStub}, {provide: TruncatableService, useValue: {}} @@ -71,6 +67,7 @@ export function getItemPageFieldsTest(mockItem: Item, component) { beforeEach(async(() => { fixture = TestBed.createComponent(component); comp = fixture.componentInstance; + comp.object = mockItem; fixture.detectChanges(); })); @@ -317,115 +314,4 @@ describe('ItemComponent', () => { }); }); - describe('when calling buildRepresentations', () => { - let comp: ItemComponent; - let fixture: ComponentFixture; - - 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(), { - id: '1', - uuid: '1', - metadata: new MetadataMap() - }); - 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] = [ - { - value: 'Second value', - place: 1 - }, - { - value: 'Third value', - place: 2, - authority: 'virtual::123' - }, - { - value: 'First value', - place: 0 - }, - { - value: 'Fourth value', - place: 3, - authority: '123' - } - ] as MetadataValue[]; - const mockItemDataService = Object.assign({ - findById: (id) => { - if (id === relatedItem.id) { - return createSuccessfulRemoteDataObject$(relatedItem) - } - } - }) as ItemDataService; - - let representations: Observable; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [TranslateModule.forRoot({ - loader: { - provide: TranslateLoader, - useClass: MockTranslateLoader - } - }), BrowserAnimationsModule], - declarations: [ItemComponent, VarDirective], - providers: [ - {provide: ITEM, useValue: mockItem} - ], - - schemas: [NO_ERRORS_SCHEMA] - }).overrideComponent(ItemComponent, { - set: {changeDetection: ChangeDetectionStrategy.Default} - }).compileComponents(); - })); - - beforeEach(async(() => { - fixture = TestBed.createComponent(ItemComponent); - comp = fixture.componentInstance; - fixture.detectChanges(); - representations = comp.buildRepresentations('bogus', metadataField); - })); - - it('should contain exactly 4 metadata-representations', () => { - representations.subscribe((reps: MetadataRepresentation[]) => { - expect(reps.length).toEqual(4); - }); - }); - - it('should have all the representations in the correct order', () => { - representations.subscribe((reps: MetadataRepresentation[]) => { - expect(reps[0].getValue()).toEqual('First value'); - expect(reps[1].getValue()).toEqual('Second value'); - expect(reps[2].getValue()).toEqual('Third value'); - expect(reps[3].getValue()).toEqual('Fourth value'); - }); - }); - - it('should have created the correct MetadatumRepresentation and ItemMetadataRepresentation objects for the correct Metadata', () => { - representations.subscribe((reps: MetadataRepresentation[]) => { - expect(reps[0] instanceof MetadatumRepresentation).toEqual(true); - expect(reps[1] instanceof MetadatumRepresentation).toEqual(true); - expect(reps[2] instanceof ItemMetadataRepresentation).toEqual(true); - expect(reps[3] instanceof MetadatumRepresentation).toEqual(true); - }); - }); - }) - }); diff --git a/src/app/+item-page/simple/item-types/shared/item.component.ts b/src/app/+item-page/simple/item-types/shared/item.component.ts index 297a333eeb..d4b0c8de89 100644 --- a/src/app/+item-page/simple/item-types/shared/item.component.ts +++ b/src/app/+item-page/simple/item-types/shared/item.component.ts @@ -1,15 +1,5 @@ -import { Component, Inject, OnInit } from '@angular/core'; -import { Observable , zip as observableZip, combineLatest as observableCombineLatest } from 'rxjs'; -import { distinctUntilChanged, filter, flatMap, map } from 'rxjs/operators'; -import { PaginatedList } from '../../../../core/data/paginated-list'; -import { RemoteData } from '../../../../core/data/remote-data'; -import { RelationshipType } from '../../../../core/shared/item-relationships/relationship-type.model'; -import { Relationship } from '../../../../core/shared/item-relationships/relationship.model'; +import { Component, Inject, Input } from '@angular/core'; import { Item } from '../../../../core/shared/item.model'; -import { getRemoteDataPayload, getSucceededRemoteData } from '../../../../core/shared/operators'; -import { ITEM } from '../../../../shared/items/switcher/item-type-switcher.component'; -import { MetadataRepresentation } from '../../../../core/shared/metadata-representation/metadata-representation.model'; -import { compareArraysUsingIds, relationsToRepresentations } from './item-relationships-utils'; @Component({ selector: 'ds-item', @@ -18,60 +8,6 @@ import { compareArraysUsingIds, relationsToRepresentations } from './item-relati /** * A generic component for displaying metadata and relations of an item */ -export class ItemComponent implements OnInit { - /** - * Resolved relationships and types together in one observable - */ - resolvedRelsAndTypes$: Observable<[Relationship[], RelationshipType[]]>; - - constructor( - @Inject(ITEM) public item: Item - ) {} - - ngOnInit(): void { - const relationships$ = this.item.relationships; - if (relationships$) { - const relsCurrentPage$ = relationships$.pipe( - filter((rd: RemoteData>) => rd.hasSucceeded), - getRemoteDataPayload(), - map((pl: PaginatedList) => pl.page), - distinctUntilChanged(compareArraysUsingIds()) - ); - - const relTypesCurrentPage$ = relsCurrentPage$.pipe( - flatMap((rels: Relationship[]) => - observableZip(...rels.map((rel: Relationship) => rel.relationshipType)).pipe( - map(([...arr]: Array>) => arr.map((d: RemoteData) => d.payload)) - ) - ), - distinctUntilChanged(compareArraysUsingIds()) - ); - - this.resolvedRelsAndTypes$ = observableCombineLatest( - relsCurrentPage$, - relTypesCurrentPage$ - ); - } - } - - /** - * Build a list of MetadataRepresentations for the current item. This combines all metadata and relationships of a - * certain type. - * @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. - */ - buildRepresentations(itemType: string, metadataField: string): Observable { - const metadata = this.item.findMetadataSortedByPlace(metadataField); - const relsCurrentPage$ = this.item.relationships.pipe( - getSucceededRemoteData(), - getRemoteDataPayload(), - map((pl: PaginatedList) => pl.page), - distinctUntilChanged(compareArraysUsingIds()) - ); - - return relsCurrentPage$.pipe( - relationsToRepresentations(this.item.id, itemType, metadata) - ); - } - +export class ItemComponent { + @Input() object: Item; } diff --git a/src/app/+item-page/simple/metadata-representation-list/metadata-representation-list.component.html b/src/app/+item-page/simple/metadata-representation-list/metadata-representation-list.component.html index 48eabf8451..64f1184181 100644 --- a/src/app/+item-page/simple/metadata-representation-list/metadata-representation-list.component.html +++ b/src/app/+item-page/simple/metadata-representation-list/metadata-representation-list.component.html @@ -1,5 +1,11 @@ - - - + + + + + diff --git a/src/app/+item-page/simple/metadata-representation-list/metadata-representation-list.component.spec.ts b/src/app/+item-page/simple/metadata-representation-list/metadata-representation-list.component.spec.ts index da2af9f2c1..7beabdceba 100644 --- a/src/app/+item-page/simple/metadata-representation-list/metadata-representation-list.component.spec.ts +++ b/src/app/+item-page/simple/metadata-representation-list/metadata-representation-list.component.spec.ts @@ -2,23 +2,72 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; import { By } from '@angular/platform-browser'; import { MetadataRepresentationListComponent } from './metadata-representation-list.component'; -import { MetadatumRepresentation } from '../../../core/shared/metadata-representation/metadatum/metadatum-representation.model'; -import { ItemMetadataRepresentation } from '../../../core/shared/metadata-representation/item/item-metadata-representation.model'; +import { RelationshipService } from '../../../core/data/relationship.service'; +import { Item } from '../../../core/shared/item.model'; +import { Relationship } from '../../../core/shared/item-relationships/relationship.model'; +import { createSuccessfulRemoteDataObject$ } from '../../../shared/testing/utils'; +import { TranslateModule } from '@ngx-translate/core'; -const itemType = 'type'; -const metadataRepresentation1 = new MetadatumRepresentation(itemType); -const metadataRepresentation2 = new ItemMetadataRepresentation(Object.assign({})); -const representations = [metadataRepresentation1, metadataRepresentation2]; +const itemType = 'Person'; +const metadataField = 'dc.contributor.author'; +const parentItem: Item = Object.assign(new Item(), { + id: 'parent-item', + metadata: { + 'dc.contributor.author': [ + { + language: null, + value: 'Related Author with authority', + authority: 'virtual::related-author', + place: 2 + }, + { + language: null, + value: 'Author without authority', + place: 1 + } + ], + 'dc.title': [ + { + language: null, + value: 'Parent Item' + } + ] + } +}); +const relatedAuthor: Item = Object.assign(new Item(), { + id: 'related-author', + metadata: { + 'dc.title': [ + { + language: null, + value: 'Related Author' + } + ] + } +}); +const relation: Relationship = Object.assign(new Relationship(), { + leftItem: createSuccessfulRemoteDataObject$(parentItem), + rightItem: createSuccessfulRemoteDataObject$(relatedAuthor) +}); +let relationshipService: RelationshipService; describe('MetadataRepresentationListComponent', () => { let comp: MetadataRepresentationListComponent; let fixture: ComponentFixture; + relationshipService = jasmine.createSpyObj('relationshipService', + { + findById: createSuccessfulRemoteDataObject$(relation) + } + ); + beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [], + imports: [TranslateModule.forRoot()], declarations: [MetadataRepresentationListComponent], - providers: [], + providers: [ + { provide: RelationshipService, useValue: relationshipService } + ], schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(MetadataRepresentationListComponent, { set: {changeDetection: ChangeDetectionStrategy.Default} @@ -28,13 +77,45 @@ describe('MetadataRepresentationListComponent', () => { beforeEach(async(() => { fixture = TestBed.createComponent(MetadataRepresentationListComponent); comp = fixture.componentInstance; - comp.representations = representations; + comp.parentItem = parentItem; + comp.itemType = itemType; + comp.metadataField = metadataField; fixture.detectChanges(); })); - it(`should load ${representations.length} item-type-switcher components`, () => { - const fields = fixture.debugElement.queryAll(By.css('ds-item-type-switcher')); - expect(fields.length).toBe(representations.length); + it('should load 2 ds-metadata-representation-loader components', () => { + const fields = fixture.debugElement.queryAll(By.css('ds-metadata-representation-loader')); + expect(fields.length).toBe(2); + }); + + it('should initialize the original limit', () => { + expect(comp.originalLimit).toEqual(comp.limit); + }); + + describe('when viewMore is called', () => { + beforeEach(() => { + comp.viewMore(); + }); + + it('should set the limit to a high number in order to retrieve all metadata representations', () => { + expect(comp.limit).toBeGreaterThanOrEqual(999); + }); + }); + + describe('when viewLess is called', () => { + let originalLimit; + + beforeEach(() => { + // Store the original value of limit + originalLimit = comp.limit; + // Set limit to a random number + comp.limit = 458; + comp.viewLess(); + }); + + it('should reset the limit to the original value', () => { + expect(comp.limit).toEqual(originalLimit); + }); }); }); diff --git a/src/app/+item-page/simple/metadata-representation-list/metadata-representation-list.component.ts b/src/app/+item-page/simple/metadata-representation-list/metadata-representation-list.component.ts index f0dc222bf1..b58290d87c 100644 --- a/src/app/+item-page/simple/metadata-representation-list/metadata-representation-list.component.ts +++ b/src/app/+item-page/simple/metadata-representation-list/metadata-representation-list.component.ts @@ -1,6 +1,16 @@ -import { Component, Input } from '@angular/core'; +import { Component, Input, OnInit } from '@angular/core'; import { MetadataRepresentation } from '../../../core/shared/metadata-representation/metadata-representation.model'; -import { ItemViewMode } from '../../../shared/items/item-type-decorator'; +import { Observable } from 'rxjs/internal/Observable'; +import { RemoteData } from '../../../core/data/remote-data'; +import { RelationshipService } from '../../../core/data/relationship.service'; +import { Item } from '../../../core/shared/item.model'; +import { combineLatest as observableCombineLatest, of as observableOf, zip as observableZip } from 'rxjs'; +import { MetadataValue } from '../../../core/shared/metadata.models'; +import { MetadatumRepresentation } from '../../../core/shared/metadata-representation/metadatum/metadatum-representation.model'; +import { filter, map, switchMap } from 'rxjs/operators'; +import { getSucceededRemoteData } from '../../../core/shared/operators'; +import { Relationship } from '../../../core/shared/item-relationships/relationship.model'; +import { ItemMetadataRepresentation } from '../../../core/shared/metadata-representation/item/item-metadata-representation.model'; @Component({ selector: 'ds-metadata-representation-list', @@ -8,13 +18,25 @@ import { ItemViewMode } from '../../../shared/items/item-type-decorator'; }) /** * This component is used for displaying metadata - * It expects a list of MetadataRepresentation objects and a label to put on top of the list + * It expects an item and a metadataField to fetch metadata + * It expects an itemType to resolve the metadata to a an item + * It expects a label to put on top of the list */ -export class MetadataRepresentationListComponent { +export class MetadataRepresentationListComponent implements OnInit { /** - * A list of metadata-representations to display + * The parent of the list of related items to display */ - @Input() representations: MetadataRepresentation[]; + @Input() parentItem: Item; + + /** + * The type of item to create a representation of + */ + @Input() itemType: string; + + /** + * The metadata field to use for fetching metadata from the item + */ + @Input() metadataField: string; /** * An i18n label to use as a title for the list @@ -22,8 +44,91 @@ export class MetadataRepresentationListComponent { @Input() label: string; /** - * The view-mode we're currently on - * @type {ElementViewMode} + * The max amount of representations to display + * Defaults to 10 + * The default can optionally be overridden by providing the limit as input to the component */ - viewMode = ItemViewMode.Metadata; + @Input() limit = 10; + + /** + * A list of metadata-representations to display + */ + representations$: Observable; + + /** + * The originally provided limit + * Used for resetting the limit to the original value when collapsing the list + */ + originalLimit: number; + + /** + * The total amount of metadata values available + */ + total: number; + + constructor(public relationshipService: RelationshipService) { + } + + ngOnInit(): void { + this.originalLimit = this.limit; + this.setRepresentations(); + } + + /** + * Initialize the metadata representations + */ + setRepresentations() { + const metadata = this.parentItem.findMetadataSortedByPlace(this.metadataField); + this.total = metadata.length; + this.representations$ = this.resolveMetadataRepresentations(metadata); + } + + /** + * Resolve a list of metadata values to a list of metadata representations + * @param metadata + */ + resolveMetadataRepresentations(metadata: MetadataValue[]): Observable { + return observableZip( + ...metadata + .slice(0, this.limit) + .map((metadatum: any) => Object.assign(new MetadataValue(), metadatum)) + .map((metadatum: MetadataValue) => { + if (metadatum.isVirtual) { + return this.relationshipService.findById(metadatum.virtualValue).pipe( + getSucceededRemoteData(), + switchMap((relRD: RemoteData) => + observableCombineLatest(relRD.payload.leftItem, relRD.payload.rightItem).pipe( + filter(([leftItem, rightItem]) => leftItem.hasSucceeded && rightItem.hasSucceeded), + map(([leftItem, rightItem]) => { + if (leftItem.payload.id === this.parentItem.id) { + return rightItem.payload; + } else if (rightItem.payload.id === this.parentItem.id) { + return leftItem.payload; + } + }), + map((item: Item) => Object.assign(new ItemMetadataRepresentation(metadatum), item)) + ) + )); + } else { + return observableOf(Object.assign(new MetadatumRepresentation(this.itemType), metadatum)); + } + }) + ); + } + + /** + * Expand the list to display all metadata representations + */ + viewMore() { + this.limit = 9999; + this.setRepresentations(); + } + + /** + * Collapse the list to display the originally displayed metadata representations + */ + viewLess() { + this.limit = this.originalLimit; + this.setRepresentations(); + } } diff --git a/src/app/+item-page/simple/related-items/related-items-component.ts b/src/app/+item-page/simple/related-items/related-items-component.ts index 7b54d7316a..9cbfd2c28d 100644 --- a/src/app/+item-page/simple/related-items/related-items-component.ts +++ b/src/app/+item-page/simple/related-items/related-items-component.ts @@ -1,6 +1,12 @@ -import { Component, Input } from '@angular/core'; +import { Component, HostBinding, Input, OnDestroy, OnInit } from '@angular/core'; import { Item } from '../../../core/shared/item.model'; -import { ItemViewMode } from '../../../shared/items/item-type-decorator'; +import { Observable } from 'rxjs/internal/Observable'; +import { RemoteData } from '../../../core/data/remote-data'; +import { PaginatedList } from '../../../core/data/paginated-list'; +import { RelationshipService } from '../../../core/data/relationship.service'; +import { FindAllOptions } from '../../../core/data/request.models'; +import { Subscription } from 'rxjs/internal/Subscription'; +import { ViewMode } from '../../../core/shared/view-mode.model'; @Component({ selector: 'ds-related-items', @@ -9,22 +15,94 @@ import { ItemViewMode } from '../../../shared/items/item-type-decorator'; }) /** * This component is used for displaying relations between items - * It expects a list of items to display and a label to put on top + * It expects a parent item and relationship type, as well as a label to display on top */ -export class RelatedItemsComponent { +export class RelatedItemsComponent implements OnInit, OnDestroy { /** - * A list of items to display + * The parent of the list of related items to display */ - @Input() items: Item[]; + @Input() parentItem: Item; + + /** + * The label of the relationship type to display + * Used in sending a search request to the REST API + */ + @Input() relationType: string; + + /** + * Default options to start a search request with + * Optional input, should you wish a different page size (or other options) + */ + @Input() options = Object.assign(new FindAllOptions(), { elementsPerPage: 5 }); /** * An i18n label to use as a title for the list (usually describes the relation) */ @Input() label: string; + /** + * Completely hide the component until there's at least one item visible + */ + @HostBinding('class.d-none') hidden = true; + + /** + * The list of related items + */ + items$: Observable>>; + + /** + * Search options for displaying all elements in a list + */ + allOptions = Object.assign(new FindAllOptions(), { elementsPerPage: 9999 }); + /** * The view-mode we're currently on * @type {ElementViewMode} */ - viewMode = ItemViewMode.Element; + viewMode = ViewMode.ListElement; + + /** + * Whether or not the list is currently expanded to show all related items + */ + showingAll = false; + + /** + * Subscription on items used to update the "hidden" property of this component + */ + itemSub: Subscription; + + constructor(public relationshipService: RelationshipService) { + } + + ngOnInit(): void { + this.items$ = this.relationshipService.getRelatedItemsByLabel(this.parentItem, this.relationType, this.options); + this.itemSub = this.items$.subscribe((itemsRD: RemoteData>) => { + this.hidden = !(itemsRD.hasSucceeded && itemsRD.payload && itemsRD.payload.page.length > 0); + }); + } + + /** + * Expand the list to display all related items + */ + viewMore() { + this.items$ = this.relationshipService.getRelatedItemsByLabel(this.parentItem, this.relationType, this.allOptions); + this.showingAll = true; + } + + /** + * Collapse the list to display the originally displayed items + */ + viewLess() { + this.items$ = this.relationshipService.getRelatedItemsByLabel(this.parentItem, this.relationType, this.options); + this.showingAll = false; + } + + /** + * Unsubscribe from the item subscription + */ + ngOnDestroy(): void { + if (this.itemSub) { + this.itemSub.unsubscribe(); + } + } } diff --git a/src/app/+item-page/simple/related-items/related-items.component.html b/src/app/+item-page/simple/related-items/related-items.component.html index 4b284ad63c..bb6c2afdc6 100644 --- a/src/app/+item-page/simple/related-items/related-items.component.html +++ b/src/app/+item-page/simple/related-items/related-items.component.html @@ -1,5 +1,11 @@ - - + - + + + diff --git a/src/app/+item-page/simple/related-items/related-items.component.spec.ts b/src/app/+item-page/simple/related-items/related-items.component.spec.ts index 1896f46015..4a751a31b8 100644 --- a/src/app/+item-page/simple/related-items/related-items.component.spec.ts +++ b/src/app/+item-page/simple/related-items/related-items.component.spec.ts @@ -2,35 +2,50 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; import { RelatedItemsComponent } from './related-items-component'; import { Item } from '../../../core/shared/item.model'; -import { RemoteData } from '../../../core/data/remote-data'; import { PaginatedList } from '../../../core/data/paginated-list'; import { PageInfo } from '../../../core/shared/page-info.model'; import { By } from '@angular/platform-browser'; import { createRelationshipsObservable } from '../item-types/shared/item.component.spec'; -import { of as observableOf } from 'rxjs'; import { createSuccessfulRemoteDataObject$ } from '../../../shared/testing/utils'; +import { RelationshipService } from '../../../core/data/relationship.service'; +import { TranslateModule } from '@ngx-translate/core'; +const parentItem: Item = Object.assign(new Item(), { + bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), + metadata: [], + relationships: createRelationshipsObservable() +}); const mockItem1: Item = Object.assign(new Item(), { - bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), + bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), metadata: [], relationships: createRelationshipsObservable() }); const mockItem2: Item = Object.assign(new Item(), { - bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), + bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), metadata: [], relationships: createRelationshipsObservable() }); const mockItems = [mockItem1, mockItem2]; +const relationType = 'isItemOfItem'; +let relationshipService: RelationshipService; describe('RelatedItemsComponent', () => { let comp: RelatedItemsComponent; let fixture: ComponentFixture; beforeEach(async(() => { + relationshipService = jasmine.createSpyObj('relationshipService', + { + getRelatedItemsByLabel: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), mockItems)), + } + ); + TestBed.configureTestingModule({ - imports: [], + imports: [TranslateModule.forRoot()], declarations: [RelatedItemsComponent], - providers: [], + providers: [ + { provide: RelationshipService, useValue: relationshipService } + ], schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(RelatedItemsComponent, { set: {changeDetection: ChangeDetectionStrategy.Default} @@ -40,13 +55,42 @@ describe('RelatedItemsComponent', () => { beforeEach(async(() => { fixture = TestBed.createComponent(RelatedItemsComponent); comp = fixture.componentInstance; - comp.items = mockItems; + comp.parentItem = parentItem; + comp.relationType = relationType; fixture.detectChanges(); })); it(`should load ${mockItems.length} item-type-switcher components`, () => { - const fields = fixture.debugElement.queryAll(By.css('ds-item-type-switcher')); + const fields = fixture.debugElement.queryAll(By.css('ds-listable-object-component-loader')); expect(fields.length).toBe(mockItems.length); }); + describe('when viewMore is called', () => { + beforeEach(() => { + comp.viewMore(); + }); + + it('should call relationship-service\'s getRelatedItemsByLabel with the correct arguments', () => { + expect(relationshipService.getRelatedItemsByLabel).toHaveBeenCalledWith(parentItem, relationType, comp.allOptions); + }); + + it('should set showingAll to true', () => { + expect(comp.showingAll).toEqual(true); + }); + }); + + describe('when viewLess is called', () => { + beforeEach(() => { + comp.viewLess(); + }); + + it('should call relationship-service\'s getRelatedItemsByLabel with the correct arguments', () => { + expect(relationshipService.getRelatedItemsByLabel).toHaveBeenCalledWith(parentItem, relationType, comp.options); + }); + + it('should set showingAll to false', () => { + expect(comp.showingAll).toEqual(false); + }); + }); + }); diff --git a/src/app/+lookup-by-id/lookup-by-id-routing.module.ts b/src/app/+lookup-by-id/lookup-by-id-routing.module.ts new file mode 100644 index 0000000000..71865dd6c6 --- /dev/null +++ b/src/app/+lookup-by-id/lookup-by-id-routing.module.ts @@ -0,0 +1,43 @@ +import { LookupGuard } from './lookup-guard'; +import { NgModule } from '@angular/core'; +import { RouterModule, UrlSegment } from '@angular/router'; +import { ObjectNotFoundComponent } from './objectnotfound/objectnotfound.component'; +import { hasValue, isNotEmpty } from '../shared/empty.util'; + +@NgModule({ + imports: [ + RouterModule.forChild([ + { + matcher: urlMatcher, + canActivate: [LookupGuard], + component: ObjectNotFoundComponent } + ]) + ], + providers: [ + LookupGuard + ] +}) + +export class LookupRoutingModule { + +} + +export function urlMatcher(url) { + // The expected path is :idType/:id + const idType = url[0].path; + // Allow for handles that are delimited with a forward slash. + const id = url + .slice(1) + .map((us: UrlSegment) => us.path) + .join('/'); + if (isNotEmpty(idType) && isNotEmpty(id)) { + return { + consumed: url, + posParams: { + idType: new UrlSegment(idType, {}), + id: new UrlSegment(id, {}) + } + }; + } + return null; +} diff --git a/src/app/+lookup-by-id/lookup-by-id.module.ts b/src/app/+lookup-by-id/lookup-by-id.module.ts new file mode 100644 index 0000000000..1b070c1279 --- /dev/null +++ b/src/app/+lookup-by-id/lookup-by-id.module.ts @@ -0,0 +1,23 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { SharedModule } from '../shared/shared.module'; +import { LookupRoutingModule } from './lookup-by-id-routing.module'; +import { ObjectNotFoundComponent } from './objectnotfound/objectnotfound.component'; +import { DsoRedirectDataService } from '../core/data/dso-redirect-data.service'; + +@NgModule({ + imports: [ + LookupRoutingModule, + CommonModule, + SharedModule, + ], + declarations: [ + ObjectNotFoundComponent + ], + providers: [ + DsoRedirectDataService + ] +}) +export class LookupIdModule { + +} diff --git a/src/app/+lookup-by-id/lookup-guard.spec.ts b/src/app/+lookup-by-id/lookup-guard.spec.ts new file mode 100644 index 0000000000..dce039eff3 --- /dev/null +++ b/src/app/+lookup-by-id/lookup-guard.spec.ts @@ -0,0 +1,50 @@ +import { LookupGuard } from './lookup-guard'; +import { of as observableOf } from 'rxjs'; +import { IdentifierType } from '../core/data/request.models'; + +describe('LookupGuard', () => { + let dsoService: any; + let guard: any; + + beforeEach(() => { + dsoService = { + findById: jasmine.createSpy('findById').and.returnValue(observableOf({ hasFailed: false, + hasSucceeded: true })) + }; + guard = new LookupGuard(dsoService); + }); + + it('should call findById with handle params', () => { + const scopedRoute = { + params: { + id: '1234', + idType: '123456789' + } + }; + guard.canActivate(scopedRoute as any, undefined); + expect(dsoService.findById).toHaveBeenCalledWith('123456789/1234', IdentifierType.HANDLE) + }); + + it('should call findById with handle params', () => { + const scopedRoute = { + params: { + id: '123456789%2F1234', + idType: 'handle' + } + }; + guard.canActivate(scopedRoute as any, undefined); + expect(dsoService.findById).toHaveBeenCalledWith('123456789%2F1234', IdentifierType.HANDLE) + }); + + it('should call findById with UUID params', () => { + const scopedRoute = { + params: { + id: '34cfed7c-f597-49ef-9cbe-ea351f0023c2', + idType: 'uuid' + } + }; + guard.canActivate(scopedRoute as any, undefined); + expect(dsoService.findById).toHaveBeenCalledWith('34cfed7c-f597-49ef-9cbe-ea351f0023c2', IdentifierType.UUID) + }); + +}); diff --git a/src/app/+lookup-by-id/lookup-guard.ts b/src/app/+lookup-by-id/lookup-guard.ts new file mode 100644 index 0000000000..c89e329241 --- /dev/null +++ b/src/app/+lookup-by-id/lookup-guard.ts @@ -0,0 +1,53 @@ +import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; +import { Injectable } from '@angular/core'; +import { IdentifierType } from '../core/data/request.models'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { RemoteData } from '../core/data/remote-data'; +import { FindByIDRequest } from '../core/data/request.models'; +import { DsoRedirectDataService } from '../core/data/dso-redirect-data.service'; + +interface LookupParams { + type: IdentifierType; + id: string; +} + +@Injectable() +export class LookupGuard implements CanActivate { + + constructor(private dsoService: DsoRedirectDataService) { + } + + canActivate(route: ActivatedRouteSnapshot, state:RouterStateSnapshot): Observable { + const params = this.getLookupParams(route); + return this.dsoService.findById(params.id, params.type).pipe( + map((response: RemoteData) => response.hasFailed) + ); + } + + private getLookupParams(route: ActivatedRouteSnapshot): LookupParams { + let type; + let id; + const idType = route.params.idType; + + // If the idType is not recognized, assume a legacy handle request (handle/prefix/id) + if (idType !== IdentifierType.HANDLE && idType !== IdentifierType.UUID) { + type = IdentifierType.HANDLE; + const prefix = route.params.idType; + const handleId = route.params.id; + id = `${prefix}/${handleId}`; + + } else if (route.params.idType === IdentifierType.HANDLE) { + type = IdentifierType.HANDLE; + id = route.params.id; + + } else { + type = IdentifierType.UUID; + id = route.params.id; + } + return { + type: type, + id: id + }; + } +} diff --git a/src/app/+lookup-by-id/objectnotfound/objectnotfound.component.html b/src/app/+lookup-by-id/objectnotfound/objectnotfound.component.html new file mode 100644 index 0000000000..e1cf58b5b2 --- /dev/null +++ b/src/app/+lookup-by-id/objectnotfound/objectnotfound.component.html @@ -0,0 +1,8 @@ +
+

{{"error.identifier" | translate}}

+

{{missingItem}}

+
+

+ {{"404.link.home-page" | translate}} +

+
diff --git a/src/app/entity-groups/research-entities/item-grid-elements/orgunit/orgunit-grid-element.component.scss b/src/app/+lookup-by-id/objectnotfound/objectnotfound.component.scss similarity index 100% rename from src/app/entity-groups/research-entities/item-grid-elements/orgunit/orgunit-grid-element.component.scss rename to src/app/+lookup-by-id/objectnotfound/objectnotfound.component.scss diff --git a/src/app/+lookup-by-id/objectnotfound/objectnotfound.component.spec.ts b/src/app/+lookup-by-id/objectnotfound/objectnotfound.component.spec.ts new file mode 100644 index 0000000000..7905655a06 --- /dev/null +++ b/src/app/+lookup-by-id/objectnotfound/objectnotfound.component.spec.ts @@ -0,0 +1,79 @@ +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { TranslateModule } from '@ngx-translate/core'; + +import { ObjectNotFoundComponent } from './objectnotfound.component'; +import { ActivatedRouteStub } from '../../shared/testing/active-router-stub'; +import { of as observableOf } from 'rxjs'; +import { ActivatedRoute } from '@angular/router'; + +describe('ObjectNotFoundComponent', () => { + let comp: ObjectNotFoundComponent; + let fixture: ComponentFixture; + const testUUID = '34cfed7c-f597-49ef-9cbe-ea351f0023c2'; + const uuidType = 'uuid'; + const handlePrefix = '123456789'; + const handleId = '22'; + const activatedRouteStub = Object.assign(new ActivatedRouteStub(), { + params: observableOf({id: testUUID, idType: uuidType}) + }); + const activatedRouteStubHandle = Object.assign(new ActivatedRouteStub(), { + params: observableOf({id: handleId, idType: handlePrefix}) + }); + describe('uuid request', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + TranslateModule.forRoot() + ], providers: [ + {provide: ActivatedRoute, useValue: activatedRouteStub} + ], + declarations: [ObjectNotFoundComponent], + schemas: [NO_ERRORS_SCHEMA] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ObjectNotFoundComponent); + comp = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create instance', () => { + expect(comp).toBeDefined() + }); + + it('should have id and idType', () => { + expect(comp.id).toEqual(testUUID); + expect(comp.idType).toEqual(uuidType); + expect(comp.missingItem).toEqual('uuid: ' + testUUID); + }); + }); + + describe( 'legacy handle request', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + TranslateModule.forRoot() + ], providers: [ + {provide: ActivatedRoute, useValue: activatedRouteStubHandle} + ], + declarations: [ObjectNotFoundComponent], + schemas: [NO_ERRORS_SCHEMA] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ObjectNotFoundComponent); + comp = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should have handle prefix and id', () => { + expect(comp.id).toEqual(handleId); + expect(comp.idType).toEqual(handlePrefix); + expect(comp.missingItem).toEqual('handle: ' + handlePrefix + '/' + handleId); + }); + }); + +}); diff --git a/src/app/+lookup-by-id/objectnotfound/objectnotfound.component.ts b/src/app/+lookup-by-id/objectnotfound/objectnotfound.component.ts new file mode 100644 index 0000000000..813b56920a --- /dev/null +++ b/src/app/+lookup-by-id/objectnotfound/objectnotfound.component.ts @@ -0,0 +1,43 @@ + +import { Component, ChangeDetectionStrategy, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +/** + * This component representing the `PageNotFound` DSpace page. + */ +@Component({ + selector: 'ds-objnotfound', + styleUrls: ['./objectnotfound.component.scss'], + templateUrl: './objectnotfound.component.html', + changeDetection: ChangeDetectionStrategy.Default +}) +export class ObjectNotFoundComponent implements OnInit { + + idType: string; + + id: string; + + missingItem: string; + + /** + * Initialize instance variables + * + * @param {AuthService} authservice + * @param {ServerResponseService} responseService + */ + constructor(private route: ActivatedRoute) { + route.params.subscribe((params) => { + this.idType = params.idType; + this.id = params.id; + }) + } + + ngOnInit(): void { + if (this.idType.startsWith('handle') || this.idType.startsWith('uuid')) { + this.missingItem = this.idType + ': ' + this.id; + } else { + this.missingItem = 'handle: ' + this.idType + '/' + this.id; + } + } + +} diff --git a/src/app/+my-dspace-page/my-dspace-new-submission/my-dspace-new-submission.component.ts b/src/app/+my-dspace-page/my-dspace-new-submission/my-dspace-new-submission.component.ts index 938a1ec899..76853db924 100644 --- a/src/app/+my-dspace-page/my-dspace-new-submission/my-dspace-new-submission.component.ts +++ b/src/app/+my-dspace-page/my-dspace-new-submission/my-dspace-new-submission.component.ts @@ -7,7 +7,6 @@ import { TranslateService } from '@ngx-translate/core'; import { SubmissionState } from '../../submission/submission.reducers'; import { AuthService } from '../../core/auth/auth.service'; -import { MyDSpaceResult } from '../my-dspace-result.model'; import { DSpaceObject } from '../../core/shared/dspace-object.model'; import { NotificationsService } from '../../shared/notifications/notifications.service'; import { NotificationOptions } from '../../shared/notifications/models/notification-options.model'; @@ -15,6 +14,7 @@ import { UploaderOptions } from '../../shared/uploader/uploader-options.model'; import { HALEndpointService } from '../../core/shared/hal-endpoint.service'; import { NotificationType } from '../../shared/notifications/models/notification-type'; import { hasValue } from '../../shared/empty.util'; +import { SearchResult } from '../../+search-page/search-result.model'; /** * This component represents the whole mydspace page header @@ -25,7 +25,10 @@ import { hasValue } from '../../shared/empty.util'; templateUrl: './my-dspace-new-submission.component.html' }) export class MyDSpaceNewSubmissionComponent implements OnDestroy, OnInit { - @Output() uploadEnd = new EventEmitter>>(); + /** + * Output that emits the workspace item when the upload has completed + */ + @Output() uploadEnd = new EventEmitter>>(); /** * The UploaderOptions object diff --git a/src/app/+my-dspace-page/my-dspace-page.component.html b/src/app/+my-dspace-page/my-dspace-page.component.html index 4c691028fc..e6d1a5c80d 100644 --- a/src/app/+my-dspace-page/my-dspace-page.component.html +++ b/src/app/+my-dspace-page/my-dspace-page.component.html @@ -39,7 +39,8 @@
+ [searchConfig]="searchOptions$ | async" + [context]="context$ | async">
diff --git a/src/app/+my-dspace-page/my-dspace-page.component.spec.ts b/src/app/+my-dspace-page/my-dspace-page.component.spec.ts index 27daa30a0f..653f4a4844 100644 --- a/src/app/+my-dspace-page/my-dspace-page.component.spec.ts +++ b/src/app/+my-dspace-page/my-dspace-page.component.spec.ts @@ -15,7 +15,6 @@ import { SortDirection, SortOptions } from '../core/cache/models/sort-options.mo import { CommunityDataService } from '../core/data/community-data.service'; import { HostWindowService } from '../shared/host-window.service'; import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model'; -import { RemoteData } from '../core/data/remote-data'; import { MyDSpacePageComponent, SEARCH_CONFIG_SERVICE } from './my-dspace-page.component'; import { RouteService } from '../core/services/route.service'; import { routeServiceStub } from '../shared/testing/route-service-stub'; @@ -50,6 +49,7 @@ describe('MyDSpacePageComponent', () => { const mockResults = createSuccessfulRemoteDataObject$(['test', 'data']); const searchServiceStub = jasmine.createSpyObj('SearchService', { search: mockResults, + getEndpoint: observableOf('discover/search/objects'), getSearchLink: '/mydspace', getScopes: observableOf(['test-scope']), setServiceOptions: {} @@ -76,6 +76,7 @@ describe('MyDSpacePageComponent', () => { scope: scopeParam }) }; + const sidebarService = { isCollapsed: observableOf(true), collapse: () => this.isCollapsed = observableOf(true), diff --git a/src/app/+my-dspace-page/my-dspace-page.component.ts b/src/app/+my-dspace-page/my-dspace-page.component.ts index 251bf50bd1..ced237f682 100644 --- a/src/app/+my-dspace-page/my-dspace-page.component.ts +++ b/src/app/+my-dspace-page/my-dspace-page.component.ts @@ -8,7 +8,7 @@ import { } from '@angular/core'; import { BehaviorSubject, Observable, Subscription } from 'rxjs'; -import { switchMap, tap, } from 'rxjs/operators'; +import { map, switchMap, tap, } from 'rxjs/operators'; import { PaginatedList } from '../core/data/paginated-list'; import { RemoteData } from '../core/data/remote-data'; @@ -20,7 +20,6 @@ import { SearchService } from '../+search-page/search-service/search.service'; import { SearchSidebarService } from '../+search-page/search-sidebar/search-sidebar.service'; import { hasValue } from '../shared/empty.util'; import { getSucceededRemoteData } from '../core/shared/operators'; -import { MyDSpaceResult } from './my-dspace-result.model'; import { MyDSpaceResponseParsingService } from '../core/data/mydspace-response-parsing.service'; import { SearchConfigurationOption } from '../+search-page/search-switch-configuration/search-configuration-option.model'; import { RoleType } from '../core/roles/role-types'; @@ -28,6 +27,8 @@ import { SearchConfigurationService } from '../+search-page/search-service/searc import { MyDSpaceConfigurationService } from './my-dspace-configuration.service'; import { ViewMode } from '../core/shared/view-mode.model'; import { MyDSpaceRequest } from '../core/data/request.models'; +import { SearchResult } from '../+search-page/search-result.model'; +import { Context } from '../core/shared/context.model'; export const MYDSPACE_ROUTE = '/mydspace'; export const SEARCH_CONFIG_SERVICE: InjectionToken = new InjectionToken('searchConfigurationService'); @@ -63,7 +64,7 @@ export class MyDSpacePageComponent implements OnInit { /** * The current search results */ - resultsRD$: BehaviorSubject>>> = new BehaviorSubject(null); + resultsRD$: BehaviorSubject>>> = new BehaviorSubject(null); /** * The current paginated search options @@ -93,7 +94,12 @@ export class MyDSpacePageComponent implements OnInit { /** * List of available view mode */ - viewModeList = [ViewMode.List, ViewMode.Detail]; + viewModeList = [ViewMode.ListElement, ViewMode.DetailedListElement]; + + /** + * The current context of this page: workspace or workflow + */ + context$: Observable; constructor(private service: SearchService, private sidebarService: SearchSidebarService, @@ -111,21 +117,35 @@ export class MyDSpacePageComponent implements OnInit { * * Listen to changes in the scope * If something changes, update the list of scopes for the dropdown + * + * Listen to changes in the configuration + * If something changes, update the current context */ ngOnInit(): void { this.configurationList$ = this.searchConfigService.getAvailableConfigurationOptions(); this.searchOptions$ = this.searchConfigService.paginatedSearchOptions; - this.sub = this.searchOptions$.pipe( tap(() => this.resultsRD$.next(null)), switchMap((options: PaginatedSearchOptions) => this.service.search(options).pipe(getSucceededRemoteData()))) .subscribe((results) => { this.resultsRD$.next(results); }); + this.scopeListRD$ = this.searchConfigService.getCurrentScope('').pipe( switchMap((scopeId) => this.service.getScopes(scopeId)) ); + this.context$ = this.searchConfigService.getCurrentConfiguration('workspace') + .pipe( + map((configuration: string) => { + if (configuration === 'workspace') { + return Context.Workspace + } else { + return Context.Workflow + } + }) + ); + } /** diff --git a/src/app/+my-dspace-page/my-dspace-page.module.ts b/src/app/+my-dspace-page/my-dspace-page.module.ts index 4b8cf37b7a..be14aebdea 100644 --- a/src/app/+my-dspace-page/my-dspace-page.module.ts +++ b/src/app/+my-dspace-page/my-dspace-page.module.ts @@ -7,19 +7,20 @@ import { MyDspacePageRoutingModule } from './my-dspace-page-routing.module'; import { MyDSpacePageComponent } from './my-dspace-page.component'; import { SearchPageModule } from '../+search-page/search-page.module'; import { MyDSpaceResultsComponent } from './my-dspace-results/my-dspace-results.component'; -import { WorkspaceitemMyDSpaceResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component'; -import { ItemMyDSpaceResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/item-my-dspace-result/item-my-dspace-result-list-element.component'; -import { WorkflowitemMyDSpaceResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-list-element.component'; -import { ClaimedMyDSpaceResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/claimed-my-dspace-result/claimed-my-dspace-result-list-element.component'; -import { PoolMyDSpaceResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/pool-my-dspace-result/pool-my-dspace-result-list-element.component'; +import { WorkspaceItemSearchResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component'; +import { ClaimedSearchResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-search-result-list-element.component'; +import { PoolSearchResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/pool-search-result/pool-search-result-list-element.component'; import { MyDSpaceNewSubmissionComponent } from './my-dspace-new-submission/my-dspace-new-submission.component'; -import { ItemMyDSpaceResultDetailElementComponent } from '../shared/object-detail/my-dspace-result-detail-element/item-my-dspace-result/item-my-dspace-result-detail-element.component'; -import { WorkspaceitemMyDSpaceResultDetailElementComponent } from '../shared/object-detail/my-dspace-result-detail-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component'; -import { WorkflowitemMyDSpaceResultDetailElementComponent } from '../shared/object-detail/my-dspace-result-detail-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-detail-element.component'; -import { ClaimedMyDSpaceResultDetailElementComponent } from '../shared/object-detail/my-dspace-result-detail-element/claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component'; -import { PoolMyDSpaceResultDetailElementComponent } from '../shared/object-detail/my-dspace-result-detail-element/pool-my-dspace-result/pool-my-dspace-result-detail-lement.component'; +import { ItemSearchResultDetailElementComponent } from '../shared/object-detail/my-dspace-result-detail-element/item-search-result/item-search-result-detail-element.component'; +import { WorkspaceItemSearchResultDetailElementComponent } from '../shared/object-detail/my-dspace-result-detail-element/workspace-item-search-result/workspace-item-search-result-detail-element.component'; +import { WorkflowItemSearchResultDetailElementComponent } from '../shared/object-detail/my-dspace-result-detail-element/workflow-item-search-result/workflow-item-search-result-detail-element.component'; +import { ClaimedTaskSearchResultDetailElementComponent } from '../shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component'; import { MyDSpaceGuard } from './my-dspace.guard'; import { MyDSpaceConfigurationService } from './my-dspace-configuration.service'; +import { SearchResultListElementComponent } from '../shared/object-list/search-result-list-element/search-result-list-element.component'; +import { ItemSearchResultListElementSubmissionComponent } from '../shared/object-list/my-dspace-result-list-element/item-search-result/item-search-result-list-element-submission.component'; +import { WorkflowItemSearchResultListElementComponent } from '../shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component'; +import { PoolSearchResultDetailElementComponent } from '../shared/object-detail/my-dspace-result-detail-element/pool-search-result/pool-search-result-detail-element.component'; @NgModule({ imports: [ @@ -31,33 +32,34 @@ import { MyDSpaceConfigurationService } from './my-dspace-configuration.service' declarations: [ MyDSpacePageComponent, MyDSpaceResultsComponent, - ItemMyDSpaceResultListElementComponent, - WorkspaceitemMyDSpaceResultListElementComponent, - WorkflowitemMyDSpaceResultListElementComponent, - ClaimedMyDSpaceResultListElementComponent, - PoolMyDSpaceResultListElementComponent, - ItemMyDSpaceResultDetailElementComponent, - WorkspaceitemMyDSpaceResultDetailElementComponent, - WorkflowitemMyDSpaceResultDetailElementComponent, - ClaimedMyDSpaceResultDetailElementComponent, - PoolMyDSpaceResultDetailElementComponent, - MyDSpaceNewSubmissionComponent + WorkspaceItemSearchResultListElementComponent, + WorkflowItemSearchResultListElementComponent, + ClaimedSearchResultListElementComponent, + PoolSearchResultListElementComponent, + ItemSearchResultDetailElementComponent, + WorkspaceItemSearchResultDetailElementComponent, + WorkflowItemSearchResultDetailElementComponent, + ClaimedTaskSearchResultDetailElementComponent, + PoolSearchResultDetailElementComponent, + MyDSpaceNewSubmissionComponent, + ItemSearchResultListElementSubmissionComponent ], providers: [ MyDSpaceGuard, MyDSpaceConfigurationService ], entryComponents: [ - ItemMyDSpaceResultListElementComponent, - WorkspaceitemMyDSpaceResultListElementComponent, - WorkflowitemMyDSpaceResultListElementComponent, - ClaimedMyDSpaceResultListElementComponent, - PoolMyDSpaceResultListElementComponent, - ItemMyDSpaceResultDetailElementComponent, - WorkspaceitemMyDSpaceResultDetailElementComponent, - WorkflowitemMyDSpaceResultDetailElementComponent, - ClaimedMyDSpaceResultDetailElementComponent, - PoolMyDSpaceResultDetailElementComponent + SearchResultListElementComponent, + WorkspaceItemSearchResultListElementComponent, + WorkflowItemSearchResultListElementComponent, + ClaimedSearchResultListElementComponent, + PoolSearchResultListElementComponent, + ItemSearchResultDetailElementComponent, + WorkspaceItemSearchResultDetailElementComponent, + WorkflowItemSearchResultDetailElementComponent, + ClaimedTaskSearchResultDetailElementComponent, + PoolSearchResultDetailElementComponent, + ItemSearchResultListElementSubmissionComponent ] }) diff --git a/src/app/+my-dspace-page/my-dspace-result.model.ts b/src/app/+my-dspace-page/my-dspace-result.model.ts deleted file mode 100644 index d300ed0bc8..0000000000 --- a/src/app/+my-dspace-page/my-dspace-result.model.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { DSpaceObject } from '../core/shared/dspace-object.model'; -import { MetadataMap } from '../core/shared/metadata.models'; -import { ListableObject } from '../shared/object-collection/shared/listable-object.model'; - -/** - * Represents a search result object of a certain () DSpaceObject - */ -export class MyDSpaceResult implements ListableObject { - /** - * The DSpaceObject that was found - */ - indexableObject: T; - - /** - * The metadata that was used to find this item, hithighlighted - */ - hitHighlights: MetadataMap; - -} diff --git a/src/app/+my-dspace-page/my-dspace-results/my-dspace-results.component.html b/src/app/+my-dspace-page/my-dspace-results/my-dspace-results.component.html index 132a0d2204..63eb0ff9a7 100644 --- a/src/app/+my-dspace-page/my-dspace-results/my-dspace-results.component.html +++ b/src/app/+my-dspace-page/my-dspace-results/my-dspace-results.component.html @@ -4,7 +4,8 @@ [hasBorder]="hasBorder" [sortConfig]="searchConfig.sort" [objects]="searchResults" - [hideGear]="true"> + [hideGear]="true" + [context]="context">
diff --git a/src/app/+my-dspace-page/my-dspace-results/my-dspace-results.component.ts b/src/app/+my-dspace-page/my-dspace-results/my-dspace-results.component.ts index 3a16def9c1..91c206fc79 100644 --- a/src/app/+my-dspace-page/my-dspace-results/my-dspace-results.component.ts +++ b/src/app/+my-dspace-page/my-dspace-results/my-dspace-results.component.ts @@ -1,13 +1,13 @@ import { Component, Input } from '@angular/core'; - import { RemoteData } from '../../core/data/remote-data'; import { DSpaceObject } from '../../core/shared/dspace-object.model'; import { fadeIn, fadeInOut } from '../../shared/animations/fade'; -import { MyDSpaceResult } from '../my-dspace-result.model'; import { SearchOptions } from '../../+search-page/search-options.model'; import { PaginatedList } from '../../core/data/paginated-list'; import { ViewMode } from '../../core/shared/view-mode.model'; import { isEmpty } from '../../shared/empty.util'; +import { SearchResult } from '../../+search-page/search-result.model'; +import { Context } from '../../core/shared/context.model'; /** * Component that represents all results for mydspace page @@ -25,7 +25,7 @@ export class MyDSpaceResultsComponent { /** * The actual search result objects */ - @Input() searchResults: RemoteData>>; + @Input() searchResults: RemoteData>>; /** * The current configuration of the search @@ -37,6 +37,10 @@ export class MyDSpaceResultsComponent { */ @Input() viewMode: ViewMode; + /** + * The current context for the search results + */ + @Input() context: Context; /** * A boolean representing if search results entry are separated by a line */ diff --git a/src/app/+search-page/normalized-search-result.model.ts b/src/app/+search-page/normalized-search-result.model.ts index abb5f21250..8b1c015fef 100644 --- a/src/app/+search-page/normalized-search-result.model.ts +++ b/src/app/+search-page/normalized-search-result.model.ts @@ -1,13 +1,12 @@ import { autoserialize, inheritSerialization } from 'cerialize'; import { MetadataMap } from '../core/shared/metadata.models'; -import { ListableObject } from '../shared/object-collection/shared/listable-object.model'; import { NormalizedObject } from '../core/cache/models/normalized-object.model'; /** * Represents a normalized version of a search result object of a certain DSpaceObject */ @inheritSerialization(NormalizedObject) -export class NormalizedSearchResult implements ListableObject { +export class NormalizedSearchResult { /** * The UUID of the DSpaceObject that was found */ @@ -19,5 +18,4 @@ export class NormalizedSearchResult implements ListableObject { */ @autoserialize hitHighlights: MetadataMap; - } diff --git a/src/app/+search-page/search-filters/search-filters.component.ts b/src/app/+search-page/search-filters/search-filters.component.ts index 9d0dfceb15..69bbb6234b 100644 --- a/src/app/+search-page/search-filters/search-filters.component.ts +++ b/src/app/+search-page/search-filters/search-filters.component.ts @@ -71,7 +71,7 @@ export class SearchFiltersComponent implements OnInit { /** * @returns {string} The base path to the search page, or the current page when inPlaceSearch is true */ - private getSearchLink(): string { + getSearchLink(): string { if (this.inPlaceSearch) { return './'; } diff --git a/src/app/+search-page/search-options.model.ts b/src/app/+search-page/search-options.model.ts index 2b18854e1e..4117c13347 100644 --- a/src/app/+search-page/search-options.model.ts +++ b/src/app/+search-page/search-options.model.ts @@ -3,14 +3,14 @@ import { URLCombiner } from '../core/url-combiner/url-combiner'; import 'core-js/library/fn/object/entries'; import { SearchFilter } from './search-filter.model'; import { DSpaceObjectType } from '../core/shared/dspace-object-type.model'; -import { SetViewMode } from '../shared/view-mode'; +import { ViewMode } from '../core/shared/view-mode.model'; /** * This model class represents all parameters needed to request information about a certain search request */ export class SearchOptions { configuration?: string; - view?: SetViewMode = SetViewMode.List; + view?: ViewMode = ViewMode.ListElement; scope?: string; query?: string; dsoType?: DSpaceObjectType; diff --git a/src/app/+search-page/search-page.module.ts b/src/app/+search-page/search-page.module.ts index 6ca449460b..f4c665d06e 100644 --- a/src/app/+search-page/search-page.module.ts +++ b/src/app/+search-page/search-page.module.ts @@ -5,7 +5,6 @@ import { SharedModule } from '../shared/shared.module'; import { SearchPageRoutingModule } from './search-page-routing.module'; import { SearchPageComponent } from './search-page.component'; import { SearchResultsComponent } from './search-results/search-results.component'; -import { ItemSearchResultGridElementComponent } from '../shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component'; import { CommunitySearchResultGridElementComponent } from '../shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component' import { CollectionSearchResultGridElementComponent } from '../shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component'; import { SearchSidebarComponent } from './search-sidebar/search-sidebar.component'; @@ -44,9 +43,6 @@ const components = [ SearchResultsComponent, SearchSidebarComponent, SearchSettingsComponent, - ItemSearchResultGridElementComponent, - CollectionSearchResultGridElementComponent, - CommunitySearchResultGridElementComponent, SearchFiltersComponent, SearchFilterComponent, SearchFacetFilterComponent, @@ -84,9 +80,6 @@ const components = [ SearchConfigurationService ], entryComponents: [ - ItemSearchResultGridElementComponent, - CollectionSearchResultGridElementComponent, - CommunitySearchResultGridElementComponent, SearchFacetFilterComponent, SearchRangeFilterComponent, SearchTextFilterComponent, diff --git a/src/app/+search-page/search-result.model.ts b/src/app/+search-page/search-result.model.ts index 0354edbc6b..95359209d9 100644 --- a/src/app/+search-page/search-result.model.ts +++ b/src/app/+search-page/search-result.model.ts @@ -1,6 +1,7 @@ import { DSpaceObject } from '../core/shared/dspace-object.model'; import { MetadataMap } from '../core/shared/metadata.models'; import { ListableObject } from '../shared/object-collection/shared/listable-object.model'; +import { GenericConstructor } from '../core/shared/generic-constructor'; /** * Represents a search result object of a certain () DSpaceObject @@ -16,4 +17,10 @@ export class SearchResult implements ListableObject { */ hitHighlights: MetadataMap; + /** + * Method that returns as which type of object this object should be rendered + */ + getRenderTypes(): Array> { + return [this.constructor as GenericConstructor]; + } } diff --git a/src/app/+search-page/search-results/search-results.component.html b/src/app/+search-page/search-results/search-results.component.html index 5a1e89858b..c08a4f023f 100644 --- a/src/app/+search-page/search-results/search-results.component.html +++ b/src/app/+search-page/search-results/search-results.component.html @@ -4,6 +4,7 @@ [config]="searchConfig.pagination" [sortConfig]="searchConfig.sort" [objects]="searchResults" + [linkType]="linkType" [hideGear]="true">
diff --git a/src/app/+search-page/search-results/search-results.component.ts b/src/app/+search-page/search-results/search-results.component.ts index 0ad1fd46bf..24c973e296 100644 --- a/src/app/+search-page/search-results/search-results.component.ts +++ b/src/app/+search-page/search-results/search-results.component.ts @@ -2,12 +2,13 @@ import { Component, Input } from '@angular/core'; import { RemoteData } from '../../core/data/remote-data'; import { DSpaceObject } from '../../core/shared/dspace-object.model'; import { fadeIn, fadeInOut } from '../../shared/animations/fade'; -import { SetViewMode } from '../../shared/view-mode'; import { SearchOptions } from '../search-options.model'; import { SearchResult } from '../search-result.model'; import { PaginatedList } from '../../core/data/paginated-list'; import { hasNoValue, isNotEmpty } from '../../shared/empty.util'; import { SortOptions } from '../../core/cache/models/sort-options.model'; +import { ViewMode } from '../../core/shared/view-mode.model'; +import { CollectionElementLinkType } from '../../shared/object-collection/collection-element-link.type'; @Component({ selector: 'ds-search-results', @@ -24,6 +25,11 @@ import { SortOptions } from '../../core/cache/models/sort-options.model'; export class SearchResultsComponent { hasNoValue = hasNoValue; + /** + * The link type of the listed search results + */ + @Input() linkType: CollectionElementLinkType; + /** * The actual search result objects */ @@ -42,7 +48,7 @@ export class SearchResultsComponent { /** * The current view-mode of the list */ - @Input() viewMode: SetViewMode; + @Input() viewMode: ViewMode; /** * An optional configuration to filter the result on one type diff --git a/src/app/+search-page/search-service/search-result-element-decorator.ts b/src/app/+search-page/search-service/search-result-element-decorator.ts index e804a5d8ee..62887387c5 100644 --- a/src/app/+search-page/search-service/search-result-element-decorator.ts +++ b/src/app/+search-page/search-service/search-result-element-decorator.ts @@ -12,19 +12,12 @@ const searchResultMap = new Map(); * @param {GenericConstructor} domainConstructor The constructor of the DSpaceObject * @returns Decorator function that performs the actual mapping on initialization of the component */ -export function searchResultFor(domainConstructor: GenericConstructor, configuration: string = null) { +export function searchResultFor(domainConstructor: GenericConstructor) { return function decorator(searchResult: any) { if (!searchResult) { return; } - if (isNull(configuration)) { - searchResultMap.set(domainConstructor, searchResult); - } else { - if (!searchResultMap.get(configuration)) { - searchResultMap.set(configuration, new Map()); - } - searchResultMap.get(configuration).set(domainConstructor, searchResult); - } + searchResultMap.set(domainConstructor, searchResult); }; } @@ -33,10 +26,6 @@ export function searchResultFor(domainConstructor: GenericConstructor} domainConstructor The DSpaceObject's constructor for which the search result component is requested * @returns The component's constructor that matches the given DSpaceObject */ -export function getSearchResultFor(domainConstructor: GenericConstructor, configuration: string = null) { - if (isNull(configuration) || configuration === 'default' || hasNoValue(searchResultMap.get(configuration))) { +export function getSearchResultFor(domainConstructor: GenericConstructor) { return searchResultMap.get(domainConstructor); - } else { - return searchResultMap.get(configuration).get(domainConstructor); - } } diff --git a/src/app/+search-page/search-service/search.service.spec.ts b/src/app/+search-page/search-service/search.service.spec.ts index 798670a0e0..4f91dde312 100644 --- a/src/app/+search-page/search-service/search.service.spec.ts +++ b/src/app/+search-page/search-service/search.service.spec.ts @@ -5,9 +5,6 @@ import { CommonModule } from '@angular/common'; import { Component } from '@angular/core'; import { SearchService } from './search.service'; -import { ItemDataService } from './../../core/data/item-data.service'; -import { SetViewMode } from '../../shared/view-mode'; -import { GLOBAL_CONFIG } from '../../../config'; import { RemoteDataBuildService } from '../../core/cache/builders/remote-data-build.service'; import { Router, UrlTree } from '@angular/router'; import { RequestService } from '../../core/data/request.service'; @@ -66,7 +63,7 @@ describe('SearchService', () => { it('should return list view mode', () => { searchService.getViewMode().subscribe((viewMode) => { - expect(viewMode).toBe(ViewMode.List); + expect(viewMode).toBe(ViewMode.ListElement); }); }); }); @@ -125,38 +122,38 @@ describe('SearchService', () => { }); it('should call the navigate method on the Router with view mode list parameter as a parameter when setViewMode is called', () => { - searchService.setViewMode(ViewMode.List); + searchService.setViewMode(ViewMode.ListElement); expect(router.navigate).toHaveBeenCalledWith(['/search'], { - queryParams: { view: ViewMode.List, page: 1 }, + queryParams: { view: ViewMode.ListElement, page: 1 }, queryParamsHandling: 'merge' }); }); it('should call the navigate method on the Router with view mode grid parameter as a parameter when setViewMode is called', () => { - searchService.setViewMode(ViewMode.Grid); + searchService.setViewMode(ViewMode.GridElement); expect(router.navigate).toHaveBeenCalledWith(['/search'], { - queryParams: { view: ViewMode.Grid, page: 1 }, + queryParams: { view: ViewMode.GridElement, page: 1 }, queryParamsHandling: 'merge' }); }); it('should return ViewMode.List when the viewMode is set to ViewMode.List in the ActivatedRoute', () => { - let viewMode = ViewMode.Grid; + let viewMode = ViewMode.GridElement; spyOn(routeService, 'getQueryParamMap').and.returnValue(observableOf(new Map([ - [ 'view', ViewMode.List ], + [ 'view', ViewMode.ListElement ], ]))); searchService.getViewMode().subscribe((mode) => viewMode = mode); - expect(viewMode).toEqual(ViewMode.List); + expect(viewMode).toEqual(ViewMode.ListElement); }); it('should return ViewMode.Grid when the viewMode is set to ViewMode.Grid in the ActivatedRoute', () => { - let viewMode = ViewMode.List; + let viewMode = ViewMode.ListElement; spyOn(routeService, 'getQueryParamMap').and.returnValue(observableOf(new Map([ - [ 'view', ViewMode.Grid ], + [ 'view', ViewMode.GridElement ], ]))); searchService.getViewMode().subscribe((mode) => viewMode = mode); - expect(viewMode).toEqual(ViewMode.Grid); + expect(viewMode).toEqual(ViewMode.GridElement); }); describe('when search is called', () => { diff --git a/src/app/+search-page/search-service/search.service.ts b/src/app/+search-page/search-service/search.service.ts index bedae84eaa..d013d9cc64 100644 --- a/src/app/+search-page/search-service/search.service.ts +++ b/src/app/+search-page/search-service/search.service.ts @@ -97,14 +97,8 @@ export class SearchService implements OnDestroy { } } - /** - * Method to retrieve a paginated list of search results from the server - * @param {PaginatedSearchOptions} searchOptions The configuration necessary to perform this search - * @param responseMsToLive The amount of milliseconds for the response to live in cache - * @returns {Observable>>>} Emits a paginated list with all search results found - */ - search(searchOptions?: PaginatedSearchOptions, responseMsToLive?: number): Observable>>> { - const hrefObs = this.halService.getEndpoint(this.searchLinkPath).pipe( + getEndpoint(searchOptions?: PaginatedSearchOptions): Observable { + return this.halService.getEndpoint(this.searchLinkPath).pipe( map((url: string) => { if (hasValue(searchOptions)) { return (searchOptions as PaginatedSearchOptions).toRestUrl(url); @@ -113,6 +107,17 @@ export class SearchService implements OnDestroy { } }) ); + } + + /** + * Method to retrieve a paginated list of search results from the server + * @param {PaginatedSearchOptions} searchOptions The configuration necessary to perform this search + * @param responseMsToLive The amount of milliseconds for the response to live in cache + * @returns {Observable>>>} Emits a paginated list with all search results found + */ + search(searchOptions?: PaginatedSearchOptions, responseMsToLive?: number): Observable>>> { + + const hrefObs = this.getEndpoint(searchOptions); const requestObs = hrefObs.pipe( map((url: string) => { @@ -160,7 +165,7 @@ export class SearchService implements OnDestroy { let co = DSpaceObject; if (dsos.payload[index]) { const constructor: GenericConstructor = dsos.payload[index].constructor as GenericConstructor; - co = getSearchResultFor(constructor, searchOptions.configuration); + co = getSearchResultFor(constructor); return Object.assign(new co(), object, { indexableObject: dsos.payload[index] }); @@ -341,7 +346,7 @@ export class SearchService implements OnDestroy { if (isNotEmpty(params.get('view')) && hasValue(params.get('view'))) { return params.get('view'); } else { - return ViewMode.List; + return ViewMode.ListElement; } })); } @@ -354,7 +359,7 @@ export class SearchService implements OnDestroy { this.routeService.getQueryParameterValue('pageSize').pipe(first()) .subscribe((pageSize) => { let queryParams = { view: viewMode, page: 1 }; - if (viewMode === ViewMode.Detail) { + if (viewMode === ViewMode.DetailedListElement) { queryParams = Object.assign(queryParams, {pageSize: '1'}); } else if (pageSize === '1') { queryParams = Object.assign(queryParams, {pageSize: '10'}); diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index e1ddc2b889..5085633a5b 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -27,6 +27,8 @@ export function getAdminModulePath() { RouterModule.forRoot([ { path: '', redirectTo: '/home', pathMatch: 'full' }, { path: 'home', loadChildren: './+home-page/home-page.module#HomePageModule' }, + { path: 'id', loadChildren: './+lookup-by-id/lookup-by-id.module#LookupIdModule' }, + { path: 'handle', loadChildren: './+lookup-by-id/lookup-by-id.module#LookupIdModule' }, { path: COMMUNITY_MODULE_PATH, loadChildren: './+community-page/community-page.module#CommunityPageModule' }, { path: COLLECTION_MODULE_PATH, loadChildren: './+collection-page/collection-page.module#CollectionPageModule' }, { path: ITEM_MODULE_PATH, loadChildren: './+item-page/item-page.module#ItemPageModule' }, diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 916788df8c..3d8bf0ed43 100755 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -128,7 +128,7 @@ const EXPORTS = [ ...PROVIDERS ], declarations: [ - ...DECLARATIONS, + ...DECLARATIONS ], exports: [ ...EXPORTS diff --git a/src/app/core/auth/auth-request.service.ts b/src/app/core/auth/auth-request.service.ts index cbabe5c3fd..8773b1a9fb 100644 --- a/src/app/core/auth/auth-request.service.ts +++ b/src/app/core/auth/auth-request.service.ts @@ -44,7 +44,11 @@ export class AuthRequestService { map((endpointURL) => this.getEndpointByMethod(endpointURL, method)), distinctUntilChanged(), map((endpointURL: string) => new AuthPostRequest(this.requestService.generateRequestId(), endpointURL, body, options)), - tap((request: PostRequest) => this.requestService.configure(request, true)), + map ((request: PostRequest) => { + request.responseMsToLive = 10 * 1000; + return request; + }), + tap((request: PostRequest) => this.requestService.configure(request)), mergeMap((request: PostRequest) => this.fetchRequest(request)), distinctUntilChanged()); } @@ -55,7 +59,11 @@ export class AuthRequestService { map((endpointURL) => this.getEndpointByMethod(endpointURL, method)), distinctUntilChanged(), map((endpointURL: string) => new AuthGetRequest(this.requestService.generateRequestId(), endpointURL, options)), - tap((request: GetRequest) => this.requestService.configure(request, true)), + map ((request: GetRequest) => { + request.responseMsToLive = 10 * 1000; + return request; + }), + tap((request: GetRequest) => this.requestService.configure(request)), mergeMap((request: GetRequest) => this.fetchRequest(request)), distinctUntilChanged()); } diff --git a/src/app/core/auth/auth-response-parsing.service.ts b/src/app/core/auth/auth-response-parsing.service.ts index a5a160531c..8137734c49 100644 --- a/src/app/core/auth/auth-response-parsing.service.ts +++ b/src/app/core/auth/auth-response-parsing.service.ts @@ -25,7 +25,7 @@ export class AuthResponseParsingService extends BaseResponseParsingService imple parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse { if (isNotEmpty(data.payload) && isNotEmpty(data.payload._links) && (data.statusCode === 200)) { - const response = this.process>(data.payload, request.uuid); + const response = this.process>(data.payload, request); return new AuthStatusResponse(response, data.statusCode, data.statusText); } else { return new AuthStatusResponse(data.payload as NormalizedAuthStatus, data.statusCode, data.statusText); diff --git a/src/app/core/auth/auth.service.spec.ts b/src/app/core/auth/auth.service.spec.ts index 5084dc8596..86794f257b 100644 --- a/src/app/core/auth/auth.service.spec.ts +++ b/src/app/core/auth/auth.service.spec.ts @@ -249,30 +249,34 @@ describe('AuthService test', () => { it ('should set redirect url to previous page', () => { spyOn(routeServiceMock, 'getHistory').and.callThrough(); + spyOn(routerStub, 'navigateByUrl'); authService.redirectAfterLoginSuccess(true); expect(routeServiceMock.getHistory).toHaveBeenCalled(); - expect(routerStub.navigate).toHaveBeenCalledWith(['/collection/123']); + expect(routerStub.navigateByUrl).toHaveBeenCalledWith('/collection/123'); }); it ('should set redirect url to current page', () => { spyOn(routeServiceMock, 'getHistory').and.callThrough(); + spyOn(routerStub, 'navigateByUrl'); authService.redirectAfterLoginSuccess(false); expect(routeServiceMock.getHistory).toHaveBeenCalled(); - expect(routerStub.navigate).toHaveBeenCalledWith(['/home']); + expect(routerStub.navigateByUrl).toHaveBeenCalledWith('/home'); }); it ('should redirect to / and not to /login', () => { spyOn(routeServiceMock, 'getHistory').and.returnValue(observableOf(['/login', '/login'])); + spyOn(routerStub, 'navigateByUrl'); authService.redirectAfterLoginSuccess(true); expect(routeServiceMock.getHistory).toHaveBeenCalled(); - expect(routerStub.navigate).toHaveBeenCalledWith(['/']); + expect(routerStub.navigateByUrl).toHaveBeenCalledWith('/'); }); it ('should redirect to / when no redirect url is found', () => { spyOn(routeServiceMock, 'getHistory').and.returnValue(observableOf([''])); + spyOn(routerStub, 'navigateByUrl'); authService.redirectAfterLoginSuccess(true); expect(routeServiceMock.getHistory).toHaveBeenCalled(); - expect(routerStub.navigate).toHaveBeenCalledWith(['/']); + expect(routerStub.navigateByUrl).toHaveBeenCalledWith('/'); }); }); }); diff --git a/src/app/core/auth/auth.service.ts b/src/app/core/auth/auth.service.ts index 5287e537ee..94b1e9e6ff 100644 --- a/src/app/core/auth/auth.service.ts +++ b/src/app/core/auth/auth.service.ts @@ -347,8 +347,7 @@ export class AuthService { if (isNotEmpty(redirectUrl)) { this.clearRedirectUrl(); this.router.onSameUrlNavigation = 'reload'; - const url = decodeURIComponent(redirectUrl); - this.navigateToRedirectUrl(url); + this.navigateToRedirectUrl(redirectUrl); } else { // If redirectUrl is empty use history. this.routeService.getHistory().pipe( @@ -368,16 +367,17 @@ export class AuthService { } - protected navigateToRedirectUrl(url: string) { + protected navigateToRedirectUrl(redirectUrl: string) { + const url = decodeURIComponent(redirectUrl); // in case the user navigates directly to /login (via bookmark, etc), or the route history is not found. if (isEmpty(url) || url.startsWith(LOGIN_ROUTE)) { - this.router.navigate(['/']); + this.router.navigateByUrl('/'); /* TODO Reenable hard redirect when REST API can handle x-forwarded-for, see https://github.com/DSpace/DSpace/pull/2207 */ // this._window.nativeWindow.location.href = '/'; } else { /* TODO Reenable hard redirect when REST API can handle x-forwarded-for, see https://github.com/DSpace/DSpace/pull/2207 */ // this._window.nativeWindow.location.href = url; - this.router.navigate([url]); + this.router.navigateByUrl(url); } } diff --git a/src/app/core/browse/browse.service.spec.ts b/src/app/core/browse/browse.service.spec.ts index 725b371c14..55ff7a090e 100644 --- a/src/app/core/browse/browse.service.spec.ts +++ b/src/app/core/browse/browse.service.spec.ts @@ -114,7 +114,7 @@ describe('BrowseService', () => { scheduler.schedule(() => service.getBrowseDefinitions().subscribe()); scheduler.flush(); - expect(requestService.configure).toHaveBeenCalledWith(expected, undefined); + expect(requestService.configure).toHaveBeenCalledWith(expected); }); it('should call RemoteDataBuildService to create the RemoteData Observable', () => { @@ -155,7 +155,7 @@ describe('BrowseService', () => { scheduler.schedule(() => service.getBrowseEntriesFor(new BrowseEntrySearchOptions(browseDefinitions[1].id)).subscribe()); scheduler.flush(); - expect(requestService.configure).toHaveBeenCalledWith(expected, undefined); + expect(requestService.configure).toHaveBeenCalledWith(expected); }); it('should call RemoteDataBuildService to create the RemoteData Observable', () => { @@ -174,7 +174,7 @@ describe('BrowseService', () => { scheduler.schedule(() => service.getBrowseItemsFor(mockAuthorName, new BrowseEntrySearchOptions(browseDefinitions[1].id)).subscribe()); scheduler.flush(); - expect(requestService.configure).toHaveBeenCalledWith(expected, undefined); + expect(requestService.configure).toHaveBeenCalledWith(expected); }); it('should call RemoteDataBuildService to create the RemoteData Observable', () => { @@ -303,7 +303,7 @@ describe('BrowseService', () => { scheduler.schedule(() => service.getFirstItemFor(browseDefinitions[1].id).subscribe()); scheduler.flush(); - expect(requestService.configure).toHaveBeenCalledWith(expected, undefined); + expect(requestService.configure).toHaveBeenCalledWith(expected); }); it('should call RemoteDataBuildService to create the RemoteData Observable', () => { diff --git a/src/app/core/cache/object-cache.reducer.ts b/src/app/core/cache/object-cache.reducer.ts index f41151fd90..afc040bf59 100644 --- a/src/app/core/cache/object-cache.reducer.ts +++ b/src/app/core/cache/object-cache.reducer.ts @@ -44,6 +44,7 @@ export abstract class TypedObject { */ export class CacheableObject extends TypedObject { uuid?: string; + handle?: string; self: string; // isNew: boolean; // dirtyType: DirtyType; diff --git a/src/app/core/cache/object-cache.service.ts b/src/app/core/cache/object-cache.service.ts index 11f3a6ce3e..e12629fa27 100644 --- a/src/app/core/cache/object-cache.service.ts +++ b/src/app/core/cache/object-cache.service.ts @@ -4,7 +4,7 @@ import { applyPatch, Operation } from 'fast-json-patch'; import { combineLatest as observableCombineLatest, Observable } from 'rxjs'; import { distinctUntilChanged, filter, map, mergeMap, take, } from 'rxjs/operators'; -import { hasNoValue, hasValue, isNotEmpty } from '../../shared/empty.util'; +import { hasNoValue, isNotEmpty } from '../../shared/empty.util'; import { CoreState } from '../core.reducers'; import { coreSelector } from '../core.selectors'; import { RestRequestMethod } from '../data/rest-request-method'; @@ -80,7 +80,8 @@ export class ObjectCacheService { * @return Observable> * An observable of the requested object in normalized form */ - getObjectByUUID(uuid: string): Observable> { + getObjectByUUID(uuid: string): + Observable> { return this.store.pipe( select(selfLinkFromUuidSelector(uuid)), mergeMap((selfLink: string) => this.getObjectBySelfLink(selfLink) diff --git a/src/app/core/config/config-response-parsing.service.ts b/src/app/core/config/config-response-parsing.service.ts index 08fe581406..d1f49710d3 100644 --- a/src/app/core/config/config-response-parsing.service.ts +++ b/src/app/core/config/config-response-parsing.service.ts @@ -24,7 +24,7 @@ export class ConfigResponseParsingService extends BaseResponseParsingService imp parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse { if (isNotEmpty(data.payload) && isNotEmpty(data.payload._links) && (data.statusCode === 201 || data.statusCode === 200)) { - const configDefinition = this.process(data.payload, request.uuid); + const configDefinition = this.process(data.payload, request); return new ConfigSuccessResponse(configDefinition, data.statusCode, data.statusText, this.processPageInfo(data.payload)); } else { return new ErrorResponse( diff --git a/src/app/core/data/base-response-parsing.service.ts b/src/app/core/data/base-response-parsing.service.ts index 0ed5dc363c..ea2d71faa7 100644 --- a/src/app/core/data/base-response-parsing.service.ts +++ b/src/app/core/data/base-response-parsing.service.ts @@ -9,6 +9,7 @@ import { PaginatedList } from './paginated-list'; import { isRestDataObject, isRestPaginatedList } from '../cache/builders/normalized-object-build.service'; import { ResourceType } from '../shared/resource-type'; import { getMapsToType } from '../cache/builders/build-decorators'; +import { RestRequest } from './request.models'; /* tslint:disable:max-classes-per-file */ export abstract class BaseResponseParsingService { @@ -16,14 +17,14 @@ export abstract class BaseResponseParsingService { protected abstract objectCache: ObjectCacheService; protected abstract toCache: boolean; - protected process(data: any, requestUUID: string): any { + protected process(data: any, request: RestRequest): any { if (isNotEmpty(data)) { if (hasNoValue(data) || (typeof data !== 'object')) { return data; } else if (isRestPaginatedList(data)) { - return this.processPaginatedList(data, requestUUID); + return this.processPaginatedList(data, request); } else if (Array.isArray(data)) { - return this.processArray(data, requestUUID); + return this.processArray(data, request); } else if (isRestDataObject(data)) { const object = this.deserialize(data); if (isNotEmpty(data._embedded)) { @@ -31,7 +32,7 @@ export abstract class BaseResponseParsingService { .keys(data._embedded) .filter((property) => data._embedded.hasOwnProperty(property)) .forEach((property) => { - const parsedObj = this.process(data._embedded[property], requestUUID); + const parsedObj = this.process(data._embedded[property], request); if (isNotEmpty(parsedObj)) { if (isRestPaginatedList(data._embedded[property])) { object[property] = parsedObj; @@ -45,7 +46,7 @@ export abstract class BaseResponseParsingService { }); } - this.cache(object, requestUUID); + this.cache(object, request); return object; } const result = {}; @@ -53,14 +54,14 @@ export abstract class BaseResponseParsingService { .filter((property) => data.hasOwnProperty(property)) .filter((property) => hasValue(data[property])) .forEach((property) => { - result[property] = this.process(data[property], requestUUID); + result[property] = this.process(data[property], request); }); return result; } } - protected processPaginatedList(data: any, requestUUID: string): PaginatedList { + protected processPaginatedList(data: any, request: RestRequest): PaginatedList { const pageInfo: PageInfo = this.processPageInfo(data); let list = data._embedded; @@ -70,14 +71,14 @@ export abstract class BaseResponseParsingService { } else if (!Array.isArray(list)) { list = this.flattenSingleKeyObject(list); } - const page: ObjectDomain[] = this.processArray(list, requestUUID); + const page: ObjectDomain[] = this.processArray(list, request); return new PaginatedList(pageInfo, page, ); } - protected processArray(data: any, requestUUID: string): ObjectDomain[] { + protected processArray(data: any, request: RestRequest): ObjectDomain[] { let array: ObjectDomain[] = []; data.forEach((datum) => { - array = [...array, this.process(datum, requestUUID)]; + array = [...array, this.process(datum, request)]; } ); return array; @@ -104,17 +105,17 @@ export abstract class BaseResponseParsingService { } } - protected cache(obj, requestUUID) { + protected cache(obj, request: RestRequest) { if (this.toCache) { - this.addToObjectCache(obj, requestUUID); + this.addToObjectCache(obj, request); } } - protected addToObjectCache(co: CacheableObject, requestUUID: string): void { + protected addToObjectCache(co: CacheableObject, request: RestRequest): void { if (hasNoValue(co) || hasNoValue(co.self)) { throw new Error('The server returned an invalid object'); } - this.objectCache.add(co, this.EnvConfig.cache.msToLive.default, requestUUID); + this.objectCache.add(co, hasValue(request.responseMsToLive) ? request.responseMsToLive : this.EnvConfig.cache.msToLive.default, request.uuid); } processPageInfo(payload: any): PageInfo { diff --git a/src/app/core/data/bitstream-format-data.service.ts b/src/app/core/data/bitstream-format-data.service.ts index a5638183c0..bdf9b16acf 100644 --- a/src/app/core/data/bitstream-format-data.service.ts +++ b/src/app/core/data/bitstream-format-data.service.ts @@ -38,7 +38,6 @@ const selectedBitstreamFormatSelector = createSelector(bitstreamFormatsStateSele export class BitstreamFormatDataService extends DataService { protected linkPath = 'bitstreamformats'; - protected forceBypassCache = false; constructor( protected requestService: RequestService, diff --git a/src/app/core/data/collection-data.service.spec.ts b/src/app/core/data/collection-data.service.spec.ts index 5cb7fed5e4..a3e1a916e3 100644 --- a/src/app/core/data/collection-data.service.spec.ts +++ b/src/app/core/data/collection-data.service.spec.ts @@ -37,7 +37,7 @@ describe('CollectionDataService', () => { }); it('should configure a GET request', () => { - expect(requestService.configure).toHaveBeenCalledWith(jasmine.any(GetRequest), undefined); + expect(requestService.configure).toHaveBeenCalledWith(jasmine.any(GetRequest)); }); }); diff --git a/src/app/core/data/collection-data.service.ts b/src/app/core/data/collection-data.service.ts index e49267d1f2..7ec31d8970 100644 --- a/src/app/core/data/collection-data.service.ts +++ b/src/app/core/data/collection-data.service.ts @@ -31,7 +31,6 @@ import { SearchParam } from '../cache/models/search-param.model'; @Injectable() export class CollectionDataService extends ComColDataService { protected linkPath = 'collections'; - protected forceBypassCache = false; constructor( protected requestService: RequestService, diff --git a/src/app/core/data/comcol-data.service.spec.ts b/src/app/core/data/comcol-data.service.spec.ts index b5232b0bff..5cc474dff9 100644 --- a/src/app/core/data/comcol-data.service.spec.ts +++ b/src/app/core/data/comcol-data.service.spec.ts @@ -28,7 +28,6 @@ class NormalizedTestObject extends NormalizedObject { } class TestService extends ComColDataService { - protected forceBypassCache = false; constructor( protected requestService: RequestService, diff --git a/src/app/core/data/community-data.service.ts b/src/app/core/data/community-data.service.ts index 8db4d762eb..cc55fe6869 100644 --- a/src/app/core/data/community-data.service.ts +++ b/src/app/core/data/community-data.service.ts @@ -24,7 +24,6 @@ export class CommunityDataService extends ComColDataService { protected linkPath = 'communities'; protected topLinkPath = 'communities/search/top'; protected cds = this; - protected forceBypassCache = false; constructor( protected requestService: RequestService, diff --git a/src/app/core/data/data.service.spec.ts b/src/app/core/data/data.service.spec.ts index dede6f8ae2..ab3cf0ac16 100644 --- a/src/app/core/data/data.service.spec.ts +++ b/src/app/core/data/data.service.spec.ts @@ -24,7 +24,6 @@ class NormalizedTestObject extends NormalizedObject { } class TestService extends DataService { - protected forceBypassCache = false; constructor( protected requestService: RequestService, diff --git a/src/app/core/data/data.service.ts b/src/app/core/data/data.service.ts index ad0db51980..bbfcde2677 100644 --- a/src/app/core/data/data.service.ts +++ b/src/app/core/data/data.service.ts @@ -45,11 +45,14 @@ export abstract class DataService { protected abstract store: Store; protected abstract linkPath: string; protected abstract halService: HALEndpointService; - protected abstract forceBypassCache = false; protected abstract objectCache: ObjectCacheService; protected abstract notificationsService: NotificationsService; protected abstract http: HttpClient; protected abstract comparator: ChangeAnalyzer; + /** + * Allows subclasses to reset the response cache time. + */ + protected responseMsToLive: number; public abstract getBrowseEndpoint(options: FindAllOptions, linkPath?: string): Observable @@ -131,7 +134,10 @@ export abstract class DataService { first((href: string) => hasValue(href))) .subscribe((href: string) => { const request = new FindAllRequest(this.requestService.generateRequestId(), href, options); - this.requestService.configure(request, this.forceBypassCache); + if (hasValue(this.responseMsToLive)) { + request.responseMsToLive = this.responseMsToLive; + } + this.requestService.configure(request); }); return this.rdbService.buildList(hrefObs) as Observable>>; @@ -147,21 +153,29 @@ export abstract class DataService { } findById(id: string): Observable> { + const hrefObs = this.halService.getEndpoint(this.linkPath).pipe( - map((endpoint: string) => this.getIDHref(endpoint, id))); + map((endpoint: string) => this.getIDHref(endpoint, encodeURIComponent(id)))); hrefObs.pipe( find((href: string) => hasValue(href))) .subscribe((href: string) => { const request = new FindByIDRequest(this.requestService.generateRequestId(), href, id); - this.requestService.configure(request, this.forceBypassCache); + if (hasValue(this.responseMsToLive)) { + request.responseMsToLive = this.responseMsToLive; + } + this.requestService.configure(request); }); return this.rdbService.buildSingle(hrefObs); } findByHref(href: string, options?: HttpOptions): Observable> { - this.requestService.configure(new GetRequest(this.requestService.generateRequestId(), href, null, options), this.forceBypassCache); + const request = new GetRequest(this.requestService.generateRequestId(), href, null, options); + if (hasValue(this.responseMsToLive)) { + request.responseMsToLive = this.responseMsToLive; + } + this.requestService.configure(request); return this.rdbService.buildSingle(href); } @@ -192,7 +206,8 @@ export abstract class DataService { first((href: string) => hasValue(href))) .subscribe((href: string) => { const request = new FindAllRequest(this.requestService.generateRequestId(), href, options); - this.requestService.configure(request, true); + request.responseMsToLive = 10 * 1000; + this.requestService.configure(request); }); return this.rdbService.buildList(hrefObs) as Observable>>; diff --git a/src/app/core/data/dso-redirect-data.service.spec.ts b/src/app/core/data/dso-redirect-data.service.spec.ts new file mode 100644 index 0000000000..80507c4492 --- /dev/null +++ b/src/app/core/data/dso-redirect-data.service.spec.ts @@ -0,0 +1,155 @@ +import { cold, getTestScheduler } from 'jasmine-marbles'; +import { TestScheduler } from 'rxjs/testing'; +import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; +import { HALEndpointService } from '../shared/hal-endpoint.service'; +import { FindByIDRequest, IdentifierType } from './request.models'; +import { RequestService } from './request.service'; +import { ObjectCacheService } from '../cache/object-cache.service'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { HttpClient } from '@angular/common/http'; +import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; +import { DsoRedirectDataService } from './dso-redirect-data.service'; +import { Store } from '@ngrx/store'; +import { CoreState } from '../core.reducers'; + +describe('DsoRedirectDataService', () => { + let scheduler: TestScheduler; + let service: DsoRedirectDataService; + let halService: HALEndpointService; + let requestService: RequestService; + let rdbService: RemoteDataBuildService; + let router; + let remoteData; + const dsoUUID = '9b4f22f4-164a-49db-8817-3316b6ee5746'; + const dsoHandle = '1234567789/22'; + const encodedHandle = encodeURIComponent(dsoHandle); + const pidLink = 'https://rest.api/rest/api/pid/find{?id}'; + const requestHandleURL = `https://rest.api/rest/api/pid/find?id=${encodedHandle}`; + const requestUUIDURL = `https://rest.api/rest/api/pid/find?id=${dsoUUID}`; + const requestUUID = '34cfed7c-f597-49ef-9cbe-ea351f0023c2'; + const store = {} as Store; + const notificationsService = {} as NotificationsService; + const http = {} as HttpClient; + const comparator = {} as any; + const dataBuildService = {} as NormalizedObjectBuildService; + const objectCache = {} as ObjectCacheService; + let setup; + beforeEach(() => { + scheduler = getTestScheduler(); + + halService = jasmine.createSpyObj('halService', { + getEndpoint: cold('a', {a: pidLink}) + }); + requestService = jasmine.createSpyObj('requestService', { + generateRequestId: requestUUID, + configure: true + }); + router = { + navigate: jasmine.createSpy('navigate') + }; + + remoteData = { + isSuccessful: true, + error: undefined, + hasSucceeded: true, + isLoading: false, + payload: { + type: 'item', + uuid: '123456789' + } + }; + + setup = () => { + rdbService = jasmine.createSpyObj('rdbService', { + buildSingle: cold('a', { + a: remoteData + }) + }); + service = new DsoRedirectDataService( + requestService, + rdbService, + dataBuildService, + store, + objectCache, + halService, + notificationsService, + http, + comparator, + router + ); + } + }); + + describe('findById', () => { + it('should call HALEndpointService with the path to the pid endpoint', () => { + setup(); + scheduler.schedule(() => service.findById(dsoHandle, IdentifierType.HANDLE)); + scheduler.flush(); + + expect(halService.getEndpoint).toHaveBeenCalledWith('pid'); + }); + + it('should call HALEndpointService with the path to the dso endpoint', () => { + setup(); + scheduler.schedule(() => service.findById(dsoUUID, IdentifierType.UUID)); + scheduler.flush(); + + expect(halService.getEndpoint).toHaveBeenCalledWith('dso'); + }); + + it('should call HALEndpointService with the path to the dso endpoint when identifier type not specified', () => { + setup(); + scheduler.schedule(() => service.findById(dsoUUID)); + scheduler.flush(); + + expect(halService.getEndpoint).toHaveBeenCalledWith('dso'); + }); + + it('should configure the proper FindByIDRequest for uuid', () => { + setup(); + scheduler.schedule(() => service.findById(dsoUUID, IdentifierType.UUID)); + scheduler.flush(); + + expect(requestService.configure).toHaveBeenCalledWith(new FindByIDRequest(requestUUID, requestUUIDURL, dsoUUID)); + }); + + it('should configure the proper FindByIDRequest for handle', () => { + setup(); + scheduler.schedule(() => service.findById(dsoHandle, IdentifierType.HANDLE)); + scheduler.flush(); + + expect(requestService.configure).toHaveBeenCalledWith(new FindByIDRequest(requestUUID, requestHandleURL, dsoHandle)); + }); + + it('should navigate to item route', () => { + remoteData.payload.type = 'item'; + setup(); + const redir = service.findById(dsoHandle, IdentifierType.HANDLE); + // The framework would normally subscribe but do it here so we can test navigation. + redir.subscribe(); + scheduler.schedule(() => redir); + scheduler.flush(); + expect(router.navigate).toHaveBeenCalledWith([remoteData.payload.type + 's/' + remoteData.payload.uuid]); + }); + + it('should navigate to collections route', () => { + remoteData.payload.type = 'collection'; + setup(); + const redir = service.findById(dsoHandle, IdentifierType.HANDLE); + redir.subscribe(); + scheduler.schedule(() => redir); + scheduler.flush(); + expect(router.navigate).toHaveBeenCalledWith([remoteData.payload.type + 's/' + remoteData.payload.uuid]); + }); + + it('should navigate to communities route', () => { + remoteData.payload.type = 'community'; + setup(); + const redir = service.findById(dsoHandle, IdentifierType.HANDLE); + redir.subscribe(); + scheduler.schedule(() => redir); + scheduler.flush(); + expect(router.navigate).toHaveBeenCalledWith(['communities/' + remoteData.payload.uuid]); + }); + }) +}); diff --git a/src/app/core/data/dso-redirect-data.service.ts b/src/app/core/data/dso-redirect-data.service.ts new file mode 100644 index 0000000000..7e71f82bbf --- /dev/null +++ b/src/app/core/data/dso-redirect-data.service.ts @@ -0,0 +1,90 @@ +import { DataService } from './data.service'; +import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; +import { HALEndpointService } from '../shared/hal-endpoint.service'; +import { HttpClient } from '@angular/common/http'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { ObjectCacheService } from '../cache/object-cache.service'; +import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; +import { RequestService } from './request.service'; +import { Store } from '@ngrx/store'; +import { CoreState } from '../core.reducers'; +import { FindAllOptions, FindByIDRequest, IdentifierType } from './request.models'; +import { Observable } from 'rxjs'; +import { RemoteData } from './remote-data'; +import { DSOChangeAnalyzer } from './dso-change-analyzer.service'; +import { Injectable } from '@angular/core'; +import { filter, take, tap } from 'rxjs/operators'; +import { hasValue } from '../../shared/empty.util'; +import { getFinishedRemoteData } from '../shared/operators'; +import { Router } from '@angular/router'; + +@Injectable() +export class DsoRedirectDataService extends DataService { + + // Set the default link path to the identifier lookup endpoint. + protected linkPath = 'pid'; + protected forceBypassCache = false; + private uuidEndpoint = 'dso'; + + constructor( + protected requestService: RequestService, + protected rdbService: RemoteDataBuildService, + protected dataBuildService: NormalizedObjectBuildService, + protected store: Store, + protected objectCache: ObjectCacheService, + protected halService: HALEndpointService, + protected notificationsService: NotificationsService, + protected http: HttpClient, + protected comparator: DSOChangeAnalyzer, + private router: Router) { + super(); + } + + getBrowseEndpoint(options: FindAllOptions = {}, linkPath: string = this.linkPath): Observable { + return this.halService.getEndpoint(linkPath); + } + + setLinkPath(identifierType: IdentifierType) { + // The default 'pid' endpoint for identifiers does not support uuid lookups. + // For uuid lookups we need to change the linkPath. + if (identifierType === IdentifierType.UUID) { + this.linkPath = this.uuidEndpoint; + } + } + + getIDHref(endpoint, resourceID): string { + // Supporting both identifier (pid) and uuid (dso) endpoints + return endpoint.replace(/\{\?id\}/, `?id=${resourceID}`) + .replace(/\{\?uuid\}/, `?uuid=${resourceID}`); + } + + findById(id: string, identifierType = IdentifierType.UUID): Observable> { + this.setLinkPath(identifierType); + return super.findById(id).pipe( + getFinishedRemoteData(), + take(1), + tap((response) => { + if (response.hasSucceeded) { + const uuid = response.payload.uuid; + const newRoute = this.getEndpointFromDSOType(response.payload.type); + if (hasValue(uuid) && hasValue(newRoute)) { + this.router.navigate([newRoute + '/' + uuid]); + } + } + }) + ); + } + // Is there an existing method somewhere else that converts dso type to route? + getEndpointFromDSOType(dsoType: string): string { + // Are there other types to consider? + if (dsoType.startsWith('item')) { + return 'items' + } else if (dsoType.startsWith('community')) { + return 'communities'; + } else if (dsoType.startsWith('collection')) { + return 'collections' + } else { + return ''; + } + } +} diff --git a/src/app/core/data/dso-response-parsing.service.ts b/src/app/core/data/dso-response-parsing.service.ts index d6c3b2caa6..d2c21825cc 100644 --- a/src/app/core/data/dso-response-parsing.service.ts +++ b/src/app/core/data/dso-response-parsing.service.ts @@ -30,7 +30,7 @@ export class DSOResponseParsingService extends BaseResponseParsingService implem if (hasValue(data.payload) && hasValue(data.payload.page) && data.payload.page.totalElements === 0) { processRequestDTO = { page: [] }; } else { - processRequestDTO = this.process>(data.payload, request.uuid); + processRequestDTO = this.process>(data.payload, request); } let objectList = processRequestDTO; diff --git a/src/app/core/data/dspace-object-data.service.spec.ts b/src/app/core/data/dspace-object-data.service.spec.ts index a0bba214ae..7047db6065 100644 --- a/src/app/core/data/dspace-object-data.service.spec.ts +++ b/src/app/core/data/dspace-object-data.service.spec.ts @@ -72,7 +72,7 @@ describe('DSpaceObjectDataService', () => { scheduler.schedule(() => service.findById(testObject.uuid)); scheduler.flush(); - expect(requestService.configure).toHaveBeenCalledWith(new FindByIDRequest(requestUUID, requestURL, testObject.uuid), false); + expect(requestService.configure).toHaveBeenCalledWith(new FindByIDRequest(requestUUID, requestURL, testObject.uuid)); }); it('should return a RemoteData for the object with the given ID', () => { diff --git a/src/app/core/data/dspace-object-data.service.ts b/src/app/core/data/dspace-object-data.service.ts index 4f0653f416..bb02afbcd1 100644 --- a/src/app/core/data/dspace-object-data.service.ts +++ b/src/app/core/data/dspace-object-data.service.ts @@ -18,7 +18,6 @@ import { DSOChangeAnalyzer } from './dso-change-analyzer.service'; /* tslint:disable:max-classes-per-file */ class DataServiceImpl extends DataService { protected linkPath = 'dso'; - protected forceBypassCache = false; constructor( protected requestService: RequestService, diff --git a/src/app/core/data/item-data.service.ts b/src/app/core/data/item-data.service.ts index de05dad0c1..e616cb8020 100644 --- a/src/app/core/data/item-data.service.ts +++ b/src/app/core/data/item-data.service.ts @@ -41,7 +41,6 @@ import { PaginatedList } from './paginated-list'; @Injectable() export class ItemDataService extends DataService { protected linkPath = 'items'; - protected forceBypassCache = false; constructor( protected requestService: RequestService, diff --git a/src/app/core/data/metadata-schema-data.service.ts b/src/app/core/data/metadata-schema-data.service.ts index 4baca6e8ed..b15dd6865f 100644 --- a/src/app/core/data/metadata-schema-data.service.ts +++ b/src/app/core/data/metadata-schema-data.service.ts @@ -19,7 +19,6 @@ import { MetadataSchema } from '../metadata/metadata-schema.model'; /* tslint:disable:max-classes-per-file */ class DataServiceImpl extends DataService { protected linkPath = 'metadataschemas'; - protected forceBypassCache = false; constructor( protected requestService: RequestService, diff --git a/src/app/core/data/relationship.service.spec.ts b/src/app/core/data/relationship.service.spec.ts index 31513bb779..4091759386 100644 --- a/src/app/core/data/relationship.service.spec.ts +++ b/src/app/core/data/relationship.service.spec.ts @@ -14,6 +14,7 @@ import { PageInfo } from '../shared/page-info.model'; import { DeleteRequest } from './request.models'; import { ObjectCacheService } from '../cache/object-cache.service'; import { Observable } from 'rxjs/internal/Observable'; +import { createSuccessfulRemoteDataObject$ } from '../../shared/testing/utils'; describe('RelationshipService', () => { let service: RelationshipService; @@ -22,12 +23,6 @@ describe('RelationshipService', () => { const restEndpointURL = 'https://rest.api/'; const relationshipsEndpointURL = `${restEndpointURL}/relationships`; const halService: any = new HALEndpointServiceStub(restEndpointURL); - const rdbService = getMockRemoteDataBuildService(); - const objectCache = Object.assign({ - /* tslint:disable:no-empty */ - remove: () => {} - /* tslint:enable:no-empty */ - }) as ObjectCacheService; const relationshipType = Object.assign(new RelationshipType(), { id: '1', @@ -72,17 +67,30 @@ describe('RelationshipService', () => { relationship2.rightItem = getRemotedataObservable(item); const relatedItems = [relatedItem1, relatedItem2]; + const buildList$ = createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [relatedItems])); + const rdbService = getMockRemoteDataBuildService(undefined, buildList$); + const objectCache = Object.assign({ + /* tslint:disable:no-empty */ + remove: () => {} + /* tslint:enable:no-empty */ + }) as ObjectCacheService; + const itemService = jasmine.createSpyObj('itemService', { findById: (uuid) => new RemoteData(false, false, true, undefined, relatedItems.filter((relatedItem) => relatedItem.id === uuid)[0]) }); function initTestService() { return new RelationshipService( - requestService, - halService, - rdbService, itemService, - objectCache + requestService, + rdbService, + null, + null, + halService, + objectCache, + null, + null, + null ); } @@ -106,7 +114,7 @@ describe('RelationshipService', () => { it('should send a DeleteRequest', () => { const expected = new DeleteRequest(requestService.generateRequestId(), relationshipsEndpointURL + '/' + relationship1.uuid); - expect(requestService.configure).toHaveBeenCalledWith(expected, undefined); + expect(requestService.configure).toHaveBeenCalledWith(expected); }); it('should clear the related items their cache', () => { @@ -144,7 +152,7 @@ describe('RelationshipService', () => { describe('getRelatedItemsByLabel', () => { it('should return the related items by label', () => { service.getRelatedItemsByLabel(item, relationshipType.rightwardType).subscribe((result) => { - expect(result).toEqual(relatedItems); + expect(result.payload.page).toEqual(relatedItems); }); }); }) diff --git a/src/app/core/data/relationship.service.ts b/src/app/core/data/relationship.service.ts index b07e4b714c..c466bd15af 100644 --- a/src/app/core/data/relationship.service.ts +++ b/src/app/core/data/relationship.service.ts @@ -10,7 +10,7 @@ import { getRemoteDataPayload, getResponseFromEntry, getSucceededRemoteData } from '../shared/operators'; -import { DeleteRequest, RestRequest } from './request.models'; +import { DeleteRequest, FindAllOptions, RestRequest } from './request.models'; import { Observable } from 'rxjs/internal/Observable'; import { RestResponse } from '../cache/response.models'; import { Item } from '../shared/item.model'; @@ -22,23 +22,42 @@ import { zip as observableZip } from 'rxjs'; import { PaginatedList } from './paginated-list'; import { ItemDataService } from './item-data.service'; import { - compareArraysUsingIds, filterRelationsByTypeLabel, + compareArraysUsingIds, filterRelationsByTypeLabel, paginatedRelationsToItems, relationsToItems } from '../../+item-page/simple/item-types/shared/item-relationships-utils'; import { ObjectCacheService } from '../cache/object-cache.service'; +import { DataService } from './data.service'; +import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service'; +import { Store } from '@ngrx/store'; +import { CoreState } from '../core.reducers'; +import { NotificationsService } from '../../shared/notifications/notifications.service'; +import { HttpClient } from '@angular/common/http'; +import { DefaultChangeAnalyzer } from './default-change-analyzer.service'; +import { SearchParam } from '../cache/models/search-param.model'; /** * The service handling all relationship requests */ @Injectable() -export class RelationshipService { +export class RelationshipService extends DataService { protected linkPath = 'relationships'; + protected forceBypassCache = false; - constructor(protected requestService: RequestService, - protected halService: HALEndpointService, + constructor(protected itemService: ItemDataService, + protected requestService: RequestService, protected rdbService: RemoteDataBuildService, - protected itemService: ItemDataService, - protected objectCache: ObjectCacheService) { + protected dataBuildService: NormalizedObjectBuildService, + protected store: Store, + protected halService: HALEndpointService, + protected objectCache: ObjectCacheService, + protected notificationsService: NotificationsService, + protected http: HttpClient, + protected comparator: DefaultChangeAnalyzer) { + super(); + } + + getBrowseEndpoint(options: FindAllOptions = {}, linkPath: string = this.linkPath): Observable { + return this.halService.getEndpoint(linkPath); } /** @@ -207,12 +226,31 @@ export class RelationshipService { * and return the items as an array * @param item * @param label + * @param options */ - getRelatedItemsByLabel(item: Item, label: string): Observable { - return this.getItemResolvedRelsAndTypes(item).pipe( - filterRelationsByTypeLabel(label), - relationsToItems(item.uuid) - ); + getRelatedItemsByLabel(item: Item, label: string, options?: FindAllOptions): Observable>> { + return this.getItemRelationshipsByLabel(item, label, options).pipe(paginatedRelationsToItems(item.uuid)); + } + + /** + * Resolve a given item's relationships into related items, filtered by a relationship label + * and return the items as an array + * @param item + * @param label + * @param options + */ + getItemRelationshipsByLabel(item: Item, label: string, options?: FindAllOptions): Observable>> { + let findAllOptions = new FindAllOptions(); + if (options) { + findAllOptions = Object.assign(new FindAllOptions(), options); + } + const searchParams = [ new SearchParam('label', label), new SearchParam('dso', item.id) ]; + if (findAllOptions.searchParams) { + findAllOptions.searchParams = [...findAllOptions.searchParams, ...searchParams]; + } else { + findAllOptions.searchParams = searchParams; + } + return this.searchBy('byLabel', findAllOptions); } /** diff --git a/src/app/core/data/request.models.ts b/src/app/core/data/request.models.ts index 43ab9e58e7..a7d11089df 100644 --- a/src/app/core/data/request.models.ts +++ b/src/app/core/data/request.models.ts @@ -22,8 +22,15 @@ import { MappedCollectionsReponseParsingService } from './mapped-collections-rep /* tslint:disable:max-classes-per-file */ +// uuid and handle requests have separate endpoints +export enum IdentifierType { + UUID ='uuid', + HANDLE = 'handle' +} + export abstract class RestRequest { - public responseMsToLive = 0; + public responseMsToLive = 10 * 1000; + public forceBypassCache = false; constructor( public uuid: string, public href: string, @@ -49,7 +56,7 @@ export class GetRequest extends RestRequest { public uuid: string, public href: string, public body?: any, - public options?: HttpOptions, + public options?: HttpOptions ) { super(uuid, href, RestRequestMethod.GET, body, options) } @@ -293,6 +300,7 @@ export class UpdateMetadataFieldRequest extends PutRequest { * Class representing a submission HTTP GET request object */ export class SubmissionRequest extends GetRequest { + forceBypassCache = true; constructor(uuid: string, href: string) { super(uuid, href); } @@ -404,7 +412,7 @@ export class TaskDeleteRequest extends DeleteRequest { } export class MyDSpaceRequest extends GetRequest { - public responseMsToLive = 0; + public responseMsToLive = 10 * 1000; } export class RequestError extends Error { diff --git a/src/app/core/data/request.service.spec.ts b/src/app/core/data/request.service.spec.ts index e2bc04040f..5807666d66 100644 --- a/src/app/core/data/request.service.spec.ts +++ b/src/app/core/data/request.service.spec.ts @@ -298,10 +298,11 @@ describe('RequestService', () => { describe('in the ObjectCache', () => { beforeEach(() => { (objectCache.hasBySelfLink as any).and.returnValue(true); + (objectCache.hasByUUID as any).and.returnValue(true); spyOn(serviceAsAny, 'hasByHref').and.returnValue(false); }); - it('should return true', () => { + it('should return true for GetRequest', () => { const result = serviceAsAny.isCachedOrPending(testGetRequest); const expected = true; diff --git a/src/app/core/data/request.service.ts b/src/app/core/data/request.service.ts index 0980d48537..bd65163892 100644 --- a/src/app/core/data/request.service.ts +++ b/src/app/core/data/request.service.ts @@ -19,7 +19,7 @@ import { } from '../index/index.selectors'; import { UUIDService } from '../shared/uuid.service'; import { RequestConfigureAction, RequestExecuteAction, RequestRemoveAction } from './request.actions'; -import { GetRequest, RestRequest } from './request.models'; +import { GetRequest, RestRequest, SubmissionRequest } from './request.models'; import { RequestEntry, RequestState } from './request.reducer'; import { CommitSSBAction } from '../cache/server-sync-buffer.actions'; import { RestRequestMethod } from './rest-request-method'; @@ -145,14 +145,10 @@ export class RequestService { * Configure a certain request * Used to make sure a request is in the cache * @param {RestRequest} request The request to send out - * @param {boolean} forceBypassCache When true, a new request is always dispatched */ - configure(request: RestRequest, forceBypassCache: boolean = false): void { + configure(request: RestRequest): void { const isGetRequest = request.method === RestRequestMethod.GET; - if (forceBypassCache) { - this.clearRequestsOnTheirWayToTheStore(request); - } - if (!isGetRequest || (forceBypassCache && !this.isPending(request)) || !this.isCachedOrPending(request)) { + if (!isGetRequest || request.forceBypassCache || !this.isCachedOrPending(request)) { this.dispatchRequest(request); if (isGetRequest) { this.trackRequestsOnTheirWayToTheStore(request); @@ -226,7 +222,6 @@ export class RequestService { const inReqCache = this.hasByHref(request.href); const inObjCache = this.objectCache.hasBySelfLink(request.href); const isCached = inReqCache || inObjCache; - const isPending = this.isPending(request); return isCached || isPending; } diff --git a/src/app/core/data/resource-policy.service.spec.ts b/src/app/core/data/resource-policy.service.spec.ts index 35d28684a7..1a02171be3 100644 --- a/src/app/core/data/resource-policy.service.spec.ts +++ b/src/app/core/data/resource-policy.service.spec.ts @@ -61,7 +61,7 @@ describe('ResourcePolicyService', () => { scheduler.schedule(() => service.findByHref(requestURL)); scheduler.flush(); - expect(requestService.configure).toHaveBeenCalledWith(new GetRequest(requestUUID, requestURL, null), false); + expect(requestService.configure).toHaveBeenCalledWith(new GetRequest(requestUUID, requestURL, null)); }); it('should return a RemoteData for the object with the given URL', () => { diff --git a/src/app/core/data/resource-policy.service.ts b/src/app/core/data/resource-policy.service.ts index 1a6a1afedc..1574111232 100644 --- a/src/app/core/data/resource-policy.service.ts +++ b/src/app/core/data/resource-policy.service.ts @@ -22,7 +22,6 @@ import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service'; /* tslint:disable:max-classes-per-file */ class DataServiceImpl extends DataService { protected linkPath = 'resourcepolicies'; - protected forceBypassCache = false; constructor( protected requestService: RequestService, diff --git a/src/app/core/eperson/eperson-response-parsing.service.ts b/src/app/core/eperson/eperson-response-parsing.service.ts index 481f37d1fa..76222323ae 100644 --- a/src/app/core/eperson/eperson-response-parsing.service.ts +++ b/src/app/core/eperson/eperson-response-parsing.service.ts @@ -28,7 +28,7 @@ export class EpersonResponseParsingService extends BaseResponseParsingService im parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse { if (isNotEmpty(data.payload) && isNotEmpty(data.payload._links)) { - const epersonDefinition = this.process(data.payload, request.href); + const epersonDefinition = this.process(data.payload, request); return new EpersonSuccessResponse(epersonDefinition[Object.keys(epersonDefinition)[0]], data.statusCode, data.statusText, this.processPageInfo(data.payload)); } else { return new ErrorResponse( diff --git a/src/app/core/eperson/group-eperson.service.ts b/src/app/core/eperson/group-eperson.service.ts index 07a1bb6aba..2014e6120a 100644 --- a/src/app/core/eperson/group-eperson.service.ts +++ b/src/app/core/eperson/group-eperson.service.ts @@ -27,7 +27,6 @@ import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service'; export class GroupEpersonService extends EpersonService { protected linkPath = 'groups'; protected browseEndpoint = ''; - protected forceBypassCache = false; constructor( protected comparator: DSOChangeAnalyzer, diff --git a/src/app/core/eperson/models/normalized-eperson.model.ts b/src/app/core/eperson/models/normalized-eperson.model.ts index bf644a83ef..9a3bf4c246 100644 --- a/src/app/core/eperson/models/normalized-eperson.model.ts +++ b/src/app/core/eperson/models/normalized-eperson.model.ts @@ -1,7 +1,6 @@ import { autoserialize, deserialize, inheritSerialization } from 'cerialize'; import { CacheableObject } from '../../cache/object-cache.reducer'; -import { ListableObject } from '../../../shared/object-collection/shared/listable-object.model'; import { NormalizedDSpaceObject } from '../../cache/models/normalized-dspace-object.model'; import { EPerson } from './eperson.model'; import { mapsTo, relationship } from '../../cache/builders/build-decorators'; @@ -9,7 +8,7 @@ import { Group } from './group.model'; @mapsTo(EPerson) @inheritSerialization(NormalizedDSpaceObject) -export class NormalizedEPerson extends NormalizedDSpaceObject implements CacheableObject, ListableObject { +export class NormalizedEPerson extends NormalizedDSpaceObject implements CacheableObject { /** * A string representing the unique handle of this EPerson */ diff --git a/src/app/core/eperson/models/normalized-group.model.ts b/src/app/core/eperson/models/normalized-group.model.ts index 329ffb8adf..72b4e7b1a4 100644 --- a/src/app/core/eperson/models/normalized-group.model.ts +++ b/src/app/core/eperson/models/normalized-group.model.ts @@ -1,14 +1,13 @@ import { autoserialize, deserialize, inheritSerialization } from 'cerialize'; import { CacheableObject } from '../../cache/object-cache.reducer'; -import { ListableObject } from '../../../shared/object-collection/shared/listable-object.model'; import { NormalizedDSpaceObject } from '../../cache/models/normalized-dspace-object.model'; import { mapsTo, relationship } from '../../cache/builders/build-decorators'; import { Group } from './group.model'; @mapsTo(Group) @inheritSerialization(NormalizedDSpaceObject) -export class NormalizedGroup extends NormalizedDSpaceObject implements CacheableObject, ListableObject { +export class NormalizedGroup extends NormalizedDSpaceObject implements CacheableObject { /** * List of Groups that this Group belong to diff --git a/src/app/core/index/index.selectors.ts b/src/app/core/index/index.selectors.ts index 3c7b331a92..a6d7b7e7b0 100644 --- a/src/app/core/index/index.selectors.ts +++ b/src/app/core/index/index.selectors.ts @@ -53,8 +53,9 @@ export const requestUUIDIndexSelector: MemoizedSelector = /** * Return the self link of an object in the object-cache based on its UUID * - * @param uuid + * @param id * the UUID for which you want to find the matching self link + * @param identifierType the type of index, used to select index from state * @returns * a MemoizedSelector to select the self link */ diff --git a/src/app/core/integration/integration-response-parsing.service.ts b/src/app/core/integration/integration-response-parsing.service.ts index 8cc0f8d252..0609cd804e 100644 --- a/src/app/core/integration/integration-response-parsing.service.ts +++ b/src/app/core/integration/integration-response-parsing.service.ts @@ -27,7 +27,7 @@ export class IntegrationResponseParsingService extends BaseResponseParsingServic parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse { if (isNotEmpty(data.payload) && isNotEmpty(data.payload._links)) { - const dataDefinition = this.process(data.payload, request.uuid); + const dataDefinition = this.process(data.payload, request); return new IntegrationSuccessResponse(this.processResponse(dataDefinition), data.statusCode, data.statusText, this.processPageInfo(data.payload)); } else { return new ErrorResponse( diff --git a/src/app/core/metadata/metadata-field.model.ts b/src/app/core/metadata/metadata-field.model.ts index 288934e52d..78d106f143 100644 --- a/src/app/core/metadata/metadata-field.model.ts +++ b/src/app/core/metadata/metadata-field.model.ts @@ -2,6 +2,7 @@ import { ListableObject } from '../../shared/object-collection/shared/listable-o import { isNotEmpty } from '../../shared/empty.util'; import { MetadataSchema } from './metadata-schema.model'; import { ResourceType } from '../shared/resource-type'; +import { GenericConstructor } from '../shared/generic-constructor'; /** * Class the represents a metadata field @@ -50,4 +51,11 @@ export class MetadataField implements ListableObject { } return key; } + + /** + * Method that returns as which type of object this object should be rendered + */ + getRenderTypes(): Array> { + return [this.constructor as GenericConstructor]; + } } diff --git a/src/app/core/metadata/metadata-schema.model.ts b/src/app/core/metadata/metadata-schema.model.ts index bc05e475cc..78d5338f2e 100644 --- a/src/app/core/metadata/metadata-schema.model.ts +++ b/src/app/core/metadata/metadata-schema.model.ts @@ -1,5 +1,6 @@ import { ListableObject } from '../../shared/object-collection/shared/listable-object.model'; import { ResourceType } from '../shared/resource-type'; +import { GenericConstructor } from '../shared/generic-constructor'; /** * Class that represents a metadata schema @@ -26,4 +27,11 @@ export class MetadataSchema implements ListableObject { * The namespace of this metadata schema */ namespace: string; + + /** + * Method that returns as which type of object this object should be rendered + */ + getRenderTypes(): Array> { + return [this.constructor as GenericConstructor]; + } } diff --git a/src/app/core/metadata/normalized-metadata-field.model.ts b/src/app/core/metadata/normalized-metadata-field.model.ts index c6b2ee32f8..075dda79d2 100644 --- a/src/app/core/metadata/normalized-metadata-field.model.ts +++ b/src/app/core/metadata/normalized-metadata-field.model.ts @@ -10,7 +10,7 @@ import { MetadataSchema } from './metadata-schema.model'; */ @mapsTo(MetadataField) @inheritSerialization(NormalizedObject) -export class NormalizedMetadataField extends NormalizedObject implements ListableObject { +export class NormalizedMetadataField extends NormalizedObject { /** * The identifier of this normalized metadata field diff --git a/src/app/core/metadata/normalized-metadata-schema.model.ts b/src/app/core/metadata/normalized-metadata-schema.model.ts index 47c7233d81..1aa5609090 100644 --- a/src/app/core/metadata/normalized-metadata-schema.model.ts +++ b/src/app/core/metadata/normalized-metadata-schema.model.ts @@ -9,7 +9,7 @@ import { MetadataSchema } from './metadata-schema.model'; */ @mapsTo(MetadataSchema) @inheritSerialization(NormalizedObject) -export class NormalizedMetadataSchema extends NormalizedObject implements ListableObject { +export class NormalizedMetadataSchema extends NormalizedObject { /** * The unique identifier for this schema */ diff --git a/src/app/core/registry/registry.service.spec.ts b/src/app/core/registry/registry.service.spec.ts index 455a8043da..03a7c132de 100644 --- a/src/app/core/registry/registry.service.spec.ts +++ b/src/app/core/registry/registry.service.spec.ts @@ -55,22 +55,24 @@ describe('RegistryService', () => { }); const mockSchemasList = [ - { + Object.assign(new MetadataSchema(), { id: 1, self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadataschemas/1', prefix: 'dc', namespace: 'http://dublincore.org/documents/dcmi-terms/', type: MetadataSchema.type -}, - { +}), + Object.assign(new MetadataSchema(), { + id: 2, self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadataschemas/2', prefix: 'mock', namespace: 'http://dspace.org/mockschema', type: MetadataSchema.type - } + }) ]; const mockFieldsList = [ + Object.assign(new MetadataField(), { id: 1, self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/8', @@ -79,8 +81,9 @@ describe('RegistryService', () => { scopeNote: null, schema: mockSchemasList[0], type: MetadataField.type - }, - { + }), + Object.assign(new MetadataField(), + { id: 2, self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/9', element: 'contributor', @@ -88,8 +91,9 @@ describe('RegistryService', () => { scopeNote: null, schema: mockSchemasList[0], type: MetadataField.type - }, - { + }), + Object.assign(new MetadataField(), + { id: 3, self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/10', element: 'contributor', @@ -97,8 +101,9 @@ describe('RegistryService', () => { scopeNote: 'test scope note', schema: mockSchemasList[1], type: MetadataField.type - }, - { + }), + Object.assign(new MetadataField(), + { id: 4, self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/metadatafields/11', element: 'contributor', @@ -106,7 +111,7 @@ describe('RegistryService', () => { scopeNote: null, schema: mockSchemasList[1], type: MetadataField.type - } + }) ]; const pageInfo = new PageInfo(); diff --git a/src/app/core/registry/registry.service.ts b/src/app/core/registry/registry.service.ts index 206426588e..3c6de36492 100644 --- a/src/app/core/registry/registry.service.ts +++ b/src/app/core/registry/registry.service.ts @@ -400,7 +400,7 @@ export class RegistryService { distinctUntilChanged() ); - const serializedSchema = new DSpaceRESTv2Serializer(getMapsToType(MetadataSchema.type)).serialize(schema as NormalizedMetadataSchema); + const serializedSchema = new DSpaceRESTv2Serializer(getMapsToType(MetadataSchema.type)).serialize(schema); const request$ = endpoint$.pipe( take(1), diff --git a/src/app/core/shared/browse-entry.model.ts b/src/app/core/shared/browse-entry.model.ts index d5d4093c81..977afb40f6 100644 --- a/src/app/core/shared/browse-entry.model.ts +++ b/src/app/core/shared/browse-entry.model.ts @@ -1,12 +1,13 @@ import { ListableObject } from '../../shared/object-collection/shared/listable-object.model'; import { TypedObject } from '../cache/object-cache.reducer'; import { ResourceType } from './resource-type'; +import { GenericConstructor } from './generic-constructor'; /** * Class object representing a browse entry * This class is not normalized because browse entries do not have self links */ -export class BrowseEntry implements ListableObject, TypedObject { +export class BrowseEntry implements ListableObject { static type = new ResourceType('browseEntry'); /** @@ -28,4 +29,11 @@ export class BrowseEntry implements ListableObject, TypedObject { * The count of this browse entry */ count: number; + + /** + * Method that returns as which type of object this object should be rendered + */ + getRenderTypes(): Array> { + return [this.constructor as GenericConstructor]; + } } diff --git a/src/app/core/shared/context.model.ts b/src/app/core/shared/context.model.ts new file mode 100644 index 0000000000..7bfd613b65 --- /dev/null +++ b/src/app/core/shared/context.model.ts @@ -0,0 +1,13 @@ +/** + * This enumeration represents all possible ways of representing a group of objects in the UI + */ + +export enum Context { + Undefined = 'undefined', + ItemPage = 'itemPage', + Search = 'search', + Workflow = 'workflow', + Workspace = 'workspace', + AdminMenu = 'adminMenu', + SubmissionModal = 'submissionModal', +} diff --git a/src/app/core/shared/dspace-object.model.ts b/src/app/core/shared/dspace-object.model.ts index 26f76c5ce2..2e50f19c4f 100644 --- a/src/app/core/shared/dspace-object.model.ts +++ b/src/app/core/shared/dspace-object.model.ts @@ -12,6 +12,7 @@ import { CacheableObject } from '../cache/object-cache.reducer'; import { RemoteData } from '../data/remote-data'; import { ListableObject } from '../../shared/object-collection/shared/listable-object.model'; import { ResourceType } from './resource-type'; +import { GenericConstructor } from './generic-constructor'; /** * An abstract model class for a DSpaceObject. @@ -109,7 +110,7 @@ export class DSpaceObject implements CacheableObject, ListableObject { * Like [[firstMetadata]], but only returns a string value, or `undefined`. * * @param {string|string[]} keyOrKeys The metadata key(s) in scope. Wildcards are supported; see [[Metadata]]. - * @param {MetadataValueFilter} filter The value filter to use. If unspecified, no filtering will be done. + * @param {MetadataValueFilter} valueFilter The value filter to use. If unspecified, no filtering will be done. * @returns {string} the first matching string value, or `undefined`. */ firstMetadataValue(keyOrKeys: string | string[], valueFilter?: MetadataValueFilter): string { @@ -146,4 +147,10 @@ export class DSpaceObject implements CacheableObject, ListableObject { }); } + /** + * Method that returns as which type of object this object should be rendered + */ + getRenderTypes(): Array> { + return [this.constructor as GenericConstructor]; + } } diff --git a/src/app/core/shared/item.model.ts b/src/app/core/shared/item.model.ts index f92d079dde..bd304274ab 100644 --- a/src/app/core/shared/item.model.ts +++ b/src/app/core/shared/item.model.ts @@ -5,13 +5,19 @@ import { DSpaceObject } from './dspace-object.model'; import { Collection } from './collection.model'; import { RemoteData } from '../data/remote-data'; import { Bitstream } from './bitstream.model'; -import { hasValueOperator, isNotEmpty } from '../../shared/empty.util'; +import { hasValueOperator, isNotEmpty, isEmpty } from '../../shared/empty.util'; import { PaginatedList } from '../data/paginated-list'; import { Relationship } from './item-relationships/relationship.model'; import { ResourceType } from './resource-type'; import { getAllSucceededRemoteData, getSucceededRemoteData } from './operators'; import { Bundle } from './bundle.model'; +import { GenericConstructor } from './generic-constructor'; +import { ListableObject } from '../../shared/object-collection/shared/listable-object.model'; +import { DEFAULT_ENTITY_TYPE } from '../../shared/metadata-representation/metadata-representation.decorator'; +/** + * Class representing a DSpace Item + */ export class Item extends DSpaceObject { static type = new ResourceType('item'); @@ -112,4 +118,14 @@ export class Item extends DSpaceObject { ); } + /** + * Method that returns as which type of object this object should be rendered + */ + getRenderTypes(): Array> { + let entityType = this.firstMetadataValue('relationship.type'); + if (isEmpty(entityType)) { + entityType = DEFAULT_ENTITY_TYPE; + } + return [entityType, ...super.getRenderTypes()]; + } } diff --git a/src/app/core/shared/operators.spec.ts b/src/app/core/shared/operators.spec.ts index 548a3f1339..ec069772f8 100644 --- a/src/app/core/shared/operators.spec.ts +++ b/src/app/core/shared/operators.spec.ts @@ -148,7 +148,7 @@ describe('Core Module - RxJS Operators', () => { scheduler.schedule(() => source.pipe(configureRequest(requestService)).subscribe()); scheduler.flush(); - expect(requestService.configure).toHaveBeenCalledWith(testRequest, undefined); + expect(requestService.configure).toHaveBeenCalledWith(testRequest); }); }); diff --git a/src/app/core/shared/operators.ts b/src/app/core/shared/operators.ts index d46c688e68..b4c7c8f1a9 100644 --- a/src/app/core/shared/operators.ts +++ b/src/app/core/shared/operators.ts @@ -52,9 +52,9 @@ export const getResourceLinksFromResponse = () => map((response: DSOSuccessResponse) => response.resourceSelfLinks), ); -export const configureRequest = (requestService: RequestService, forceBypassCache?: boolean) => +export const configureRequest = (requestService: RequestService) => (source: Observable): Observable => - source.pipe(tap((request: RestRequest) => requestService.configure(request, forceBypassCache))); + source.pipe(tap((request: RestRequest) => requestService.configure(request))); export const getRemoteDataPayload = () => (source: Observable>): Observable => diff --git a/src/app/core/shared/view-mode.model.ts b/src/app/core/shared/view-mode.model.ts index 9c8d086097..c2f076a5e5 100644 --- a/src/app/core/shared/view-mode.model.ts +++ b/src/app/core/shared/view-mode.model.ts @@ -3,7 +3,8 @@ */ export enum ViewMode { - List = 'list', - Grid = 'grid', - Detail = 'detail' + ListElement = 'listElement', + GridElement = 'gridElement', + DetailedListElement = 'detailedListElement', + StandalonePage = 'standalonePage', } diff --git a/src/app/core/submission/submission-response-parsing.service.ts b/src/app/core/submission/submission-response-parsing.service.ts index de7d683d91..da3b578fcd 100644 --- a/src/app/core/submission/submission-response-parsing.service.ts +++ b/src/app/core/submission/submission-response-parsing.service.ts @@ -91,7 +91,7 @@ export class SubmissionResponseParsingService extends BaseResponseParsingService if (isNotEmpty(data.payload) && isNotEmpty(data.payload._links) && this.isSuccessStatus(data.statusCode)) { - const dataDefinition = this.processResponse(data.payload, request.href); + const dataDefinition = this.processResponse(data.payload, request); return new SubmissionSuccessResponse(dataDefinition, data.statusCode, data.statusText, this.processPageInfo(data.payload)); } else if (isEmpty(data.payload) && this.isSuccessStatus(data.statusCode)) { return new SubmissionSuccessResponse(null, data.statusCode, data.statusText); @@ -109,11 +109,11 @@ export class SubmissionResponseParsingService extends BaseResponseParsingService * Parses response and normalize it * * @param {DSpaceRESTV2Response} data - * @param {string} requestHref + * @param {RestRequest} request * @returns {any[]} */ - protected processResponse(data: any, requestHref: string): any[] { - const dataDefinition = this.process(data, requestHref); + protected processResponse(data: any, request: RestRequest): any[] { + const dataDefinition = this.process(data, request); const normalizedDefinition = Array.of(); const processedList = Array.isArray(dataDefinition) ? dataDefinition : Array.of(dataDefinition); diff --git a/src/app/core/submission/submission-rest.service.spec.ts b/src/app/core/submission/submission-rest.service.spec.ts index 6e748c5575..30fe9f9163 100644 --- a/src/app/core/submission/submission-rest.service.spec.ts +++ b/src/app/core/submission/submission-rest.service.spec.ts @@ -59,10 +59,13 @@ describe('SubmissionRestService test suite', () => { describe('getDataById', () => { it('should configure a new SubmissionRequest', () => { const expected = new SubmissionRequest(requestService.generateRequestId(), resourceHref); + // set cache time to zero + expected.responseMsToLive = 0; + expected.forceBypassCache = true; scheduler.schedule(() => service.getDataById(resourceEndpoint, resourceScope).subscribe()); scheduler.flush(); - expect(requestService.configure).toHaveBeenCalledWith(expected, true); + expect(requestService.configure).toHaveBeenCalledWith(expected); }); }); diff --git a/src/app/core/submission/submission-rest.service.ts b/src/app/core/submission/submission-rest.service.ts index e2b8bb01c8..58aa507314 100644 --- a/src/app/core/submission/submission-rest.service.ts +++ b/src/app/core/submission/submission-rest.service.ts @@ -6,7 +6,7 @@ import { distinctUntilChanged, filter, flatMap, map, mergeMap, tap } from 'rxjs/ import { RequestService } from '../data/request.service'; import { isNotEmpty } from '../../shared/empty.util'; import { - DeleteRequest, + DeleteRequest, GetRequest, PostRequest, RestRequest, SubmissionDeleteRequest, @@ -109,7 +109,11 @@ export class SubmissionRestService { filter((href: string) => isNotEmpty(href)), distinctUntilChanged(), map((endpointURL: string) => new SubmissionRequest(requestId, endpointURL)), - tap((request: RestRequest) => this.requestService.configure(request, true)), + map ((request: RestRequest) => { + request.responseMsToLive = 0; + return request; + }), + tap((request: RestRequest) => this.requestService.configure(request)), flatMap(() => this.fetchRequest(requestId)), distinctUntilChanged()); } diff --git a/src/app/core/submission/workflowitem-data.service.ts b/src/app/core/submission/workflowitem-data.service.ts index fd769745da..43c4aecafe 100644 --- a/src/app/core/submission/workflowitem-data.service.ts +++ b/src/app/core/submission/workflowitem-data.service.ts @@ -20,7 +20,7 @@ import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service'; @Injectable() export class WorkflowItemDataService extends DataService { protected linkPath = 'workflowitems'; - protected forceBypassCache = true; + protected responseMsToLive = 10 * 1000; constructor( protected comparator: DSOChangeAnalyzer, diff --git a/src/app/core/submission/workspaceitem-data.service.ts b/src/app/core/submission/workspaceitem-data.service.ts index de671d57c7..4d388ec513 100644 --- a/src/app/core/submission/workspaceitem-data.service.ts +++ b/src/app/core/submission/workspaceitem-data.service.ts @@ -20,7 +20,7 @@ import { WorkspaceItem } from './models/workspaceitem.model'; @Injectable() export class WorkspaceitemDataService extends DataService { protected linkPath = 'workspaceitems'; - protected forceBypassCache = true; + protected responseMsToLive = 10 * 1000; constructor( protected comparator: DSOChangeAnalyzer, diff --git a/src/app/core/tasks/claimed-task-data.service.ts b/src/app/core/tasks/claimed-task-data.service.ts index dda42e1c67..76e5e769d7 100644 --- a/src/app/core/tasks/claimed-task-data.service.ts +++ b/src/app/core/tasks/claimed-task-data.service.ts @@ -22,16 +22,13 @@ import { ProcessTaskResponse } from './models/process-task-response'; @Injectable() export class ClaimedTaskDataService extends TasksService { + protected responseMsToLive = 10 * 1000; + /** * The endpoint link name */ protected linkPath = 'claimedtasks'; - /** - * When true, a new request is always dispatched - */ - protected forceBypassCache = true; - /** * Initialize instance variables * diff --git a/src/app/core/tasks/pool-task-data.service.ts b/src/app/core/tasks/pool-task-data.service.ts index 1a93450d4d..0e7704336d 100644 --- a/src/app/core/tasks/pool-task-data.service.ts +++ b/src/app/core/tasks/pool-task-data.service.ts @@ -27,10 +27,7 @@ export class PoolTaskDataService extends TasksService { */ protected linkPath = 'pooltasks'; - /** - * When true, a new request is always dispatched - */ - protected forceBypassCache = true; + protected responseMsToLive = 10 * 1000; /** * Initialize instance variables diff --git a/src/app/core/tasks/tasks.service.spec.ts b/src/app/core/tasks/tasks.service.spec.ts index 753ce2ddd5..3ca9b8ea8f 100644 --- a/src/app/core/tasks/tasks.service.spec.ts +++ b/src/app/core/tasks/tasks.service.spec.ts @@ -29,7 +29,6 @@ class TestTask extends TaskObject { class TestService extends TasksService { protected linkPath = LINK_NAME; - protected forceBypassCache = true; constructor( protected requestService: RequestService, diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/journal-issue/journal-issue-grid-element.component.html b/src/app/entity-groups/journal-entities/item-grid-elements/journal-issue/journal-issue-grid-element.component.html index 3aa79fc70a..fb69ed92f5 100644 --- a/src/app/entity-groups/journal-entities/item-grid-elements/journal-issue/journal-issue-grid-element.component.html +++ b/src/app/entity-groups/journal-entities/item-grid-elements/journal-issue/journal-issue-grid-element.component.html @@ -1,30 +1 @@ - -
- -
- - -
-
-
- - -

-
-

- - - -

-

- - - -

-
- View -
-
-
-
+ \ No newline at end of file diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/journal-issue/journal-issue-grid-element.component.spec.ts b/src/app/entity-groups/journal-entities/item-grid-elements/journal-issue/journal-issue-grid-element.component.spec.ts index de16a05e5e..854ca1065d 100644 --- a/src/app/entity-groups/journal-entities/item-grid-elements/journal-issue/journal-issue-grid-element.component.spec.ts +++ b/src/app/entity-groups/journal-entities/item-grid-elements/journal-issue/journal-issue-grid-element.component.spec.ts @@ -1,15 +1,17 @@ -import { ItemSearchResult } from '../../../../shared/object-collection/shared/item-search-result.model'; import { Item } from '../../../../core/shared/item.model'; -import { of as observableOf } from 'rxjs/internal/observable/of'; -import { getEntityGridElementTestComponent } from '../../../../shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.spec'; import { JournalIssueGridElementComponent } from './journal-issue-grid-element.component'; import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils'; import { PaginatedList } from '../../../../core/data/paginated-list'; import { PageInfo } from '../../../../core/shared/page-info.model'; +import { of as observableOf } from 'rxjs'; +import { async, TestBed } from '@angular/core/testing'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { TruncatePipe } from '../../../../shared/utils/truncate.pipe'; +import { TruncatableService } from '../../../../shared/truncatable/truncatable.service'; +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { By } from '@angular/platform-browser'; -const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult(); -mockItemWithMetadata.hitHighlights = {}; -mockItemWithMetadata.indexableObject = Object.assign(new Item(), { +const mockItem = Object.assign(new Item(), { bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), metadata: { 'dc.title': [ @@ -33,18 +35,41 @@ mockItemWithMetadata.indexableObject = Object.assign(new Item(), { } }); -const mockItemWithoutMetadata: ItemSearchResult = new ItemSearchResult(); -mockItemWithoutMetadata.hitHighlights = {}; -mockItemWithoutMetadata.indexableObject = Object.assign(new Item(), { - bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), - metadata: { - 'dc.title': [ - { - language: 'en_US', - value: 'This is just another title' - } - ] - } -}); +describe('JournalIssueGridElementComponent', () => { + let comp; + let fixture; -describe('JournalIssueGridElementComponent', getEntityGridElementTestComponent(JournalIssueGridElementComponent, mockItemWithMetadata, mockItemWithoutMetadata, ['date', 'journal-title'])); + const truncatableServiceStub: any = { + isCollapsed: (id: number) => observableOf(true), + }; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [NoopAnimationsModule], + declarations: [JournalIssueGridElementComponent, TruncatePipe], + providers: [ + { provide: TruncatableService, useValue: truncatableServiceStub }, + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(JournalIssueGridElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(JournalIssueGridElementComponent); + comp = fixture.componentInstance; + })); + + describe(`when the journal issue is rendered`, () => { + beforeEach(() => { + comp.object = mockItem; + fixture.detectChanges(); + }); + + it(`should contain a JournalIssueSearchResultGridElementComponent`, () => { + const journalIssueGridElement = fixture.debugElement.query(By.css(`ds-journal-issue-search-result-grid-element`)); + expect(journalIssueGridElement).not.toBeNull(); + }); + }); +}); diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/journal-issue/journal-issue-grid-element.component.ts b/src/app/entity-groups/journal-entities/item-grid-elements/journal-issue/journal-issue-grid-element.component.ts index 06c27ebacf..3e57731613 100644 --- a/src/app/entity-groups/journal-entities/item-grid-elements/journal-issue/journal-issue-grid-element.component.ts +++ b/src/app/entity-groups/journal-entities/item-grid-elements/journal-issue/journal-issue-grid-element.component.ts @@ -1,17 +1,17 @@ -import { ItemViewMode, rendersItemType } from '../../../../shared/items/item-type-decorator'; import { Component } from '@angular/core'; -import { focusShadow } from '../../../../shared/animations/focus'; -import { TypedItemSearchResultGridElementComponent } from '../../../../shared/object-grid/item-grid-element/item-types/typed-item-search-result-grid-element.component'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; +import { listableObjectComponent } from '../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { AbstractListableElementComponent } from '../../../../shared/object-collection/shared/object-collection-element/abstract-listable-element.component'; +import { Item } from '../../../../core/shared/item.model'; -@rendersItemType('JournalIssue', ItemViewMode.Card) +@listableObjectComponent('JournalIssue', ViewMode.GridElement) @Component({ selector: 'ds-journal-issue-grid-element', styleUrls: ['./journal-issue-grid-element.component.scss'], templateUrl: './journal-issue-grid-element.component.html', - animations: [focusShadow] }) /** * The component for displaying a grid element for an item of the type Journal Issue */ -export class JournalIssueGridElementComponent extends TypedItemSearchResultGridElementComponent { +export class JournalIssueGridElementComponent extends AbstractListableElementComponent { } diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/journal-volume/journal-volume-grid-element.component.html b/src/app/entity-groups/journal-entities/item-grid-elements/journal-volume/journal-volume-grid-element.component.html index b2b251f550..53713b47ee 100644 --- a/src/app/entity-groups/journal-entities/item-grid-elements/journal-volume/journal-volume-grid-element.component.html +++ b/src/app/entity-groups/journal-entities/item-grid-elements/journal-volume/journal-volume-grid-element.component.html @@ -1,30 +1 @@ - -
- -
- - -
-
-
- - -

-
-

- - - -

-

- - - -

-
- View -
-
-
-
+ \ No newline at end of file diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/journal-volume/journal-volume-grid-element.component.spec.ts b/src/app/entity-groups/journal-entities/item-grid-elements/journal-volume/journal-volume-grid-element.component.spec.ts index 80479f597d..7405bb7ab4 100644 --- a/src/app/entity-groups/journal-entities/item-grid-elements/journal-volume/journal-volume-grid-element.component.spec.ts +++ b/src/app/entity-groups/journal-entities/item-grid-elements/journal-volume/journal-volume-grid-element.component.spec.ts @@ -1,15 +1,17 @@ -import { ItemSearchResult } from '../../../../shared/object-collection/shared/item-search-result.model'; import { Item } from '../../../../core/shared/item.model'; -import { of as observableOf } from 'rxjs/internal/observable/of'; -import { getEntityGridElementTestComponent } from '../../../../shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.spec'; import { JournalVolumeGridElementComponent } from './journal-volume-grid-element.component'; import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils'; import { PaginatedList } from '../../../../core/data/paginated-list'; import { PageInfo } from '../../../../core/shared/page-info.model'; +import { of as observableOf } from 'rxjs'; +import { async, TestBed } from '@angular/core/testing'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { TruncatePipe } from '../../../../shared/utils/truncate.pipe'; +import { TruncatableService } from '../../../../shared/truncatable/truncatable.service'; +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { By } from '@angular/platform-browser'; -const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult(); -mockItemWithMetadata.hitHighlights = {}; -mockItemWithMetadata.indexableObject = Object.assign(new Item(), { +const mockItem = Object.assign(new Item(), { bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), metadata: { 'dc.title': [ @@ -33,18 +35,41 @@ mockItemWithMetadata.indexableObject = Object.assign(new Item(), { } }); -const mockItemWithoutMetadata: ItemSearchResult = new ItemSearchResult(); -mockItemWithoutMetadata.hitHighlights = {}; -mockItemWithoutMetadata.indexableObject = Object.assign(new Item(), { - bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), - metadata: { - 'dc.title': [ - { - language: 'en_US', - value: 'This is just another title' - } - ] - } -}); +describe('JournalVolumeGridElementComponent', () => { + let comp; + let fixture; -describe('JournalVolumeGridElementComponent', getEntityGridElementTestComponent(JournalVolumeGridElementComponent, mockItemWithMetadata, mockItemWithoutMetadata, ['date', 'description'])); + const truncatableServiceStub: any = { + isCollapsed: (id: number) => observableOf(true), + }; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [NoopAnimationsModule], + declarations: [JournalVolumeGridElementComponent, TruncatePipe], + providers: [ + { provide: TruncatableService, useValue: truncatableServiceStub }, + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(JournalVolumeGridElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(JournalVolumeGridElementComponent); + comp = fixture.componentInstance; + })); + + describe(`when the journal volume is rendered`, () => { + beforeEach(() => { + comp.object = mockItem; + fixture.detectChanges(); + }); + + it(`should contain a JournalVolumeSearchResultGridElementComponent`, () => { + const journalVolumeGridElement = fixture.debugElement.query(By.css(`ds-journal-volume-search-result-grid-element`)); + expect(journalVolumeGridElement).not.toBeNull(); + }); + }); +}); diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/journal-volume/journal-volume-grid-element.component.ts b/src/app/entity-groups/journal-entities/item-grid-elements/journal-volume/journal-volume-grid-element.component.ts index e5183536ef..eb88c25a12 100644 --- a/src/app/entity-groups/journal-entities/item-grid-elements/journal-volume/journal-volume-grid-element.component.ts +++ b/src/app/entity-groups/journal-entities/item-grid-elements/journal-volume/journal-volume-grid-element.component.ts @@ -1,17 +1,17 @@ -import { ItemViewMode, rendersItemType } from '../../../../shared/items/item-type-decorator'; import { Component } from '@angular/core'; -import { focusShadow } from '../../../../shared/animations/focus'; -import { TypedItemSearchResultGridElementComponent } from '../../../../shared/object-grid/item-grid-element/item-types/typed-item-search-result-grid-element.component'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; +import { listableObjectComponent } from '../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { AbstractListableElementComponent } from '../../../../shared/object-collection/shared/object-collection-element/abstract-listable-element.component'; +import { Item } from '../../../../core/shared/item.model'; -@rendersItemType('JournalVolume', ItemViewMode.Card) +@listableObjectComponent('JournalVolume', ViewMode.GridElement) @Component({ selector: 'ds-journal-volume-grid-element', styleUrls: ['./journal-volume-grid-element.component.scss'], templateUrl: './journal-volume-grid-element.component.html', - animations: [focusShadow] }) /** * The component for displaying a grid element for an item of the type Journal Volume */ -export class JournalVolumeGridElementComponent extends TypedItemSearchResultGridElementComponent { +export class JournalVolumeGridElementComponent extends AbstractListableElementComponent { } diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/journal/journal-grid-element.component.html b/src/app/entity-groups/journal-entities/item-grid-elements/journal/journal-grid-element.component.html index af0739004c..594a0e0dc1 100644 --- a/src/app/entity-groups/journal-entities/item-grid-elements/journal/journal-grid-element.component.html +++ b/src/app/entity-groups/journal-entities/item-grid-elements/journal/journal-grid-element.component.html @@ -1,35 +1 @@ - -
- -
- - -
-
-
- - -

-
-

- - {{dso.firstMetadataValue('creativework.editor')}} - - , - {{dso.firstMetadataValue('creativework.publisher')}} - - -

-

- - - -

-
- View -
-
-
-
+ \ No newline at end of file diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/journal/journal-grid-element.component.spec.ts b/src/app/entity-groups/journal-entities/item-grid-elements/journal/journal-grid-element.component.spec.ts index 7376b571bd..7355c4aad1 100644 --- a/src/app/entity-groups/journal-entities/item-grid-elements/journal/journal-grid-element.component.spec.ts +++ b/src/app/entity-groups/journal-entities/item-grid-elements/journal/journal-grid-element.component.spec.ts @@ -1,15 +1,17 @@ -import { ItemSearchResult } from '../../../../shared/object-collection/shared/item-search-result.model'; import { Item } from '../../../../core/shared/item.model'; import { of as observableOf } from 'rxjs/internal/observable/of'; -import { getEntityGridElementTestComponent } from '../../../../shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.spec'; import { JournalGridElementComponent } from './journal-grid-element.component'; import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils'; import { PaginatedList } from '../../../../core/data/paginated-list'; import { PageInfo } from '../../../../core/shared/page-info.model'; +import { async, TestBed } from '@angular/core/testing'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { TruncatePipe } from '../../../../shared/utils/truncate.pipe'; +import { TruncatableService } from '../../../../shared/truncatable/truncatable.service'; +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { By } from '@angular/platform-browser'; -const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult(); -mockItemWithMetadata.hitHighlights = {}; -mockItemWithMetadata.indexableObject = Object.assign(new Item(), { +const mockItem = Object.assign(new Item(), { bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), metadata: { 'dc.title': [ @@ -39,18 +41,41 @@ mockItemWithMetadata.indexableObject = Object.assign(new Item(), { } }); -const mockItemWithoutMetadata: ItemSearchResult = new ItemSearchResult(); -mockItemWithoutMetadata.hitHighlights = {}; -mockItemWithoutMetadata.indexableObject = Object.assign(new Item(), { - bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), - metadata: { - 'dc.title': [ - { - language: 'en_US', - value: 'This is just another title' - } - ] - } -}); +describe('JournalGridElementComponent', () => { + let comp; + let fixture; -describe('JournalGridElementComponent', getEntityGridElementTestComponent(JournalGridElementComponent, mockItemWithMetadata, mockItemWithoutMetadata, ['editor', 'publisher', 'description'])); + const truncatableServiceStub: any = { + isCollapsed: (id: number) => observableOf(true), + }; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [NoopAnimationsModule], + declarations: [JournalGridElementComponent, TruncatePipe], + providers: [ + { provide: TruncatableService, useValue: truncatableServiceStub }, + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(JournalGridElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(JournalGridElementComponent); + comp = fixture.componentInstance; + })); + + describe(`when the journal is rendered`, () => { + beforeEach(() => { + comp.object = mockItem; + fixture.detectChanges(); + }); + + it(`should contain a JournalGridElementComponent`, () => { + const journalGridElement = fixture.debugElement.query(By.css(`ds-journal-search-result-grid-element`)); + expect(journalGridElement).not.toBeNull(); + }); + }); +}); diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/journal/journal-grid-element.component.ts b/src/app/entity-groups/journal-entities/item-grid-elements/journal/journal-grid-element.component.ts index 7f23211538..1d7c1e5b73 100644 --- a/src/app/entity-groups/journal-entities/item-grid-elements/journal/journal-grid-element.component.ts +++ b/src/app/entity-groups/journal-entities/item-grid-elements/journal/journal-grid-element.component.ts @@ -1,17 +1,17 @@ -import { ItemViewMode, rendersItemType } from '../../../../shared/items/item-type-decorator'; import { Component } from '@angular/core'; -import { focusShadow } from '../../../../shared/animations/focus'; -import { TypedItemSearchResultGridElementComponent } from '../../../../shared/object-grid/item-grid-element/item-types/typed-item-search-result-grid-element.component'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; +import { listableObjectComponent } from '../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { AbstractListableElementComponent } from '../../../../shared/object-collection/shared/object-collection-element/abstract-listable-element.component'; +import { Item } from '../../../../core/shared/item.model'; -@rendersItemType('Journal', ItemViewMode.Card) +@listableObjectComponent('Journal', ViewMode.GridElement) @Component({ selector: 'ds-journal-grid-element', styleUrls: ['./journal-grid-element.component.scss'], templateUrl: './journal-grid-element.component.html', - animations: [focusShadow] }) /** * The component for displaying a grid element for an item of the type Journal */ -export class JournalGridElementComponent extends TypedItemSearchResultGridElementComponent { +export class JournalGridElementComponent extends AbstractListableElementComponent { } diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.html b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.html new file mode 100644 index 0000000000..18ff77bf23 --- /dev/null +++ b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.html @@ -0,0 +1,36 @@ + +
+ +
+ + +
+
+ +
+ + +
+
+
+ + +

+
+

+ + + +

+

+ + + +

+
+ View +
+
+
+
diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component.scss b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.scss similarity index 100% rename from src/app/shared/object-detail/my-dspace-result-detail-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component.scss rename to src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.scss diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.spec.ts b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.spec.ts new file mode 100644 index 0000000000..98616daa0b --- /dev/null +++ b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.spec.ts @@ -0,0 +1,49 @@ +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { Item } from '../../../../../core/shared/item.model'; +import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/testing/utils'; +import { PaginatedList } from '../../../../../core/data/paginated-list'; +import { PageInfo } from '../../../../../core/shared/page-info.model'; +import { getEntityGridElementTestComponent } from '../../../../../shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.spec'; +import { JournalIssueSearchResultGridElementComponent } from './journal-issue-search-result-grid-element.component'; + +const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult(); +mockItemWithMetadata.hitHighlights = {}; +mockItemWithMetadata.indexableObject = Object.assign(new Item(), { + bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + 'creativework.datePublished': [ + { + language: null, + value: '2015-06-26' + } + ], + 'journal.title': [ + { + language: 'en_US', + value: 'The journal title' + } + ] + } +}); + +const mockItemWithoutMetadata: ItemSearchResult = new ItemSearchResult(); +mockItemWithoutMetadata.hitHighlights = {}; +mockItemWithoutMetadata.indexableObject = Object.assign(new Item(), { + bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ] + } +}); + +describe('JournalIssueSearchResultGridElementComponent', getEntityGridElementTestComponent(JournalIssueSearchResultGridElementComponent, mockItemWithMetadata, mockItemWithoutMetadata, ['date', 'journal-title'])); diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.ts b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.ts new file mode 100644 index 0000000000..9d27842c16 --- /dev/null +++ b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.ts @@ -0,0 +1,20 @@ +import { Component } from '@angular/core'; +import { ViewMode } from '../../../../../core/shared/view-mode.model'; +import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { focusShadow } from '../../../../../shared/animations/focus'; +import { SearchResultGridElementComponent } from '../../../../../shared/object-grid/search-result-grid-element/search-result-grid-element.component'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { Item } from '../../../../../core/shared/item.model'; + +@listableObjectComponent('JournalIssueSearchResult', ViewMode.GridElement) +@Component({ + selector: 'ds-journal-issue-search-result-grid-element', + styleUrls: ['./journal-issue-search-result-grid-element.component.scss'], + templateUrl: './journal-issue-search-result-grid-element.component.html', + animations: [focusShadow] +}) +/** + * The component for displaying a grid element for an item search result of the type Journal Issue + */ +export class JournalIssueSearchResultGridElementComponent extends SearchResultGridElementComponent { +} diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.html b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.html new file mode 100644 index 0000000000..07e50eb6fb --- /dev/null +++ b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.html @@ -0,0 +1,36 @@ + +
+ +
+ + +
+
+ +
+ + +
+
+
+ + +

+
+

+ + + +

+

+ + + +

+
+ View +
+
+
+
diff --git a/src/app/shared/object-list/item-list-element/item-list-element.component.scss b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.scss similarity index 100% rename from src/app/shared/object-list/item-list-element/item-list-element.component.scss rename to src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.scss diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.spec.ts b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.spec.ts new file mode 100644 index 0000000000..9dfa3c3ab3 --- /dev/null +++ b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.spec.ts @@ -0,0 +1,49 @@ +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { Item } from '../../../../../core/shared/item.model'; +import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/testing/utils'; +import { PaginatedList } from '../../../../../core/data/paginated-list'; +import { PageInfo } from '../../../../../core/shared/page-info.model'; +import { getEntityGridElementTestComponent } from '../../../../../shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.spec'; +import { JournalVolumeSearchResultGridElementComponent } from './journal-volume-search-result-grid-element.component'; + +const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult(); +mockItemWithMetadata.hitHighlights = {}; +mockItemWithMetadata.indexableObject = Object.assign(new Item(), { + bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + 'creativework.datePublished': [ + { + language: null, + value: '2015-06-26' + } + ], + 'dc.description': [ + { + language: 'en_US', + value: 'A description for the journal volume' + } + ] + } +}); + +const mockItemWithoutMetadata: ItemSearchResult = new ItemSearchResult(); +mockItemWithoutMetadata.hitHighlights = {}; +mockItemWithoutMetadata.indexableObject = Object.assign(new Item(), { + bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ] + } +}); + +describe('JournalVolumeSearchResultGridElementComponent', getEntityGridElementTestComponent(JournalVolumeSearchResultGridElementComponent, mockItemWithMetadata, mockItemWithoutMetadata, ['date', 'description'])); diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.ts b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.ts new file mode 100644 index 0000000000..802a6d8692 --- /dev/null +++ b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.ts @@ -0,0 +1,20 @@ +import { Component } from '@angular/core'; +import { SearchResultGridElementComponent } from '../../../../../shared/object-grid/search-result-grid-element/search-result-grid-element.component'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { Item } from '../../../../../core/shared/item.model'; +import { ViewMode } from '../../../../../core/shared/view-mode.model'; +import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { focusShadow } from '../../../../../shared/animations/focus'; + +@listableObjectComponent('JournalVolumeSearchResult', ViewMode.GridElement) +@Component({ + selector: 'ds-journal-volume-search-result-grid-element', + styleUrls: ['./journal-volume-search-result-grid-element.component.scss'], + templateUrl: './journal-volume-search-result-grid-element.component.html', + animations: [focusShadow] +}) +/** + * The component for displaying a grid element for an item search result of the type Journal Volume + */ +export class JournalVolumeSearchResultGridElementComponent extends SearchResultGridElementComponent { +} diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.html b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.html new file mode 100644 index 0000000000..394e5241e1 --- /dev/null +++ b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.html @@ -0,0 +1,41 @@ + +
+ +
+ + +
+
+ +
+ + +
+
+
+ + +

+
+

+ + {{firstMetadataValue('creativework.editor')}} + + , + {{firstMetadataValue('creativework.publisher')}} + + +

+

+ + + +

+
+ View +
+
+
+
diff --git a/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.scss b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.scss similarity index 100% rename from src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.scss rename to src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.scss diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.spec.ts b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.spec.ts new file mode 100644 index 0000000000..4aea6ef156 --- /dev/null +++ b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.spec.ts @@ -0,0 +1,55 @@ +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { Item } from '../../../../../core/shared/item.model'; +import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/testing/utils'; +import { PaginatedList } from '../../../../../core/data/paginated-list'; +import { PageInfo } from '../../../../../core/shared/page-info.model'; +import { getEntityGridElementTestComponent } from '../../../../../shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.spec'; +import { JournalSearchResultGridElementComponent } from './journal-search-result-grid-element.component'; + +const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult(); +mockItemWithMetadata.hitHighlights = {}; +mockItemWithMetadata.indexableObject = Object.assign(new Item(), { + bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + 'creativework.editor': [ + { + language: 'en_US', + value: 'Smith, Donald' + } + ], + 'creativework.publisher': [ + { + language: 'en_US', + value: 'A company' + } + ], + 'dc.description': [ + { + language: 'en_US', + value: 'This is the description' + } + ] + } +}); + +const mockItemWithoutMetadata: ItemSearchResult = new ItemSearchResult(); +mockItemWithoutMetadata.hitHighlights = {}; +mockItemWithoutMetadata.indexableObject = Object.assign(new Item(), { + bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ] + } +}); + +describe('JournalSearchResultGridElementComponent', getEntityGridElementTestComponent(JournalSearchResultGridElementComponent, mockItemWithMetadata, mockItemWithoutMetadata, ['editor', 'publisher', 'description'])); diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.ts b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.ts new file mode 100644 index 0000000000..97d43356c6 --- /dev/null +++ b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.ts @@ -0,0 +1,20 @@ +import { Component } from '@angular/core'; +import { focusShadow } from '../../../../../shared/animations/focus'; +import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { ViewMode } from '../../../../../core/shared/view-mode.model'; +import { SearchResultGridElementComponent } from '../../../../../shared/object-grid/search-result-grid-element/search-result-grid-element.component'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { Item } from '../../../../../core/shared/item.model'; + +@listableObjectComponent('JournalSearchResult', ViewMode.GridElement) +@Component({ + selector: 'ds-journal-search-result-grid-element', + styleUrls: ['./journal-search-result-grid-element.component.scss'], + templateUrl: './journal-search-result-grid-element.component.html', + animations: [focusShadow] +}) +/** + * The component for displaying a grid element for an item search result of the type Journal + */ +export class JournalSearchResultGridElementComponent extends SearchResultGridElementComponent { +} diff --git a/src/app/entity-groups/journal-entities/item-list-elements/journal-issue/journal-issue-list-element.component.html b/src/app/entity-groups/journal-entities/item-list-elements/journal-issue/journal-issue-list-element.component.html index 030a26df39..398feea260 100644 --- a/src/app/entity-groups/journal-entities/item-list-elements/journal-issue/journal-issue-list-element.component.html +++ b/src/app/entity-groups/journal-entities/item-list-elements/journal-issue/journal-issue-list-element.component.html @@ -1,21 +1 @@ - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/src/app/entity-groups/journal-entities/item-list-elements/journal-issue/journal-issue-list-element.component.spec.ts b/src/app/entity-groups/journal-entities/item-list-elements/journal-issue/journal-issue-list-element.component.spec.ts index a2df725fae..107776d16d 100644 --- a/src/app/entity-groups/journal-entities/item-list-elements/journal-issue/journal-issue-list-element.component.spec.ts +++ b/src/app/entity-groups/journal-entities/item-list-elements/journal-issue/journal-issue-list-element.component.spec.ts @@ -1,17 +1,13 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { async, TestBed } from '@angular/core/testing'; import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; import { By } from '@angular/platform-browser'; import { JournalIssueListElementComponent } from './journal-issue-list-element.component'; import { of as observableOf } from 'rxjs'; import { Item } from '../../../../core/shared/item.model'; import { TruncatePipe } from '../../../../shared/utils/truncate.pipe'; -import { ITEM } from '../../../../shared/items/switcher/item-type-switcher.component'; import { TruncatableService } from '../../../../shared/truncatable/truncatable.service'; -let journalIssueListElementComponent: JournalIssueListElementComponent; -let fixture: ComponentFixture; - -const mockItemWithMetadata: Item = Object.assign(new Item(), { +const mockItem: Item = Object.assign(new Item(), { bundles: observableOf({}), metadata: { 'dc.title': [ @@ -34,28 +30,22 @@ const mockItemWithMetadata: Item = Object.assign(new Item(), { ] } }); -const mockItemWithoutMetadata: Item = Object.assign(new Item(), { - bundles: observableOf({}), - metadata: { - 'dc.title': [ - { - language: 'en_US', - value: 'This is just another title' - } - ] - } -}); describe('JournalIssueListElementComponent', () => { + let comp; + let fixture; + + const truncatableServiceStub: any = { + isCollapsed: (id: number) => observableOf(true), + }; + beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ JournalIssueListElementComponent , TruncatePipe], + declarations: [JournalIssueListElementComponent, TruncatePipe], providers: [ - { provide: ITEM, useValue: mockItemWithMetadata}, - { provide: TruncatableService, useValue: {} } + { provide: TruncatableService, useValue: truncatableServiceStub }, ], - - schemas: [ NO_ERRORS_SCHEMA ] + schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(JournalIssueListElementComponent, { set: { changeDetection: ChangeDetectionStrategy.Default } }).compileComponents(); @@ -63,55 +53,19 @@ describe('JournalIssueListElementComponent', () => { beforeEach(async(() => { fixture = TestBed.createComponent(JournalIssueListElementComponent); - journalIssueListElementComponent = fixture.componentInstance; - + comp = fixture.componentInstance; })); - describe('When the item has a journal identifier', () => { + describe(`when the journal issue is rendered`, () => { beforeEach(() => { - journalIssueListElementComponent.item = mockItemWithMetadata; + comp.object = mockItem; fixture.detectChanges(); }); - it('should show the journal issues span', () => { - const journalIdentifierField = fixture.debugElement.query(By.css('span.item-list-journal-issues')); - expect(journalIdentifierField).not.toBeNull(); + it(`should contain a JournalIssueListElementComponent`, () => { + const journalIssueListElement = fixture.debugElement.query(By.css(`ds-journal-issue-search-result-list-element`)); + expect(journalIssueListElement).not.toBeNull(); }); }); - describe('When the item has no journal identifier', () => { - beforeEach(() => { - journalIssueListElementComponent.item = mockItemWithoutMetadata; - fixture.detectChanges(); - }); - - it('should not show the journal issues span', () => { - const journalIdentifierField = fixture.debugElement.query(By.css('span.item-list-journal-issues')); - expect(journalIdentifierField).toBeNull(); - }); - }); - - describe('When the item has a journal number', () => { - beforeEach(() => { - journalIssueListElementComponent.item = mockItemWithMetadata; - fixture.detectChanges(); - }); - - it('should show the journal issue numbers span', () => { - const journalNumberField = fixture.debugElement.query(By.css('span.item-list-journal-issue-numbers')); - expect(journalNumberField).not.toBeNull(); - }); - }); - - describe('When the item has no journal number', () => { - beforeEach(() => { - journalIssueListElementComponent.item = mockItemWithoutMetadata; - fixture.detectChanges(); - }); - - it('should not show the journal issue numbers span', () => { - const journalNumberField = fixture.debugElement.query(By.css('span.item-list-journal-issue-numbers')); - expect(journalNumberField).toBeNull(); - }); - }); }); diff --git a/src/app/entity-groups/journal-entities/item-list-elements/journal-issue/journal-issue-list-element.component.ts b/src/app/entity-groups/journal-entities/item-list-elements/journal-issue/journal-issue-list-element.component.ts index e1aeb7c4e6..454c140050 100644 --- a/src/app/entity-groups/journal-entities/item-list-elements/journal-issue/journal-issue-list-element.component.ts +++ b/src/app/entity-groups/journal-entities/item-list-elements/journal-issue/journal-issue-list-element.component.ts @@ -1,8 +1,10 @@ import { Component } from '@angular/core'; -import { ItemViewMode, rendersItemType } from '../../../../shared/items/item-type-decorator'; -import { TypedItemSearchResultListElementComponent } from '../../../../shared/object-list/item-list-element/item-types/typed-item-search-result-list-element.component'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; +import { listableObjectComponent } from '../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { AbstractListableElementComponent } from '../../../../shared/object-collection/shared/object-collection-element/abstract-listable-element.component'; +import { Item } from '../../../../core/shared/item.model'; -@rendersItemType('JournalIssue', ItemViewMode.Element) +@listableObjectComponent('JournalIssue', ViewMode.ListElement) @Component({ selector: 'ds-journal-issue-list-element', styleUrls: ['./journal-issue-list-element.component.scss'], @@ -11,5 +13,5 @@ import { TypedItemSearchResultListElementComponent } from '../../../../shared/ob /** * The component for displaying a list element for an item of the type Journal Issue */ -export class JournalIssueListElementComponent extends TypedItemSearchResultListElementComponent { +export class JournalIssueListElementComponent extends AbstractListableElementComponent { } diff --git a/src/app/entity-groups/journal-entities/item-list-elements/journal-volume/journal-volume-list-element.component.html b/src/app/entity-groups/journal-entities/item-list-elements/journal-volume/journal-volume-list-element.component.html index 4e6e34d3d6..bf967e6e78 100644 --- a/src/app/entity-groups/journal-entities/item-list-elements/journal-volume/journal-volume-list-element.component.html +++ b/src/app/entity-groups/journal-entities/item-list-elements/journal-volume/journal-volume-list-element.component.html @@ -1,21 +1 @@ - - - - - - - - - - - - () - - - - - + \ No newline at end of file diff --git a/src/app/entity-groups/journal-entities/item-list-elements/journal-volume/journal-volume-list-element.component.spec.ts b/src/app/entity-groups/journal-entities/item-list-elements/journal-volume/journal-volume-list-element.component.spec.ts index c2220b155c..14ea91204a 100644 --- a/src/app/entity-groups/journal-entities/item-list-elements/journal-volume/journal-volume-list-element.component.spec.ts +++ b/src/app/entity-groups/journal-entities/item-list-elements/journal-volume/journal-volume-list-element.component.spec.ts @@ -1,17 +1,13 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { async, TestBed } from '@angular/core/testing'; import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; import { By } from '@angular/platform-browser'; import { JournalVolumeListElementComponent } from './journal-volume-list-element.component'; import { of as observableOf } from 'rxjs'; import { Item } from '../../../../core/shared/item.model'; import { TruncatePipe } from '../../../../shared/utils/truncate.pipe'; -import { ITEM } from '../../../../shared/items/switcher/item-type-switcher.component'; import { TruncatableService } from '../../../../shared/truncatable/truncatable.service'; -let journalVolumeListElementComponent: JournalVolumeListElementComponent; -let fixture: ComponentFixture; - -const mockItemWithMetadata: Item = Object.assign(new Item(), { +const mockItem: Item = Object.assign(new Item(), { bundles: observableOf({}), metadata: { 'dc.title': [ @@ -34,28 +30,22 @@ const mockItemWithMetadata: Item = Object.assign(new Item(), { ] } }); -const mockItemWithoutMetadata: Item = Object.assign(new Item(), { - bundles: observableOf({}), - metadata: { - 'dc.title': [ - { - language: 'en_US', - value: 'This is just another title' - } - ] - } -}); describe('JournalVolumeListElementComponent', () => { + let comp; + let fixture; + + const truncatableServiceStub: any = { + isCollapsed: (id: number) => observableOf(true), + }; + beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ JournalVolumeListElementComponent , TruncatePipe], + declarations: [JournalVolumeListElementComponent, TruncatePipe], providers: [ - { provide: ITEM, useValue: mockItemWithMetadata}, - { provide: TruncatableService, useValue: {} } + { provide: TruncatableService, useValue: truncatableServiceStub }, ], - - schemas: [ NO_ERRORS_SCHEMA ] + schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(JournalVolumeListElementComponent, { set: { changeDetection: ChangeDetectionStrategy.Default } }).compileComponents(); @@ -63,55 +53,18 @@ describe('JournalVolumeListElementComponent', () => { beforeEach(async(() => { fixture = TestBed.createComponent(JournalVolumeListElementComponent); - journalVolumeListElementComponent = fixture.componentInstance; - + comp = fixture.componentInstance; })); - describe('When the item has a journal title', () => { + describe(`when the journal volume is rendered`, () => { beforeEach(() => { - journalVolumeListElementComponent.item = mockItemWithMetadata; + comp.object = mockItem; fixture.detectChanges(); }); - it('should show the journal title span', () => { - const journalTitleField = fixture.debugElement.query(By.css('span.item-list-journal-volumes')); - expect(journalTitleField).not.toBeNull(); - }); - }); - - describe('When the item has no journal title', () => { - beforeEach(() => { - journalVolumeListElementComponent.item = mockItemWithoutMetadata; - fixture.detectChanges(); - }); - - it('should not show the journal title span', () => { - const journalTitleField = fixture.debugElement.query(By.css('span.item-list-journal-volumes')); - expect(journalTitleField).toBeNull(); - }); - }); - - describe('When the item has a journal identifier', () => { - beforeEach(() => { - journalVolumeListElementComponent.item = mockItemWithMetadata; - fixture.detectChanges(); - }); - - it('should show the journal identifiers span', () => { - const journalIdentifierField = fixture.debugElement.query(By.css('span.item-list-journal-volume-identifiers')); - expect(journalIdentifierField).not.toBeNull(); - }); - }); - - describe('When the item has no journal identifier', () => { - beforeEach(() => { - journalVolumeListElementComponent.item = mockItemWithoutMetadata; - fixture.detectChanges(); - }); - - it('should not show the journal identifiers span', () => { - const journalIdentifierField = fixture.debugElement.query(By.css('span.item-list-journal-volume-identifiers')); - expect(journalIdentifierField).toBeNull(); + it(`should contain a JournalVolumeListElementComponent`, () => { + const journalVolumeListElement = fixture.debugElement.query(By.css(`ds-journal-volume-search-result-list-element`)); + expect(journalVolumeListElement).not.toBeNull(); }); }); }); diff --git a/src/app/entity-groups/journal-entities/item-list-elements/journal-volume/journal-volume-list-element.component.ts b/src/app/entity-groups/journal-entities/item-list-elements/journal-volume/journal-volume-list-element.component.ts index 42e83ea7bd..641a0d2238 100644 --- a/src/app/entity-groups/journal-entities/item-list-elements/journal-volume/journal-volume-list-element.component.ts +++ b/src/app/entity-groups/journal-entities/item-list-elements/journal-volume/journal-volume-list-element.component.ts @@ -1,8 +1,10 @@ import { Component } from '@angular/core'; -import { ItemViewMode, rendersItemType } from '../../../../shared/items/item-type-decorator'; -import { TypedItemSearchResultListElementComponent } from '../../../../shared/object-list/item-list-element/item-types/typed-item-search-result-list-element.component'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; +import { listableObjectComponent } from '../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { AbstractListableElementComponent } from '../../../../shared/object-collection/shared/object-collection-element/abstract-listable-element.component'; +import { Item } from '../../../../core/shared/item.model'; -@rendersItemType('JournalVolume', ItemViewMode.Element) +@listableObjectComponent('JournalVolume', ViewMode.ListElement) @Component({ selector: 'ds-journal-volume-list-element', styleUrls: ['./journal-volume-list-element.component.scss'], @@ -11,5 +13,5 @@ import { TypedItemSearchResultListElementComponent } from '../../../../shared/ob /** * The component for displaying a list element for an item of the type Journal Volume */ -export class JournalVolumeListElementComponent extends TypedItemSearchResultListElementComponent { +export class JournalVolumeListElementComponent extends AbstractListableElementComponent { } diff --git a/src/app/entity-groups/journal-entities/item-list-elements/journal/journal-list-element.component.html b/src/app/entity-groups/journal-entities/item-list-elements/journal/journal-list-element.component.html index 0e46e921bb..3e4dfb0b48 100644 --- a/src/app/entity-groups/journal-entities/item-list-elements/journal/journal-list-element.component.html +++ b/src/app/entity-groups/journal-entities/item-list-elements/journal/journal-list-element.component.html @@ -1,15 +1 @@ - - - - - - - - - - - - + \ No newline at end of file diff --git a/src/app/entity-groups/journal-entities/item-list-elements/journal/journal-list-element.component.spec.ts b/src/app/entity-groups/journal-entities/item-list-elements/journal/journal-list-element.component.spec.ts index 4f07bb2d07..8b8ca974f6 100644 --- a/src/app/entity-groups/journal-entities/item-list-elements/journal/journal-list-element.component.spec.ts +++ b/src/app/entity-groups/journal-entities/item-list-elements/journal/journal-list-element.component.spec.ts @@ -1,17 +1,13 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { async, TestBed } from '@angular/core/testing'; import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; import { By } from '@angular/platform-browser'; import { JournalListElementComponent } from './journal-list-element.component'; import { of as observableOf } from 'rxjs'; import { Item } from '../../../../core/shared/item.model'; import { TruncatePipe } from '../../../../shared/utils/truncate.pipe'; -import { ITEM } from '../../../../shared/items/switcher/item-type-switcher.component'; import { TruncatableService } from '../../../../shared/truncatable/truncatable.service'; -let journalListElementComponent: JournalListElementComponent; -let fixture: ComponentFixture; - -const mockItemWithMetadata: Item = Object.assign(new Item(), { +const mockItem: Item = Object.assign(new Item(), { bundles: observableOf({}), metadata: { 'dc.title': [ @@ -28,28 +24,22 @@ const mockItemWithMetadata: Item = Object.assign(new Item(), { ] } }); -const mockItemWithoutMetadata: Item = Object.assign(new Item(), { - bundles: observableOf({}), - metadata: { - 'dc.title': [ - { - language: 'en_US', - value: 'This is just another title' - } - ] - } -}); describe('JournalListElementComponent', () => { + let comp; + let fixture; + + const truncatableServiceStub: any = { + isCollapsed: (id: number) => observableOf(true), + }; + beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ JournalListElementComponent , TruncatePipe], + declarations: [JournalListElementComponent, TruncatePipe], providers: [ - { provide: ITEM, useValue: mockItemWithMetadata}, - { provide: TruncatableService, useValue: {} } + { provide: TruncatableService, useValue: truncatableServiceStub }, ], - - schemas: [ NO_ERRORS_SCHEMA ] + schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(JournalListElementComponent, { set: { changeDetection: ChangeDetectionStrategy.Default } }).compileComponents(); @@ -57,31 +47,18 @@ describe('JournalListElementComponent', () => { beforeEach(async(() => { fixture = TestBed.createComponent(JournalListElementComponent); - journalListElementComponent = fixture.componentInstance; - + comp = fixture.componentInstance; })); - describe('When the item has an issn', () => { + describe(`when the journal is rendered`, () => { beforeEach(() => { - journalListElementComponent.item = mockItemWithMetadata; + comp.object = mockItem; fixture.detectChanges(); }); - it('should show the journals span', () => { - const issnField = fixture.debugElement.query(By.css('span.item-list-journals')); - expect(issnField).not.toBeNull(); - }); - }); - - describe('When the item has no issn', () => { - beforeEach(() => { - journalListElementComponent.item = mockItemWithoutMetadata; - fixture.detectChanges(); - }); - - it('should not show the journals span', () => { - const issnField = fixture.debugElement.query(By.css('span.item-list-journals')); - expect(issnField).toBeNull(); + it(`should contain a JournalListElementComponent`, () => { + const journalListElement = fixture.debugElement.query(By.css(`ds-journal-search-result-list-element`)); + expect(journalListElement).not.toBeNull(); }); }); }); diff --git a/src/app/entity-groups/journal-entities/item-list-elements/journal/journal-list-element.component.ts b/src/app/entity-groups/journal-entities/item-list-elements/journal/journal-list-element.component.ts index fdcf0ba5b0..fa83c3cff4 100644 --- a/src/app/entity-groups/journal-entities/item-list-elements/journal/journal-list-element.component.ts +++ b/src/app/entity-groups/journal-entities/item-list-elements/journal/journal-list-element.component.ts @@ -1,8 +1,10 @@ import { Component } from '@angular/core'; -import { ItemViewMode, rendersItemType } from '../../../../shared/items/item-type-decorator'; -import { TypedItemSearchResultListElementComponent } from '../../../../shared/object-list/item-list-element/item-types/typed-item-search-result-list-element.component'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; +import { listableObjectComponent } from '../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { AbstractListableElementComponent } from '../../../../shared/object-collection/shared/object-collection-element/abstract-listable-element.component'; +import { Item } from '../../../../core/shared/item.model'; -@rendersItemType('Journal', ItemViewMode.Element) +@listableObjectComponent('Journal', ViewMode.ListElement) @Component({ selector: 'ds-journal-list-element', styleUrls: ['./journal-list-element.component.scss'], @@ -11,5 +13,5 @@ import { TypedItemSearchResultListElementComponent } from '../../../../shared/ob /** * The component for displaying a list element for an item of the type Journal */ -export class JournalListElementComponent extends TypedItemSearchResultListElementComponent { +export class JournalListElementComponent extends AbstractListableElementComponent { } diff --git a/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-issue/journal-issue-search-result-list-element.component.html b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-issue/journal-issue-search-result-list-element.component.html new file mode 100644 index 0000000000..38094c5c79 --- /dev/null +++ b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-issue/journal-issue-search-result-list-element.component.html @@ -0,0 +1,25 @@ + + + + + + + + + + + + + - + + + + + + diff --git a/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-issue/journal-issue-search-result-list-element.component.scss b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-issue/journal-issue-search-result-list-element.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-issue/journal-issue-search-result-list-element.component.spec.ts b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-issue/journal-issue-search-result-list-element.component.spec.ts new file mode 100644 index 0000000000..34a5f93d7c --- /dev/null +++ b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-issue/journal-issue-search-result-list-element.component.spec.ts @@ -0,0 +1,125 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { By } from '@angular/platform-browser'; +import { of as observableOf } from 'rxjs'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { JournalIssueSearchResultListElementComponent } from './journal-issue-search-result-list-element.component'; +import { Item } from '../../../../../core/shared/item.model'; +import { TruncatePipe } from '../../../../../shared/utils/truncate.pipe'; +import { TruncatableService } from '../../../../../shared/truncatable/truncatable.service'; + +let journalIssueListElementComponent: JournalIssueSearchResultListElementComponent; +let fixture: ComponentFixture; + +const mockItemWithMetadata: ItemSearchResult = Object.assign( + new ItemSearchResult(), + { + indexableObject: Object.assign(new Item(), { + bundles: observableOf({}), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + 'publicationvolume.volumeNumber': [ + { + language: 'en_US', + value: '1234' + } + ], + 'publicationissue.issueNumber': [ + { + language: 'en_US', + value: '5678' + } + ] + } + }) + }); + +const mockItemWithoutMetadata: ItemSearchResult = Object.assign( + new ItemSearchResult(), + { + indexableObject: Object.assign(new Item(), { + bundles: observableOf({}), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ] + } + }) + }); + +describe('JournalIssueSearchResultListElementComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [JournalIssueSearchResultListElementComponent, TruncatePipe], + providers: [ + { provide: TruncatableService, useValue: {} } + ], + + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(JournalIssueSearchResultListElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(JournalIssueSearchResultListElementComponent); + journalIssueListElementComponent = fixture.componentInstance; + + })); + + describe('When the item has a journal identifier', () => { + beforeEach(() => { + journalIssueListElementComponent.object = mockItemWithMetadata; + fixture.detectChanges(); + }); + + it('should show the journal issues span', () => { + const journalIdentifierField = fixture.debugElement.query(By.css('span.item-list-journal-issues')); + expect(journalIdentifierField).not.toBeNull(); + }); + }); + + describe('When the item has no journal identifier', () => { + beforeEach(() => { + journalIssueListElementComponent.object = mockItemWithoutMetadata; + fixture.detectChanges(); + }); + + it('should not show the journal issues span', () => { + const journalIdentifierField = fixture.debugElement.query(By.css('span.item-list-journal-issues')); + expect(journalIdentifierField).toBeNull(); + }); + }); + + describe('When the item has a journal number', () => { + beforeEach(() => { + journalIssueListElementComponent.object = mockItemWithMetadata; + fixture.detectChanges(); + }); + + it('should show the journal issue numbers span', () => { + const journalNumberField = fixture.debugElement.query(By.css('span.item-list-journal-issue-numbers')); + expect(journalNumberField).not.toBeNull(); + }); + }); + + describe('When the item has no journal number', () => { + beforeEach(() => { + journalIssueListElementComponent.object = mockItemWithoutMetadata; + fixture.detectChanges(); + }); + + it('should not show the journal issue numbers span', () => { + const journalNumberField = fixture.debugElement.query(By.css('span.item-list-journal-issue-numbers')); + expect(journalNumberField).toBeNull(); + }); + }); +}); diff --git a/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-issue/journal-issue-search-result-list-element.component.ts b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-issue/journal-issue-search-result-list-element.component.ts new file mode 100644 index 0000000000..1d320cbfe8 --- /dev/null +++ b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-issue/journal-issue-search-result-list-element.component.ts @@ -0,0 +1,18 @@ +import { Component } from '@angular/core'; +import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { ViewMode } from '../../../../../core/shared/view-mode.model'; +import { SearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/search-result-list-element.component'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { Item } from '../../../../../core/shared/item.model'; + +@listableObjectComponent('JournalIssueSearchResult', ViewMode.ListElement) +@Component({ + selector: 'ds-journal-issue-search-result-list-element', + styleUrls: ['./journal-issue-search-result-list-element.component.scss'], + templateUrl: './journal-issue-search-result-list-element.component.html' +}) +/** + * The component for displaying a list element for an item search result of the type Journal Issue + */ +export class JournalIssueSearchResultListElementComponent extends SearchResultListElementComponent { +} diff --git a/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-volume/journal-volume-search-result-list-element.component.html b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-volume/journal-volume-search-result-list-element.component.html new file mode 100644 index 0000000000..460c4a2187 --- /dev/null +++ b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-volume/journal-volume-search-result-list-element.component.html @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + () + + + + + diff --git a/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-volume/journal-volume-search-result-list-element.component.scss b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-volume/journal-volume-search-result-list-element.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-volume/journal-volume-search-result-list-element.component.spec.ts b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-volume/journal-volume-search-result-list-element.component.spec.ts new file mode 100644 index 0000000000..64e2ff2e59 --- /dev/null +++ b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-volume/journal-volume-search-result-list-element.component.spec.ts @@ -0,0 +1,124 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { By } from '@angular/platform-browser'; +import { of as observableOf } from 'rxjs'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { Item } from '../../../../../core/shared/item.model'; +import { JournalVolumeSearchResultListElementComponent } from './journal-volume-search-result-list-element.component'; +import { TruncatePipe } from '../../../../../shared/utils/truncate.pipe'; +import { TruncatableService } from '../../../../../shared/truncatable/truncatable.service'; + +let journalVolumeListElementComponent: JournalVolumeSearchResultListElementComponent; +let fixture: ComponentFixture; + +const mockItemWithMetadata: ItemSearchResult = Object.assign( + new ItemSearchResult(), + { + indexableObject: Object.assign(new Item(), { + bundles: observableOf({}), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + 'journal.title': [ + { + language: 'en_US', + value: 'This is just another journal title' + } + ], + 'publicationvolume.volumeNumber': [ + { + language: 'en_US', + value: '1234' + } + ] + } + }) + }); +const mockItemWithoutMetadata: ItemSearchResult = Object.assign( + new ItemSearchResult(), + { + indexableObject: Object.assign(new Item(), { + bundles: observableOf({}), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ] + } + }) + }); + +describe('JournalVolumeSearchResultListElementComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [JournalVolumeSearchResultListElementComponent, TruncatePipe], + providers: [ + { provide: TruncatableService, useValue: {} } + ], + + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(JournalVolumeSearchResultListElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(JournalVolumeSearchResultListElementComponent); + journalVolumeListElementComponent = fixture.componentInstance; + + })); + + describe('When the item has a journal title', () => { + beforeEach(() => { + journalVolumeListElementComponent.object = mockItemWithMetadata; + fixture.detectChanges(); + }); + + it('should show the journal title span', () => { + const journalTitleField = fixture.debugElement.query(By.css('span.item-list-journal-volumes')); + expect(journalTitleField).not.toBeNull(); + }); + }); + + describe('When the item has no journal title', () => { + beforeEach(() => { + journalVolumeListElementComponent.object = mockItemWithoutMetadata; + fixture.detectChanges(); + }); + + it('should not show the journal title span', () => { + const journalTitleField = fixture.debugElement.query(By.css('span.item-list-journal-volumes')); + expect(journalTitleField).toBeNull(); + }); + }); + + describe('When the item has a journal identifier', () => { + beforeEach(() => { + journalVolumeListElementComponent.object = mockItemWithMetadata; + fixture.detectChanges(); + }); + + it('should show the journal identifiers span', () => { + const journalIdentifierField = fixture.debugElement.query(By.css('span.item-list-journal-volume-identifiers')); + expect(journalIdentifierField).not.toBeNull(); + }); + }); + + describe('When the item has no journal identifier', () => { + beforeEach(() => { + journalVolumeListElementComponent.object = mockItemWithoutMetadata; + fixture.detectChanges(); + }); + + it('should not show the journal identifiers span', () => { + const journalIdentifierField = fixture.debugElement.query(By.css('span.item-list-journal-volume-identifiers')); + expect(journalIdentifierField).toBeNull(); + }); + }); +}); diff --git a/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-volume/journal-volume-search-result-list-element.component.ts b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-volume/journal-volume-search-result-list-element.component.ts new file mode 100644 index 0000000000..41795b8022 --- /dev/null +++ b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-volume/journal-volume-search-result-list-element.component.ts @@ -0,0 +1,18 @@ +import { Component } from '@angular/core'; +import { SearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/search-result-list-element.component'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { Item } from '../../../../../core/shared/item.model'; +import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { ViewMode } from '../../../../../core/shared/view-mode.model'; + +@listableObjectComponent('JournalVolumeSearchResult', ViewMode.ListElement) +@Component({ + selector: 'ds-journal-volume-search-result-list-element', + styleUrls: ['./journal-volume-search-result-list-element.component.scss'], + templateUrl: './journal-volume-search-result-list-element.component.html' +}) +/** + * The component for displaying a list element for an item search result of the type Journal Volume + */ +export class JournalVolumeSearchResultListElementComponent extends SearchResultListElementComponent { +} diff --git a/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal/journal-search-result-list-element.component.html b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal/journal-search-result-list-element.component.html new file mode 100644 index 0000000000..a43132d332 --- /dev/null +++ b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal/journal-search-result-list-element.component.html @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + diff --git a/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal/journal-search-result-list-element.component.scss b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal/journal-search-result-list-element.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal/journal-search-result-list-element.component.spec.ts b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal/journal-search-result-list-element.component.spec.ts new file mode 100644 index 0000000000..2af226bfb3 --- /dev/null +++ b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal/journal-search-result-list-element.component.spec.ts @@ -0,0 +1,96 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { By } from '@angular/platform-browser'; +import { of as observableOf } from 'rxjs'; +import { JournalSearchResultListElementComponent } from './journal-search-result-list-element.component'; +import { Item } from '../../../../../core/shared/item.model'; +import { TruncatePipe } from '../../../../../shared/utils/truncate.pipe'; +import { TruncatableService } from '../../../../../shared/truncatable/truncatable.service'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; + +let journalListElementComponent: JournalSearchResultListElementComponent; +let fixture: ComponentFixture; + +const mockItemWithMetadata: ItemSearchResult = Object.assign( + new ItemSearchResult(), + { + indexableObject: Object.assign(new Item(), { + bundles: observableOf({}), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + 'creativeworkseries.issn': [ + { + language: 'en_US', + value: '1234' + } + ] + } + }) + }); + +const mockItemWithoutMetadata: ItemSearchResult = Object.assign( + new ItemSearchResult(), + { + indexableObject: Object.assign(new Item(), { + bundles: observableOf({}), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ] + } + }) + } +); + +describe('JournalSearchResultListElementComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [JournalSearchResultListElementComponent, TruncatePipe], + providers: [ + { provide: TruncatableService, useValue: {} } + ], + + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(JournalSearchResultListElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(JournalSearchResultListElementComponent); + journalListElementComponent = fixture.componentInstance; + + })); + + describe('When the item has an issn', () => { + beforeEach(() => { + journalListElementComponent.object = mockItemWithMetadata; + fixture.detectChanges(); + }); + + it('should show the journals span', () => { + const issnField = fixture.debugElement.query(By.css('span.item-list-journals')); + expect(issnField).not.toBeNull(); + }); + }); + + describe('When the item has no issn', () => { + beforeEach(() => { + journalListElementComponent.object = mockItemWithoutMetadata; + fixture.detectChanges(); + }); + + it('should not show the journals span', () => { + const issnField = fixture.debugElement.query(By.css('span.item-list-journals')); + expect(issnField).toBeNull(); + }); + }); +}); diff --git a/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal/journal-search-result-list-element.component.ts b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal/journal-search-result-list-element.component.ts new file mode 100644 index 0000000000..01de0d4626 --- /dev/null +++ b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal/journal-search-result-list-element.component.ts @@ -0,0 +1,18 @@ +import { Component } from '@angular/core'; +import { SearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/search-result-list-element.component'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { Item } from '../../../../../core/shared/item.model'; +import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { ViewMode } from '../../../../../core/shared/view-mode.model'; + +@listableObjectComponent('JournalSearchResult', ViewMode.ListElement) +@Component({ + selector: 'ds-journal-search-result-list-element', + styleUrls: ['./journal-search-result-list-element.component.scss'], + templateUrl: './journal-search-result-list-element.component.html' +}) +/** + * The component for displaying a list element for an item search result of the type Journal + */ +export class JournalSearchResultListElementComponent extends SearchResultListElementComponent { +} diff --git a/src/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.html b/src/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.html index eebd3e03c8..87312f8784 100644 --- a/src/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.html +++ b/src/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.html @@ -1,52 +1,54 @@

- {{'journalissue.page.titleprefix' | translate}} + {{'journalissue.page.titleprefix' | translate}}

- + - - - - -
- - diff --git a/src/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.spec.ts b/src/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.spec.ts index 897fc9dc72..64c1fc3bf7 100644 --- a/src/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.spec.ts +++ b/src/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.spec.ts @@ -1,13 +1,8 @@ import { Item } from '../../../../core/shared/item.model'; -import { RemoteData } from '../../../../core/data/remote-data'; import { PaginatedList } from '../../../../core/data/paginated-list'; import { PageInfo } from '../../../../core/shared/page-info.model'; import { JournalIssueComponent } from './journal-issue.component'; -import { of as observableOf } from 'rxjs'; -import { - createRelationshipsObservable, - getItemPageFieldsTest -} from '../../../../+item-page/simple/item-types/shared/item.component.spec'; +import { createRelationshipsObservable, getItemPageFieldsTest } from '../../../../+item-page/simple/item-types/shared/item.component.spec'; import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils'; const mockItem: Item = Object.assign(new Item(), { diff --git a/src/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.ts b/src/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.ts index b584fa3285..6f1cbf9923 100644 --- a/src/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.ts +++ b/src/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.ts @@ -1,12 +1,9 @@ import { Component } from '@angular/core'; -import { Observable } from 'rxjs'; -import { Item } from '../../../../core/shared/item.model'; -import { ItemViewMode, rendersItemType } from '../../../../shared/items/item-type-decorator'; -import { isNotEmpty } from '../../../../shared/empty.util'; import { ItemComponent } from '../../../../+item-page/simple/item-types/shared/item.component'; -import { getRelatedItemsByTypeLabel } from '../../../../+item-page/simple/item-types/shared/item-relationships-utils'; +import { listableObjectComponent } from '../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; -@rendersItemType('JournalIssue', ItemViewMode.Full) +@listableObjectComponent('JournalIssue', ViewMode.StandalonePage) @Component({ selector: 'ds-journal-issue', styleUrls: ['./journal-issue.component.scss'], @@ -16,26 +13,4 @@ import { getRelatedItemsByTypeLabel } from '../../../../+item-page/simple/item-t * The component for displaying metadata and relations of an item of the type Journal Issue */ export class JournalIssueComponent extends ItemComponent { - /** - * The volumes related to this journal issue - */ - volumes$: Observable; - - /** - * The publications related to this journal issue - */ - publications$: Observable; - - ngOnInit(): void { - super.ngOnInit(); - - if (isNotEmpty(this.resolvedRelsAndTypes$)) { - this.volumes$ = this.resolvedRelsAndTypes$.pipe( - getRelatedItemsByTypeLabel(this.item.id, 'isJournalVolumeOfIssue') - ); - this.publications$ = this.resolvedRelsAndTypes$.pipe( - getRelatedItemsByTypeLabel(this.item.id, 'isPublicationOfJournalIssue') - ); - } - } } diff --git a/src/app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.html b/src/app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.html index 83626c7ae7..e77b24a98b 100644 --- a/src/app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.html +++ b/src/app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.html @@ -1,35 +1,37 @@

- {{'journalvolume.page.titleprefix' | translate}} + {{'journalvolume.page.titleprefix' | translate}}

- + - -
- diff --git a/src/app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.ts b/src/app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.ts index 66df0b8104..4219609aab 100644 --- a/src/app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.ts +++ b/src/app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.ts @@ -1,12 +1,9 @@ import { Component } from '@angular/core'; -import { Observable } from 'rxjs'; -import { Item } from '../../../../core/shared/item.model'; -import { ItemViewMode, rendersItemType } from '../../../../shared/items/item-type-decorator'; -import { isNotEmpty } from '../../../../shared/empty.util'; import { ItemComponent } from '../../../../+item-page/simple/item-types/shared/item.component'; -import { getRelatedItemsByTypeLabel } from '../../../../+item-page/simple/item-types/shared/item-relationships-utils'; +import { listableObjectComponent } from '../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; -@rendersItemType('JournalVolume', ItemViewMode.Full) +@listableObjectComponent('JournalVolume', ViewMode.StandalonePage) @Component({ selector: 'ds-journal-volume', styleUrls: ['./journal-volume.component.scss'], @@ -16,26 +13,4 @@ import { getRelatedItemsByTypeLabel } from '../../../../+item-page/simple/item-t * The component for displaying metadata and relations of an item of the type Journal Volume */ export class JournalVolumeComponent extends ItemComponent { - /** - * The journals related to this journal volume - */ - journals$: Observable; - - /** - * The journal issues related to this journal volume - */ - issues$: Observable; - - ngOnInit(): void { - super.ngOnInit(); - - if (isNotEmpty(this.resolvedRelsAndTypes$)) { - this.journals$ = this.resolvedRelsAndTypes$.pipe( - getRelatedItemsByTypeLabel(this.item.id, 'isJournalOfVolume') - ); - this.issues$ = this.resolvedRelsAndTypes$.pipe( - getRelatedItemsByTypeLabel(this.item.id, 'isIssueOfJournalVolume') - ); - } - } } diff --git a/src/app/entity-groups/journal-entities/item-pages/journal/journal.component.html b/src/app/entity-groups/journal-entities/item-pages/journal/journal.component.html index a82d3c5df6..ae6c3a8914 100644 --- a/src/app/entity-groups/journal-entities/item-pages/journal/journal.component.html +++ b/src/app/entity-groups/journal-entities/item-pages/journal/journal.component.html @@ -1,41 +1,42 @@

- {{'journal.page.titleprefix' | translate}} + {{'journal.page.titleprefix' | translate}}

- + - - -
-
diff --git a/src/app/entity-groups/journal-entities/item-pages/journal/journal.component.spec.ts b/src/app/entity-groups/journal-entities/item-pages/journal/journal.component.spec.ts index 1a2c7f7ca7..a475e16637 100644 --- a/src/app/entity-groups/journal-entities/item-pages/journal/journal.component.spec.ts +++ b/src/app/entity-groups/journal-entities/item-pages/journal/journal.component.spec.ts @@ -1,19 +1,16 @@ import { ChangeDetectionStrategy, DebugElement, NO_ERRORS_SCHEMA } from '@angular/core'; import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { TruncatableService } from '../../../../shared/truncatable/truncatable.service'; -import { ITEM } from '../../../../shared/items/switcher/item-type-switcher.component'; import { TruncatePipe } from '../../../../shared/utils/truncate.pipe'; import { ItemDataService } from '../../../../core/data/item-data.service'; import { Item } from '../../../../core/shared/item.model'; import { By } from '@angular/platform-browser'; import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; import { MockTranslateLoader } from '../../../../shared/mocks/mock-translate-loader'; -import { RemoteData } from '../../../../core/data/remote-data'; import { PaginatedList } from '../../../../core/data/paginated-list'; import { PageInfo } from '../../../../core/shared/page-info.model'; import { isNotEmpty } from '../../../../shared/empty.util'; import { JournalComponent } from './journal.component'; -import { of as observableOf } from 'rxjs'; import { GenericItemPageFieldComponent } from '../../../../+item-page/simple/field-components/specific-field/generic/generic-item-page-field.component'; import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils'; @@ -55,7 +52,6 @@ describe('JournalComponent', () => { })], declarations: [JournalComponent, GenericItemPageFieldComponent, TruncatePipe], providers: [ - {provide: ITEM, useValue: mockItem}, {provide: ItemDataService, useValue: {}}, {provide: TruncatableService, useValue: {}} ], @@ -69,6 +65,7 @@ describe('JournalComponent', () => { beforeEach(async(() => { fixture = TestBed.createComponent(JournalComponent); comp = fixture.componentInstance; + comp.object = mockItem; fixture.detectChanges(); })); diff --git a/src/app/entity-groups/journal-entities/item-pages/journal/journal.component.ts b/src/app/entity-groups/journal-entities/item-pages/journal/journal.component.ts index a8f071d78a..dbbeb81662 100644 --- a/src/app/entity-groups/journal-entities/item-pages/journal/journal.component.ts +++ b/src/app/entity-groups/journal-entities/item-pages/journal/journal.component.ts @@ -1,12 +1,9 @@ import { Component } from '@angular/core'; -import { Observable } from 'rxjs'; -import { Item } from '../../../../core/shared/item.model'; -import { ItemViewMode, rendersItemType } from '../../../../shared/items/item-type-decorator'; -import { isNotEmpty } from '../../../../shared/empty.util'; import { ItemComponent } from '../../../../+item-page/simple/item-types/shared/item.component'; -import { getRelatedItemsByTypeLabel } from '../../../../+item-page/simple/item-types/shared/item-relationships-utils'; +import { listableObjectComponent } from '../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; -@rendersItemType('Journal', ItemViewMode.Full) +@listableObjectComponent('Journal', ViewMode.StandalonePage) @Component({ selector: 'ds-journal', styleUrls: ['./journal.component.scss'], @@ -16,18 +13,4 @@ import { getRelatedItemsByTypeLabel } from '../../../../+item-page/simple/item-t * The component for displaying metadata and relations of an item of the type Journal */ export class JournalComponent extends ItemComponent { - /** - * The volumes related to this journal - */ - volumes$: Observable; - - ngOnInit(): void { - super.ngOnInit(); - - if (isNotEmpty(this.resolvedRelsAndTypes$)) { - this.volumes$ = this.resolvedRelsAndTypes$.pipe( - getRelatedItemsByTypeLabel(this.item.id, 'isVolumeOfJournal') - ); - } - } } diff --git a/src/app/entity-groups/journal-entities/journal-entities.module.ts b/src/app/entity-groups/journal-entities/journal-entities.module.ts index 4033645e1b..d00eae1e54 100644 --- a/src/app/entity-groups/journal-entities/journal-entities.module.ts +++ b/src/app/entity-groups/journal-entities/journal-entities.module.ts @@ -12,6 +12,12 @@ import { TooltipModule } from 'ngx-bootstrap'; import { JournalIssueGridElementComponent } from './item-grid-elements/journal-issue/journal-issue-grid-element.component'; import { JournalVolumeGridElementComponent } from './item-grid-elements/journal-volume/journal-volume-grid-element.component'; import { JournalGridElementComponent } from './item-grid-elements/journal/journal-grid-element.component'; +import { JournalSearchResultListElementComponent } from './item-list-elements/search-result-list-elements/journal/journal-search-result-list-element.component'; +import { JournalSearchResultGridElementComponent } from './item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component'; +import { JournalIssueSearchResultListElementComponent } from './item-list-elements/search-result-list-elements/journal-issue/journal-issue-search-result-list-element.component'; +import { JournalVolumeSearchResultListElementComponent } from './item-list-elements/search-result-list-elements/journal-volume/journal-volume-search-result-list-element.component'; +import { JournalIssueSearchResultGridElementComponent } from './item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component'; +import { JournalVolumeSearchResultGridElementComponent } from './item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component'; const ENTRY_COMPONENTS = [ JournalComponent, @@ -22,7 +28,13 @@ const ENTRY_COMPONENTS = [ JournalVolumeListElementComponent, JournalIssueGridElementComponent, JournalVolumeGridElementComponent, - JournalGridElementComponent + JournalGridElementComponent, + JournalSearchResultListElementComponent, + JournalIssueSearchResultListElementComponent, + JournalVolumeSearchResultListElementComponent, + JournalIssueSearchResultGridElementComponent, + JournalVolumeSearchResultGridElementComponent, + JournalSearchResultGridElementComponent ]; @NgModule({ diff --git a/src/app/entity-groups/research-entities/item-grid-elements/org-unit/org-unit-grid-element.component.html b/src/app/entity-groups/research-entities/item-grid-elements/org-unit/org-unit-grid-element.component.html new file mode 100644 index 0000000000..e4522398a6 --- /dev/null +++ b/src/app/entity-groups/research-entities/item-grid-elements/org-unit/org-unit-grid-element.component.html @@ -0,0 +1 @@ + diff --git a/src/app/entity-groups/research-entities/item-grid-elements/org-unit/org-unit-grid-element.component.scss b/src/app/entity-groups/research-entities/item-grid-elements/org-unit/org-unit-grid-element.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/entity-groups/research-entities/item-grid-elements/org-unit/org-unit-grid-element.component.spec.ts b/src/app/entity-groups/research-entities/item-grid-elements/org-unit/org-unit-grid-element.component.spec.ts new file mode 100644 index 0000000000..f5a0b04dba --- /dev/null +++ b/src/app/entity-groups/research-entities/item-grid-elements/org-unit/org-unit-grid-element.component.spec.ts @@ -0,0 +1,81 @@ +import { Item } from '../../../../core/shared/item.model'; +import { of as observableOf } from 'rxjs/internal/observable/of'; +import { OrgUnitGridElementComponent } from './org-unit-grid-element.component'; +import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils'; +import { PaginatedList } from '../../../../core/data/paginated-list'; +import { PageInfo } from '../../../../core/shared/page-info.model'; +import { async, TestBed } from '@angular/core/testing'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { TruncatePipe } from '../../../../shared/utils/truncate.pipe'; +import { TruncatableService } from '../../../../shared/truncatable/truncatable.service'; +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { By } from '@angular/platform-browser'; + +const mockItem = Object.assign(new Item(), { + bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + 'organization.foundingDate': [ + { + language: null, + value: '2015-06-26' + } + ], + 'organization.address.addressCountry': [ + { + language: 'en_US', + value: 'Belgium' + } + ], + 'organization.address.addressLocality': [ + { + language: 'en_US', + value: 'Brussels' + } + ] + } +}); + +describe('OrgUnitGridElementComponent', () => { + let comp; + let fixture; + + const truncatableServiceStub: any = { + isCollapsed: (id: number) => observableOf(true), + }; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [NoopAnimationsModule], + declarations: [OrgUnitGridElementComponent, TruncatePipe], + providers: [ + { provide: TruncatableService, useValue: truncatableServiceStub }, + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(OrgUnitGridElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(OrgUnitGridElementComponent); + comp = fixture.componentInstance; + })); + + describe(`when the org unit is rendered`, () => { + beforeEach(() => { + comp.object = mockItem; + fixture.detectChanges(); + }); + + it(`should contain a OrgUnitGridElementComponent`, () => { + const orgUnitGridElement = fixture.debugElement.query(By.css(`ds-org-unit-search-result-grid-element`)); + expect(orgUnitGridElement).not.toBeNull(); + }); + }); +}); diff --git a/src/app/entity-groups/research-entities/item-grid-elements/org-unit/org-unit-grid-element.component.ts b/src/app/entity-groups/research-entities/item-grid-elements/org-unit/org-unit-grid-element.component.ts new file mode 100644 index 0000000000..05a7f6c8c5 --- /dev/null +++ b/src/app/entity-groups/research-entities/item-grid-elements/org-unit/org-unit-grid-element.component.ts @@ -0,0 +1,17 @@ +import { Component } from '@angular/core'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; +import { listableObjectComponent } from '../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { AbstractListableElementComponent } from '../../../../shared/object-collection/shared/object-collection-element/abstract-listable-element.component'; +import { Item } from '../../../../core/shared/item.model'; + +@listableObjectComponent('OrgUnit', ViewMode.GridElement) +@Component({ + selector: 'ds-org-unit-grid-element', + styleUrls: ['./org-unit-grid-element.component.scss'], + templateUrl: './org-unit-grid-element.component.html', +}) +/** + * The component for displaying a grid element for an item of the type Organisation Unit + */ +export class OrgUnitGridElementComponent extends AbstractListableElementComponent { +} diff --git a/src/app/entity-groups/research-entities/item-grid-elements/orgunit/orgunit-grid-element.component.html b/src/app/entity-groups/research-entities/item-grid-elements/orgunit/orgunit-grid-element.component.html deleted file mode 100644 index a4765c4e8f..0000000000 --- a/src/app/entity-groups/research-entities/item-grid-elements/orgunit/orgunit-grid-element.component.html +++ /dev/null @@ -1,35 +0,0 @@ - -
- -
- - -
-
-
- - -

-
-

- - - -

-

- - {{dso.firstMetadataValue('organization.address.addressCountry')}} - - , - {{dso.firstMetadataValue('organization.address.addressLocality')}} - - -

-
- View -
-
-
-
diff --git a/src/app/entity-groups/research-entities/item-grid-elements/orgunit/orgunit-grid-element.component.ts b/src/app/entity-groups/research-entities/item-grid-elements/orgunit/orgunit-grid-element.component.ts deleted file mode 100644 index 0effc22027..0000000000 --- a/src/app/entity-groups/research-entities/item-grid-elements/orgunit/orgunit-grid-element.component.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { ItemViewMode, rendersItemType } from '../../../../shared/items/item-type-decorator'; -import { Component } from '@angular/core'; -import { focusShadow } from '../../../../shared/animations/focus'; -import { TypedItemSearchResultGridElementComponent } from '../../../../shared/object-grid/item-grid-element/item-types/typed-item-search-result-grid-element.component'; - -@rendersItemType('OrgUnit', ItemViewMode.Card) -@Component({ - selector: 'ds-orgunit-grid-element', - styleUrls: ['./orgunit-grid-element.component.scss'], - templateUrl: './orgunit-grid-element.component.html', - animations: [focusShadow] -}) -/** - * The component for displaying a grid element for an item of the type Organisation Unit - */ -export class OrgunitGridElementComponent extends TypedItemSearchResultGridElementComponent { -} diff --git a/src/app/entity-groups/research-entities/item-grid-elements/person/person-grid-element.component.html b/src/app/entity-groups/research-entities/item-grid-elements/person/person-grid-element.component.html index 331c2bd520..a431f5979f 100644 --- a/src/app/entity-groups/research-entities/item-grid-elements/person/person-grid-element.component.html +++ b/src/app/entity-groups/research-entities/item-grid-elements/person/person-grid-element.component.html @@ -1,30 +1 @@ - -
- -
- - -
-
-
- - -

-
- -

- - - -

-
- View -
-
-
-
+ \ No newline at end of file diff --git a/src/app/entity-groups/research-entities/item-grid-elements/person/person-grid-element.component.spec.ts b/src/app/entity-groups/research-entities/item-grid-elements/person/person-grid-element.component.spec.ts index bdbd32d980..469f45ebf5 100644 --- a/src/app/entity-groups/research-entities/item-grid-elements/person/person-grid-element.component.spec.ts +++ b/src/app/entity-groups/research-entities/item-grid-elements/person/person-grid-element.component.spec.ts @@ -1,15 +1,17 @@ -import { ItemSearchResult } from '../../../../shared/object-collection/shared/item-search-result.model'; import { Item } from '../../../../core/shared/item.model'; import { of as observableOf } from 'rxjs/internal/observable/of'; -import { getEntityGridElementTestComponent } from '../../../../shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.spec'; import { PersonGridElementComponent } from './person-grid-element.component'; import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils'; import { PaginatedList } from '../../../../core/data/paginated-list'; import { PageInfo } from '../../../../core/shared/page-info.model'; +import { async, TestBed } from '@angular/core/testing'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { TruncatePipe } from '../../../../shared/utils/truncate.pipe'; +import { TruncatableService } from '../../../../shared/truncatable/truncatable.service'; +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { By } from '@angular/platform-browser'; -const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult(); -mockItemWithMetadata.hitHighlights = {}; -mockItemWithMetadata.indexableObject = Object.assign(new Item(), { +const mockItem = Object.assign(new Item(), { bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), metadata: { 'dc.title': [ @@ -33,18 +35,41 @@ mockItemWithMetadata.indexableObject = Object.assign(new Item(), { } }); -const mockItemWithoutMetadata: ItemSearchResult = new ItemSearchResult(); -mockItemWithoutMetadata.hitHighlights = {}; -mockItemWithoutMetadata.indexableObject = Object.assign(new Item(), { - bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), - metadata: { - 'dc.title': [ - { - language: 'en_US', - value: 'This is just another title' - } - ] - } -}); +describe('PersonGridElementComponent', () => { + let comp; + let fixture; -describe('PersonGridElementComponent', getEntityGridElementTestComponent(PersonGridElementComponent, mockItemWithMetadata, mockItemWithoutMetadata, ['email', 'jobtitle'])); + const truncatableServiceStub: any = { + isCollapsed: (id: number) => observableOf(true), + }; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [NoopAnimationsModule], + declarations: [PersonGridElementComponent, TruncatePipe], + providers: [ + { provide: TruncatableService, useValue: truncatableServiceStub }, + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(PersonGridElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(PersonGridElementComponent); + comp = fixture.componentInstance; + })); + + describe(`when the person is rendered`, () => { + beforeEach(() => { + comp.object = mockItem; + fixture.detectChanges(); + }); + + it(`should contain a PersonGridElementComponent`, () => { + const personGridElement = fixture.debugElement.query(By.css(`ds-person-search-result-grid-element`)); + expect(personGridElement).not.toBeNull(); + }); + }); +}); diff --git a/src/app/entity-groups/research-entities/item-grid-elements/person/person-grid-element.component.ts b/src/app/entity-groups/research-entities/item-grid-elements/person/person-grid-element.component.ts index bf7b8aa119..2e3ce5804e 100644 --- a/src/app/entity-groups/research-entities/item-grid-elements/person/person-grid-element.component.ts +++ b/src/app/entity-groups/research-entities/item-grid-elements/person/person-grid-element.component.ts @@ -1,17 +1,17 @@ -import { ItemViewMode, rendersItemType } from '../../../../shared/items/item-type-decorator'; import { Component } from '@angular/core'; -import { TypedItemSearchResultGridElementComponent } from '../../../../shared/object-grid/item-grid-element/item-types/typed-item-search-result-grid-element.component'; -import { focusShadow } from '../../../../shared/animations/focus'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; +import { listableObjectComponent } from '../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { AbstractListableElementComponent } from '../../../../shared/object-collection/shared/object-collection-element/abstract-listable-element.component'; +import { Item } from '../../../../core/shared/item.model'; -@rendersItemType('Person', ItemViewMode.Card) +@listableObjectComponent('Person', ViewMode.GridElement) @Component({ selector: 'ds-person-grid-element', styleUrls: ['./person-grid-element.component.scss'], templateUrl: './person-grid-element.component.html', - animations: [focusShadow] }) /** * The component for displaying a grid element for an item of the type Person */ -export class PersonGridElementComponent extends TypedItemSearchResultGridElementComponent { +export class PersonGridElementComponent extends AbstractListableElementComponent { } diff --git a/src/app/entity-groups/research-entities/item-grid-elements/project/project-grid-element.component.html b/src/app/entity-groups/research-entities/item-grid-elements/project/project-grid-element.component.html index 889276b29b..0c87599399 100644 --- a/src/app/entity-groups/research-entities/item-grid-elements/project/project-grid-element.component.html +++ b/src/app/entity-groups/research-entities/item-grid-elements/project/project-grid-element.component.html @@ -1,25 +1 @@ - -
- -
- - -
-
-
- - -

-
-

- - - -

-
- View -
-
-
-
+ \ No newline at end of file diff --git a/src/app/entity-groups/research-entities/item-grid-elements/project/project-grid-element.component.spec.ts b/src/app/entity-groups/research-entities/item-grid-elements/project/project-grid-element.component.spec.ts index b6877f62aa..ff9e3bb64a 100644 --- a/src/app/entity-groups/research-entities/item-grid-elements/project/project-grid-element.component.spec.ts +++ b/src/app/entity-groups/research-entities/item-grid-elements/project/project-grid-element.component.spec.ts @@ -1,15 +1,17 @@ -import { ItemSearchResult } from '../../../../shared/object-collection/shared/item-search-result.model'; import { Item } from '../../../../core/shared/item.model'; import { of as observableOf } from 'rxjs/internal/observable/of'; -import { getEntityGridElementTestComponent } from '../../../../shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.spec'; import { ProjectGridElementComponent } from './project-grid-element.component'; import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils'; import { PaginatedList } from '../../../../core/data/paginated-list'; import { PageInfo } from '../../../../core/shared/page-info.model'; +import { async, TestBed } from '@angular/core/testing'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { TruncatePipe } from '../../../../shared/utils/truncate.pipe'; +import { TruncatableService } from '../../../../shared/truncatable/truncatable.service'; +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { By } from '@angular/platform-browser'; -const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult(); -mockItemWithMetadata.hitHighlights = {}; -mockItemWithMetadata.indexableObject = Object.assign(new Item(), { +const mockItem = Object.assign(new Item(), { bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), metadata: { 'dc.title': [ @@ -27,18 +29,41 @@ mockItemWithMetadata.indexableObject = Object.assign(new Item(), { } }); -const mockItemWithoutMetadata: ItemSearchResult = new ItemSearchResult(); -mockItemWithoutMetadata.hitHighlights = {}; -mockItemWithoutMetadata.indexableObject = Object.assign(new Item(), { - bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), - metadata: { - 'dc.title': [ - { - language: 'en_US', - value: 'This is just another title' - } - ] - } -}); +describe('ProjectGridElementComponent', () => { + let comp; + let fixture; -describe('ProjectGridElementComponent', getEntityGridElementTestComponent(ProjectGridElementComponent, mockItemWithMetadata, mockItemWithoutMetadata, ['description'])); + const truncatableServiceStub: any = { + isCollapsed: (id: number) => observableOf(true), + }; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [NoopAnimationsModule], + declarations: [ProjectGridElementComponent, TruncatePipe], + providers: [ + { provide: TruncatableService, useValue: truncatableServiceStub }, + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(ProjectGridElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(ProjectGridElementComponent); + comp = fixture.componentInstance; + })); + + describe(`when the project is rendered`, () => { + beforeEach(() => { + comp.object = mockItem; + fixture.detectChanges(); + }); + + it(`should contain a ProjectGridElementComponent`, () => { + const projectGridElement = fixture.debugElement.query(By.css(`ds-project-search-result-grid-element`)); + expect(projectGridElement).not.toBeNull(); + }); + }); +}); diff --git a/src/app/entity-groups/research-entities/item-grid-elements/project/project-grid-element.component.ts b/src/app/entity-groups/research-entities/item-grid-elements/project/project-grid-element.component.ts index 15d525fcf2..58547960cf 100644 --- a/src/app/entity-groups/research-entities/item-grid-elements/project/project-grid-element.component.ts +++ b/src/app/entity-groups/research-entities/item-grid-elements/project/project-grid-element.component.ts @@ -1,17 +1,17 @@ -import { ItemViewMode, rendersItemType } from '../../../../shared/items/item-type-decorator'; import { Component } from '@angular/core'; -import { focusShadow } from '../../../../shared/animations/focus'; -import { TypedItemSearchResultGridElementComponent } from '../../../../shared/object-grid/item-grid-element/item-types/typed-item-search-result-grid-element.component'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; +import { listableObjectComponent } from '../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { AbstractListableElementComponent } from '../../../../shared/object-collection/shared/object-collection-element/abstract-listable-element.component'; +import { Item } from '../../../../core/shared/item.model'; -@rendersItemType('Project', ItemViewMode.Card) +@listableObjectComponent('Project', ViewMode.GridElement) @Component({ selector: 'ds-project-grid-element', styleUrls: ['./project-grid-element.component.scss'], templateUrl: './project-grid-element.component.html', - animations: [focusShadow] }) /** * The component for displaying a grid element for an item of the type Project */ -export class ProjectGridElementComponent extends TypedItemSearchResultGridElementComponent { +export class ProjectGridElementComponent extends AbstractListableElementComponent { } diff --git a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/org-unit/org-unit-search-result-grid-element.component.html b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/org-unit/org-unit-search-result-grid-element.component.html new file mode 100644 index 0000000000..5c42be2b24 --- /dev/null +++ b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/org-unit/org-unit-search-result-grid-element.component.html @@ -0,0 +1,41 @@ + +
+ +
+ + +
+
+ +
+ + +
+
+
+ + +

+
+

+ + + +

+

+ + {{firstMetadataValue('organization.address.addressCountry')}} + + , + {{firstMetadataValue('organization.address.addressLocality')}} + + +

+
+ View +
+
+
+
diff --git a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/org-unit/org-unit-search-result-grid-element.component.scss b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/org-unit/org-unit-search-result-grid-element.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/entity-groups/research-entities/item-grid-elements/orgunit/orgunit-grid-element.component.spec.ts b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/org-unit/org-unit-search-result-grid-element.component.spec.ts similarity index 55% rename from src/app/entity-groups/research-entities/item-grid-elements/orgunit/orgunit-grid-element.component.spec.ts rename to src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/org-unit/org-unit-search-result-grid-element.component.spec.ts index 522e16b5b9..a44d2d1373 100644 --- a/src/app/entity-groups/research-entities/item-grid-elements/orgunit/orgunit-grid-element.component.spec.ts +++ b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/org-unit/org-unit-search-result-grid-element.component.spec.ts @@ -1,11 +1,10 @@ -import { ItemSearchResult } from '../../../../shared/object-collection/shared/item-search-result.model'; -import { Item } from '../../../../core/shared/item.model'; -import { of as observableOf } from 'rxjs/internal/observable/of'; -import { getEntityGridElementTestComponent } from '../../../../shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.spec'; -import { OrgunitGridElementComponent } from './orgunit-grid-element.component'; -import { createSuccessfulRemoteDataObject$ } from '../../../../shared/testing/utils'; -import { PaginatedList } from '../../../../core/data/paginated-list'; -import { PageInfo } from '../../../../core/shared/page-info.model'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { Item } from '../../../../../core/shared/item.model'; +import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/testing/utils'; +import { PaginatedList } from '../../../../../core/data/paginated-list'; +import { PageInfo } from '../../../../../core/shared/page-info.model'; +import { OrgUnitSearchResultGridElementComponent } from './org-unit-search-result-grid-element.component'; +import { getEntityGridElementTestComponent } from '../../../../../shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.spec'; const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult(); mockItemWithMetadata.hitHighlights = {}; @@ -53,4 +52,4 @@ mockItemWithoutMetadata.indexableObject = Object.assign(new Item(), { } }); -describe('OrgunitGridElementComponent', getEntityGridElementTestComponent(OrgunitGridElementComponent, mockItemWithMetadata, mockItemWithoutMetadata, ['date', 'country', 'city'])); +describe('OrgUnitSearchResultGridElementComponent', getEntityGridElementTestComponent(OrgUnitSearchResultGridElementComponent, mockItemWithMetadata, mockItemWithoutMetadata, ['date', 'country', 'city'])); diff --git a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/org-unit/org-unit-search-result-grid-element.component.ts b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/org-unit/org-unit-search-result-grid-element.component.ts new file mode 100644 index 0000000000..64b4be4a11 --- /dev/null +++ b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/org-unit/org-unit-search-result-grid-element.component.ts @@ -0,0 +1,20 @@ +import { Component } from '@angular/core'; +import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { ViewMode } from '../../../../../core/shared/view-mode.model'; +import { focusShadow } from '../../../../../shared/animations/focus'; +import { SearchResultGridElementComponent } from '../../../../../shared/object-grid/search-result-grid-element/search-result-grid-element.component'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { Item } from '../../../../../core/shared/item.model'; + +@listableObjectComponent('OrgUnitSearchResult', ViewMode.GridElement) +@Component({ + selector: 'ds-org-unit-search-result-grid-element', + styleUrls: ['./org-unit-search-result-grid-element.component.scss'], + templateUrl: './org-unit-search-result-grid-element.component.html', + animations: [focusShadow] +}) +/** + * The component for displaying a grid element for an item search result of the type Organisation Unit + */ +export class OrgUnitSearchResultGridElementComponent extends SearchResultGridElementComponent { +} diff --git a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.html b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.html new file mode 100644 index 0000000000..b7eed7c8b4 --- /dev/null +++ b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.html @@ -0,0 +1,37 @@ + +
+ +
+ + +
+
+ +
+ + +
+
+
+ + +

+
+ +

+ + + +

+
+ View +
+
+
+
diff --git a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.scss b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.spec.ts b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.spec.ts new file mode 100644 index 0000000000..4938af2b73 --- /dev/null +++ b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.spec.ts @@ -0,0 +1,49 @@ +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { Item } from '../../../../../core/shared/item.model'; +import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/testing/utils'; +import { PaginatedList } from '../../../../../core/data/paginated-list'; +import { PageInfo } from '../../../../../core/shared/page-info.model'; +import { getEntityGridElementTestComponent } from '../../../../../shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.spec'; +import { PersonSearchResultGridElementComponent } from './person-search-result-grid-element.component'; + +const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult(); +mockItemWithMetadata.hitHighlights = {}; +mockItemWithMetadata.indexableObject = Object.assign(new Item(), { + bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + 'person.email': [ + { + language: 'en_US', + value: 'Smith-Donald@gmail.com' + } + ], + 'person.jobTitle': [ + { + language: 'en_US', + value: 'Web Developer' + } + ] + } +}); + +const mockItemWithoutMetadata: ItemSearchResult = new ItemSearchResult(); +mockItemWithoutMetadata.hitHighlights = {}; +mockItemWithoutMetadata.indexableObject = Object.assign(new Item(), { + bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ] + } +}); + +describe('PersonSearchResultGridElementComponent', getEntityGridElementTestComponent(PersonSearchResultGridElementComponent, mockItemWithMetadata, mockItemWithoutMetadata, ['email', 'jobtitle'])); diff --git a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.ts b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.ts new file mode 100644 index 0000000000..55bc4f5a0d --- /dev/null +++ b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.ts @@ -0,0 +1,20 @@ +import { Component } from '@angular/core'; +import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { ViewMode } from '../../../../../core/shared/view-mode.model'; +import { focusShadow } from '../../../../../shared/animations/focus'; +import { SearchResultGridElementComponent } from '../../../../../shared/object-grid/search-result-grid-element/search-result-grid-element.component'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { Item } from '../../../../../core/shared/item.model'; + +@listableObjectComponent('PersonSearchResult', ViewMode.GridElement) +@Component({ + selector: 'ds-person-search-result-grid-element', + styleUrls: ['./person-search-result-grid-element.component.scss'], + templateUrl: './person-search-result-grid-element.component.html', + animations: [focusShadow] +}) +/** + * The component for displaying a grid element for an item search result of the type Person + */ +export class PersonSearchResultGridElementComponent extends SearchResultGridElementComponent { +} diff --git a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.html b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.html new file mode 100644 index 0000000000..f3a0dea81f --- /dev/null +++ b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.html @@ -0,0 +1,31 @@ + +
+ +
+ + +
+
+ +
+ + +
+
+
+ + +

+
+

+ + + +

+
+ View +
+
+
+
diff --git a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.scss b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.spec.ts b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.spec.ts new file mode 100644 index 0000000000..6497fadbaf --- /dev/null +++ b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.spec.ts @@ -0,0 +1,43 @@ +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { Item } from '../../../../../core/shared/item.model'; +import { createSuccessfulRemoteDataObject$ } from '../../../../../shared/testing/utils'; +import { PaginatedList } from '../../../../../core/data/paginated-list'; +import { PageInfo } from '../../../../../core/shared/page-info.model'; +import { ProjectSearchResultGridElementComponent } from './project-search-result-grid-element.component'; +import { getEntityGridElementTestComponent } from '../../../../../shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.spec'; + +const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult(); +mockItemWithMetadata.hitHighlights = {}; +mockItemWithMetadata.indexableObject = Object.assign(new Item(), { + bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + 'dc.description': [ + { + language: 'en_US', + value: 'The project description' + } + ] + } +}); + +const mockItemWithoutMetadata: ItemSearchResult = new ItemSearchResult(); +mockItemWithoutMetadata.hitHighlights = {}; +mockItemWithoutMetadata.indexableObject = Object.assign(new Item(), { + bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ] + } +}); + +describe('ProjectSearchResultGridElementComponent', getEntityGridElementTestComponent(ProjectSearchResultGridElementComponent, mockItemWithMetadata, mockItemWithoutMetadata, ['description'])); diff --git a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.ts b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.ts new file mode 100644 index 0000000000..a352d2dcb0 --- /dev/null +++ b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.ts @@ -0,0 +1,20 @@ +import { Component } from '@angular/core'; +import { SearchResultGridElementComponent } from '../../../../../shared/object-grid/search-result-grid-element/search-result-grid-element.component'; +import { Item } from '../../../../../core/shared/item.model'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { ViewMode } from '../../../../../core/shared/view-mode.model'; +import { focusShadow } from '../../../../../shared/animations/focus'; + +@listableObjectComponent('ProjectSearchResult', ViewMode.GridElement) +@Component({ + selector: 'ds-project-search-result-grid-element', + styleUrls: ['./project-search-result-grid-element.component.scss'], + templateUrl: './project-search-result-grid-element.component.html', + animations: [focusShadow] +}) +/** + * The component for displaying a grid element for an item search result of the type Project + */ +export class ProjectSearchResultGridElementComponent extends SearchResultGridElementComponent { +} diff --git a/src/app/entity-groups/research-entities/item-list-elements/org-unit/org-unit-list-element.component.html b/src/app/entity-groups/research-entities/item-list-elements/org-unit/org-unit-list-element.component.html new file mode 100644 index 0000000000..03ef45c7a4 --- /dev/null +++ b/src/app/entity-groups/research-entities/item-list-elements/org-unit/org-unit-list-element.component.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/app/entity-groups/research-entities/item-list-elements/orgunit/orgunit-list-element.component.scss b/src/app/entity-groups/research-entities/item-list-elements/org-unit/org-unit-list-element.component.scss similarity index 100% rename from src/app/entity-groups/research-entities/item-list-elements/orgunit/orgunit-list-element.component.scss rename to src/app/entity-groups/research-entities/item-list-elements/org-unit/org-unit-list-element.component.scss diff --git a/src/app/entity-groups/research-entities/item-list-elements/org-unit/org-unit-list-element.component.spec.ts b/src/app/entity-groups/research-entities/item-list-elements/org-unit/org-unit-list-element.component.spec.ts new file mode 100644 index 0000000000..fedfcf35c9 --- /dev/null +++ b/src/app/entity-groups/research-entities/item-list-elements/org-unit/org-unit-list-element.component.spec.ts @@ -0,0 +1,64 @@ +import { async, TestBed } from '@angular/core/testing'; +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { By } from '@angular/platform-browser'; +import { OrgUnitListElementComponent } from './org-unit-list-element.component'; +import { of as observableOf } from 'rxjs'; +import { Item } from '../../../../core/shared/item.model'; +import { TruncatePipe } from '../../../../shared/utils/truncate.pipe'; +import { TruncatableService } from '../../../../shared/truncatable/truncatable.service'; + +const mockItem: Item = Object.assign(new Item(), { + bundles: observableOf({}), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + 'dc.description': [ + { + language: 'en_US', + value: 'A description about the OrgUnit' + } + ] + } +}); + +describe('OrgUnitListElementComponent', () => { + let comp; + let fixture; + + const truncatableServiceStub: any = { + isCollapsed: (id: number) => observableOf(true), + }; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [OrgUnitListElementComponent, TruncatePipe], + providers: [ + { provide: TruncatableService, useValue: truncatableServiceStub }, + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(OrgUnitListElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(OrgUnitListElementComponent); + comp = fixture.componentInstance; + })); + + describe(`when the org unit is rendered`, () => { + beforeEach(() => { + comp.object = mockItem; + fixture.detectChanges(); + }); + + it(`should contain a OrgUnitListElementComponent`, () => { + const orgUnitListElement = fixture.debugElement.query(By.css(`ds-org-unit-search-result-list-element`)); + expect(orgUnitListElement).not.toBeNull(); + }); + }); +}); diff --git a/src/app/entity-groups/research-entities/item-list-elements/org-unit/org-unit-list-element.component.ts b/src/app/entity-groups/research-entities/item-list-elements/org-unit/org-unit-list-element.component.ts new file mode 100644 index 0000000000..32254595aa --- /dev/null +++ b/src/app/entity-groups/research-entities/item-list-elements/org-unit/org-unit-list-element.component.ts @@ -0,0 +1,17 @@ +import { Component } from '@angular/core'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; +import { listableObjectComponent } from '../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { AbstractListableElementComponent } from '../../../../shared/object-collection/shared/object-collection-element/abstract-listable-element.component'; +import { Item } from '../../../../core/shared/item.model'; + +@listableObjectComponent('OrgUnit', ViewMode.ListElement) +@Component({ + selector: 'ds-org-unit-list-element', + styleUrls: ['./org-unit-list-element.component.scss'], + templateUrl: './org-unit-list-element.component.html' +}) +/** + * The component for displaying a list element for an item of the type Organisation Unit + */ +export class OrgUnitListElementComponent extends AbstractListableElementComponent { +} diff --git a/src/app/entity-groups/research-entities/item-list-elements/orgunit/orgunit-list-element.component.html b/src/app/entity-groups/research-entities/item-list-elements/orgunit/orgunit-list-element.component.html deleted file mode 100644 index 8d312fb7c0..0000000000 --- a/src/app/entity-groups/research-entities/item-list-elements/orgunit/orgunit-list-element.component.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - diff --git a/src/app/entity-groups/research-entities/item-list-elements/orgunit/orgunit-list-element.component.spec.ts b/src/app/entity-groups/research-entities/item-list-elements/orgunit/orgunit-list-element.component.spec.ts deleted file mode 100644 index fb5d0aedec..0000000000 --- a/src/app/entity-groups/research-entities/item-list-elements/orgunit/orgunit-list-element.component.spec.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; -import { By } from '@angular/platform-browser'; -import { OrgUnitListElementComponent } from './orgunit-list-element.component'; -import { of as observableOf } from 'rxjs'; -import { Item } from '../../../../core/shared/item.model'; -import { TruncatePipe } from '../../../../shared/utils/truncate.pipe'; -import { ITEM } from '../../../../shared/items/switcher/item-type-switcher.component'; -import { TruncatableService } from '../../../../shared/truncatable/truncatable.service'; - -let orgUnitListElementComponent: OrgUnitListElementComponent; -let fixture: ComponentFixture; - -const mockItemWithMetadata: Item = Object.assign(new Item(), { - bundles: observableOf({}), - metadata: { - 'dc.title': [ - { - language: 'en_US', - value: 'This is just another title' - } - ], - 'dc.description': [ - { - language: 'en_US', - value: 'A description about the OrgUnit' - } - ] - } -}); -const mockItemWithoutMetadata: Item = Object.assign(new Item(), { - bundles: observableOf({}), - metadata: { - 'dc.title': [ - { - language: 'en_US', - value: 'This is just another title' - } - ] - } -}); - -describe('OrgUnitListElementComponent', () => { - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ OrgUnitListElementComponent , TruncatePipe], - providers: [ - { provide: ITEM, useValue: mockItemWithMetadata}, - { provide: TruncatableService, useValue: {} } - ], - - schemas: [ NO_ERRORS_SCHEMA ] - }).overrideComponent(OrgUnitListElementComponent, { - set: { changeDetection: ChangeDetectionStrategy.Default } - }).compileComponents(); - })); - - beforeEach(async(() => { - fixture = TestBed.createComponent(OrgUnitListElementComponent); - orgUnitListElementComponent = fixture.componentInstance; - - })); - - describe('When the item has an orgunit description', () => { - beforeEach(() => { - orgUnitListElementComponent.item = mockItemWithMetadata; - fixture.detectChanges(); - }); - - it('should show the description span', () => { - const orgunitDescriptionField = fixture.debugElement.query(By.css('span.item-list-orgunit-description')); - expect(orgunitDescriptionField).not.toBeNull(); - }); - }); - - describe('When the item has no orgunit description', () => { - beforeEach(() => { - orgUnitListElementComponent.item = mockItemWithoutMetadata; - fixture.detectChanges(); - }); - - it('should not show the description span', () => { - const orgunitDescriptionField = fixture.debugElement.query(By.css('span.item-list-orgunit-description')); - expect(orgunitDescriptionField).toBeNull(); - }); - }); -}); diff --git a/src/app/entity-groups/research-entities/item-list-elements/orgunit/orgunit-list-element.component.ts b/src/app/entity-groups/research-entities/item-list-elements/orgunit/orgunit-list-element.component.ts deleted file mode 100644 index 9a56bb6d03..0000000000 --- a/src/app/entity-groups/research-entities/item-list-elements/orgunit/orgunit-list-element.component.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Component } from '@angular/core'; -import { ItemViewMode, rendersItemType } from '../../../../shared/items/item-type-decorator'; -import { TypedItemSearchResultListElementComponent } from '../../../../shared/object-list/item-list-element/item-types/typed-item-search-result-list-element.component'; - -@rendersItemType('OrgUnit', ItemViewMode.Element) -@Component({ - selector: 'ds-orgunit-list-element', - styleUrls: ['./orgunit-list-element.component.scss'], - templateUrl: './orgunit-list-element.component.html' -}) -/** - * The component for displaying a list element for an item of the type Organisation Unit - */ -export class OrgUnitListElementComponent extends TypedItemSearchResultListElementComponent { -} diff --git a/src/app/entity-groups/research-entities/item-list-elements/orgunit/orgunit-metadata-list-element.component.ts b/src/app/entity-groups/research-entities/item-list-elements/orgunit/orgunit-metadata-list-element.component.ts deleted file mode 100644 index 21d0d9f86b..0000000000 --- a/src/app/entity-groups/research-entities/item-list-elements/orgunit/orgunit-metadata-list-element.component.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Component } from '@angular/core'; -import { MetadataRepresentationType } from '../../../../core/shared/metadata-representation/metadata-representation.model'; -import { ItemViewMode, rendersItemType } from '../../../../shared/items/item-type-decorator'; -import { ItemMetadataRepresentationListElementComponent } from '../../../../shared/object-list/metadata-representation-list-element/item/item-metadata-representation-list-element.component'; - -@rendersItemType('OrgUnit', ItemViewMode.Element, MetadataRepresentationType.Item) -@Component({ - selector: 'ds-orgunit-metadata-list-element', - templateUrl: './orgunit-metadata-list-element.component.html' -}) -/** - * The component for displaying a list element for an item of the type OrgUnit - */ -export class OrgUnitMetadataListElementComponent extends ItemMetadataRepresentationListElementComponent { -} diff --git a/src/app/entity-groups/research-entities/item-list-elements/person/person-list-element.component.html b/src/app/entity-groups/research-entities/item-list-elements/person/person-list-element.component.html index c88b77083d..dbc3a42a05 100644 --- a/src/app/entity-groups/research-entities/item-list-elements/person/person-list-element.component.html +++ b/src/app/entity-groups/research-entities/item-list-elements/person/person-list-element.component.html @@ -1,15 +1 @@ - - - - - - - - - - - - + \ No newline at end of file diff --git a/src/app/entity-groups/research-entities/item-list-elements/person/person-list-element.component.spec.ts b/src/app/entity-groups/research-entities/item-list-elements/person/person-list-element.component.spec.ts index cc2b85c4b8..10c799e139 100644 --- a/src/app/entity-groups/research-entities/item-list-elements/person/person-list-element.component.spec.ts +++ b/src/app/entity-groups/research-entities/item-list-elements/person/person-list-element.component.spec.ts @@ -5,13 +5,9 @@ import { PersonListElementComponent } from './person-list-element.component'; import { of as observableOf } from 'rxjs'; import { Item } from '../../../../core/shared/item.model'; import { TruncatePipe } from '../../../../shared/utils/truncate.pipe'; -import { ITEM } from '../../../../shared/items/switcher/item-type-switcher.component'; import { TruncatableService } from '../../../../shared/truncatable/truncatable.service'; -let personListElementComponent: PersonListElementComponent; -let fixture: ComponentFixture; - -const mockItemWithMetadata: Item = Object.assign(new Item(), { +const mockItem: Item = Object.assign(new Item(), { bundles: observableOf({}), metadata: { 'dc.title': [ @@ -28,28 +24,22 @@ const mockItemWithMetadata: Item = Object.assign(new Item(), { ] } }); -const mockItemWithoutMetadata: Item = Object.assign(new Item(), { - bundles: observableOf({}), - metadata: { - 'dc.title': [ - { - language: 'en_US', - value: 'This is just another title' - } - ] - } -}); describe('PersonListElementComponent', () => { + let comp; + let fixture; + + const truncatableServiceStub: any = { + isCollapsed: (id: number) => observableOf(true), + }; + beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ PersonListElementComponent , TruncatePipe], + declarations: [PersonListElementComponent, TruncatePipe], providers: [ - { provide: ITEM, useValue: mockItemWithMetadata}, - { provide: TruncatableService, useValue: {} } + { provide: TruncatableService, useValue: truncatableServiceStub }, ], - - schemas: [ NO_ERRORS_SCHEMA ] + schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(PersonListElementComponent, { set: { changeDetection: ChangeDetectionStrategy.Default } }).compileComponents(); @@ -57,31 +47,18 @@ describe('PersonListElementComponent', () => { beforeEach(async(() => { fixture = TestBed.createComponent(PersonListElementComponent); - personListElementComponent = fixture.componentInstance; - + comp = fixture.componentInstance; })); - describe('When the item has a job title', () => { + describe(`when the person is rendered`, () => { beforeEach(() => { - personListElementComponent.item = mockItemWithMetadata; + comp.object = mockItem; fixture.detectChanges(); }); - it('should show the job title span', () => { - const jobTitleField = fixture.debugElement.query(By.css('span.item-list-job-title')); - expect(jobTitleField).not.toBeNull(); - }); - }); - - describe('When the item has no job title', () => { - beforeEach(() => { - personListElementComponent.item = mockItemWithoutMetadata; - fixture.detectChanges(); - }); - - it('should not show the job title span', () => { - const jobTitleField = fixture.debugElement.query(By.css('span.item-list-job-title')); - expect(jobTitleField).toBeNull(); + it(`should contain a PersonListElementComponent`, () => { + const personListElement = fixture.debugElement.query(By.css(`ds-person-search-result-list-element`)); + expect(personListElement).not.toBeNull(); }); }); }); diff --git a/src/app/entity-groups/research-entities/item-list-elements/person/person-list-element.component.ts b/src/app/entity-groups/research-entities/item-list-elements/person/person-list-element.component.ts index 46d90a6f2d..f35ed90c58 100644 --- a/src/app/entity-groups/research-entities/item-list-elements/person/person-list-element.component.ts +++ b/src/app/entity-groups/research-entities/item-list-elements/person/person-list-element.component.ts @@ -1,8 +1,10 @@ import { Component } from '@angular/core'; -import { ItemViewMode, rendersItemType } from '../../../../shared/items/item-type-decorator'; -import { TypedItemSearchResultListElementComponent } from '../../../../shared/object-list/item-list-element/item-types/typed-item-search-result-list-element.component'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; +import { listableObjectComponent } from '../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { AbstractListableElementComponent } from '../../../../shared/object-collection/shared/object-collection-element/abstract-listable-element.component'; +import { Item } from '../../../../core/shared/item.model'; -@rendersItemType('Person', ItemViewMode.Element) +@listableObjectComponent('Person', ViewMode.ListElement) @Component({ selector: 'ds-person-list-element', styleUrls: ['./person-list-element.component.scss'], @@ -11,5 +13,5 @@ import { TypedItemSearchResultListElementComponent } from '../../../../shared/ob /** * The component for displaying a list element for an item of the type Person */ -export class PersonListElementComponent extends TypedItemSearchResultListElementComponent { +export class PersonListElementComponent extends AbstractListableElementComponent { } diff --git a/src/app/entity-groups/research-entities/item-list-elements/person/person-metadata-list-element.component.ts b/src/app/entity-groups/research-entities/item-list-elements/person/person-metadata-list-element.component.ts deleted file mode 100644 index 35fbcd1173..0000000000 --- a/src/app/entity-groups/research-entities/item-list-elements/person/person-metadata-list-element.component.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Component } from '@angular/core'; -import { ItemViewMode, rendersItemType } from '../../../../shared/items/item-type-decorator'; -import { MetadataRepresentationType } from '../../../../core/shared/metadata-representation/metadata-representation.model'; -import { ItemMetadataRepresentationListElementComponent } from '../../../../shared/object-list/metadata-representation-list-element/item/item-metadata-representation-list-element.component'; - -@rendersItemType('Person', ItemViewMode.Element, MetadataRepresentationType.Item) -@Component({ - selector: 'ds-person-metadata-list-element', - templateUrl: './person-metadata-list-element.component.html' -}) -/** - * The component for displaying a list element for an item of the type Person - */ -export class PersonMetadataListElementComponent extends ItemMetadataRepresentationListElementComponent { -} diff --git a/src/app/entity-groups/research-entities/item-list-elements/project/project-list-element.component.html b/src/app/entity-groups/research-entities/item-list-elements/project/project-list-element.component.html index 3e979b4e4d..8f74452eaa 100644 --- a/src/app/entity-groups/research-entities/item-list-elements/project/project-list-element.component.html +++ b/src/app/entity-groups/research-entities/item-list-elements/project/project-list-element.component.html @@ -1,16 +1 @@ - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/src/app/entity-groups/research-entities/item-list-elements/project/project-list-element.component.spec.ts b/src/app/entity-groups/research-entities/item-list-elements/project/project-list-element.component.spec.ts index ba929ee33e..8db265837f 100644 --- a/src/app/entity-groups/research-entities/item-list-elements/project/project-list-element.component.spec.ts +++ b/src/app/entity-groups/research-entities/item-list-elements/project/project-list-element.component.spec.ts @@ -1,17 +1,13 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { async, TestBed } from '@angular/core/testing'; import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; import { By } from '@angular/platform-browser'; -import { ProjectListElementComponent } from './project-list-element.component'; import { of as observableOf } from 'rxjs'; import { Item } from '../../../../core/shared/item.model'; import { TruncatePipe } from '../../../../shared/utils/truncate.pipe'; -import { ITEM } from '../../../../shared/items/switcher/item-type-switcher.component'; import { TruncatableService } from '../../../../shared/truncatable/truncatable.service'; +import { ProjectListElementComponent } from './project-list-element.component'; -let projectListElementComponent: ProjectListElementComponent; -let fixture: ComponentFixture; - -const mockItemWithMetadata: Item = Object.assign(new Item(), { +const mockItem: Item = Object.assign(new Item(), { bundles: observableOf({}), metadata: { 'dc.title': [ @@ -28,28 +24,22 @@ const mockItemWithMetadata: Item = Object.assign(new Item(), { // ] } }); -const mockItemWithoutMetadata: Item = Object.assign(new Item(), { - bundles: observableOf({}), - metadata: { - 'dc.title': [ - { - language: 'en_US', - value: 'This is just another title' - } - ] - } -}); describe('ProjectListElementComponent', () => { + let comp; + let fixture; + + const truncatableServiceStub: any = { + isCollapsed: (id: number) => observableOf(true), + }; + beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ ProjectListElementComponent , TruncatePipe], + declarations: [ProjectListElementComponent, TruncatePipe], providers: [ - { provide: ITEM, useValue: mockItemWithMetadata}, - { provide: TruncatableService, useValue: {} } + { provide: TruncatableService, useValue: truncatableServiceStub }, ], - - schemas: [ NO_ERRORS_SCHEMA ] + schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(ProjectListElementComponent, { set: { changeDetection: ChangeDetectionStrategy.Default } }).compileComponents(); @@ -57,31 +47,18 @@ describe('ProjectListElementComponent', () => { beforeEach(async(() => { fixture = TestBed.createComponent(ProjectListElementComponent); - projectListElementComponent = fixture.componentInstance; - + comp = fixture.componentInstance; })); - // describe('When the item has a status', () => { - // beforeEach(() => { - // projectListElementComponent.item = mockItemWithMetadata; - // fixture.detectChanges(); - // }); - // - // it('should show the status span', () => { - // const statusField = fixture.debugElement.query(By.css('span.item-list-status')); - // expect(statusField).not.toBeNull(); - // }); - // }); - // - // describe('When the item has no status', () => { - // beforeEach(() => { - // projectListElementComponent.item = mockItemWithoutMetadata; - // fixture.detectChanges(); - // }); - // - // it('should not show the status span', () => { - // const statusField = fixture.debugElement.query(By.css('span.item-list-status')); - // expect(statusField).toBeNull(); - // }); - // }); + describe(`when the project is rendered`, () => { + beforeEach(() => { + comp.object = mockItem; + fixture.detectChanges(); + }); + + it(`should contain a ProjectListElementComponent`, () => { + const projectListElement = fixture.debugElement.query(By.css(`ds-project-search-result-list-element`)); + expect(projectListElement).not.toBeNull(); + }); + }); }); diff --git a/src/app/entity-groups/research-entities/item-list-elements/project/project-list-element.component.ts b/src/app/entity-groups/research-entities/item-list-elements/project/project-list-element.component.ts index 2d3e716ff4..5f158158d8 100644 --- a/src/app/entity-groups/research-entities/item-list-elements/project/project-list-element.component.ts +++ b/src/app/entity-groups/research-entities/item-list-elements/project/project-list-element.component.ts @@ -1,8 +1,10 @@ import { Component } from '@angular/core'; -import { ItemViewMode, rendersItemType } from '../../../../shared/items/item-type-decorator'; -import { TypedItemSearchResultListElementComponent } from '../../../../shared/object-list/item-list-element/item-types/typed-item-search-result-list-element.component'; +import { AbstractListableElementComponent } from '../../../../shared/object-collection/shared/object-collection-element/abstract-listable-element.component'; +import { Item } from '../../../../core/shared/item.model'; +import { listableObjectComponent } from '../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; -@rendersItemType('Project', ItemViewMode.Element) +@listableObjectComponent('Project', ViewMode.ListElement) @Component({ selector: 'ds-project-list-element', styleUrls: ['./project-list-element.component.scss'], @@ -11,5 +13,5 @@ import { TypedItemSearchResultListElementComponent } from '../../../../shared/ob /** * The component for displaying a list element for an item of the type Project */ -export class ProjectListElementComponent extends TypedItemSearchResultListElementComponent { +export class ProjectListElementComponent extends AbstractListableElementComponent { } diff --git a/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/org-unit/org-unit-search-result-list-element.component.html b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/org-unit/org-unit-search-result-list-element.component.html new file mode 100644 index 0000000000..f08d0fdc11 --- /dev/null +++ b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/org-unit/org-unit-search-result-list-element.component.html @@ -0,0 +1,19 @@ + + + + + + + + + + + + + diff --git a/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/org-unit/org-unit-search-result-list-element.component.scss b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/org-unit/org-unit-search-result-list-element.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/org-unit/org-unit-search-result-list-element.component.spec.ts b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/org-unit/org-unit-search-result-list-element.component.spec.ts new file mode 100644 index 0000000000..dfc9716075 --- /dev/null +++ b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/org-unit/org-unit-search-result-list-element.component.spec.ts @@ -0,0 +1,94 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { By } from '@angular/platform-browser'; +import { of as observableOf } from 'rxjs'; +import { OrgUnitSearchResultListElementComponent } from './org-unit-search-result-list-element.component'; +import { Item } from '../../../../../core/shared/item.model'; +import { TruncatePipe } from '../../../../../shared/utils/truncate.pipe'; +import { TruncatableService } from '../../../../../shared/truncatable/truncatable.service'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; + +let orgUnitListElementComponent: OrgUnitSearchResultListElementComponent; +let fixture: ComponentFixture; + +const mockItemWithMetadata: ItemSearchResult = Object.assign( + new ItemSearchResult(), + { + indexableObject: Object.assign(new Item(), { + bundles: observableOf({}), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + 'dc.description': [ + { + language: 'en_US', + value: 'A description about the OrgUnit' + } + ] + } + }) + }); +const mockItemWithoutMetadata: ItemSearchResult = Object.assign( + new ItemSearchResult(), + { + indexableObject: Object.assign(new Item(), { + bundles: observableOf({}), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ] + } + }) + }); + +describe('OrgUnitSearchResultListElementComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ OrgUnitSearchResultListElementComponent , TruncatePipe], + providers: [ + { provide: TruncatableService, useValue: {} } + ], + + schemas: [ NO_ERRORS_SCHEMA ] + }).overrideComponent(OrgUnitSearchResultListElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(OrgUnitSearchResultListElementComponent); + orgUnitListElementComponent = fixture.componentInstance; + + })); + + describe('When the item has an org unit description', () => { + beforeEach(() => { + orgUnitListElementComponent.object = mockItemWithMetadata; + fixture.detectChanges(); + }); + + it('should show the description span', () => { + const orgUnitDescriptionField = fixture.debugElement.query(By.css('span.item-list-org-unit-description')); + expect(orgUnitDescriptionField).not.toBeNull(); + }); + }); + + describe('When the item has no org unit description', () => { + beforeEach(() => { + orgUnitListElementComponent.object = mockItemWithoutMetadata; + fixture.detectChanges(); + }); + + it('should not show the description span', () => { + const orgUnitDescriptionField = fixture.debugElement.query(By.css('span.item-list-org-unit-description')); + expect(orgUnitDescriptionField).toBeNull(); + }); + }); +}); diff --git a/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/org-unit/org-unit-search-result-list-element.component.ts b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/org-unit/org-unit-search-result-list-element.component.ts new file mode 100644 index 0000000000..5b50e5a78c --- /dev/null +++ b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/org-unit/org-unit-search-result-list-element.component.ts @@ -0,0 +1,18 @@ +import { Component } from '@angular/core'; +import { ViewMode } from '../../../../../core/shared/view-mode.model'; +import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { SearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/search-result-list-element.component'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { Item } from '../../../../../core/shared/item.model'; + +@listableObjectComponent('OrgUnitSearchResult', ViewMode.ListElement) +@Component({ + selector: 'ds-org-unit-search-result-list-element', + styleUrls: ['./org-unit-search-result-list-element.component.scss'], + templateUrl: './org-unit-search-result-list-element.component.html' +}) +/** + * The component for displaying a list element for an item search result of the type Organisation Unit + */ +export class OrgUnitSearchResultListElementComponent extends SearchResultListElementComponent { +} diff --git a/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/person/person-search-result-list-element.component.html b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/person/person-search-result-list-element.component.html new file mode 100644 index 0000000000..b2791c4891 --- /dev/null +++ b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/person/person-search-result-list-element.component.html @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + diff --git a/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/person/person-search-result-list-element.component.scss b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/person/person-search-result-list-element.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/person/person-search-result-list-element.component.spec.ts b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/person/person-search-result-list-element.component.spec.ts new file mode 100644 index 0000000000..c10ad5d88e --- /dev/null +++ b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/person/person-search-result-list-element.component.spec.ts @@ -0,0 +1,94 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { By } from '@angular/platform-browser'; +import { of as observableOf } from 'rxjs'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { PersonSearchResultListElementComponent } from './person-search-result-list-element.component'; +import { Item } from '../../../../../core/shared/item.model'; +import { TruncatePipe } from '../../../../../shared/utils/truncate.pipe'; +import { TruncatableService } from '../../../../../shared/truncatable/truncatable.service'; + +let personListElementComponent: PersonSearchResultListElementComponent; +let fixture: ComponentFixture; + +const mockItemWithMetadata: ItemSearchResult = Object.assign( + new ItemSearchResult(), + { + indexableObject: Object.assign(new Item(), { + bundles: observableOf({}), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + 'person.jobTitle': [ + { + language: 'en_US', + value: 'Developer' + } + ] + } + }) + }); +const mockItemWithoutMetadata: ItemSearchResult = Object.assign( + new ItemSearchResult(), + { + indexableObject: Object.assign(new Item(), { + bundles: observableOf({}), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ] + } + }) + }); + +describe('PersonSearchResultListElementComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [PersonSearchResultListElementComponent, TruncatePipe], + providers: [ + { provide: TruncatableService, useValue: {} } + ], + + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(PersonSearchResultListElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(PersonSearchResultListElementComponent); + personListElementComponent = fixture.componentInstance; + + })); + + describe('When the item has a job title', () => { + beforeEach(() => { + personListElementComponent.object = mockItemWithMetadata; + fixture.detectChanges(); + }); + + it('should show the job title span', () => { + const jobTitleField = fixture.debugElement.query(By.css('span.item-list-job-title')); + expect(jobTitleField).not.toBeNull(); + }); + }); + + describe('When the item has no job title', () => { + beforeEach(() => { + personListElementComponent.object = mockItemWithoutMetadata; + fixture.detectChanges(); + }); + + it('should not show the job title span', () => { + const jobTitleField = fixture.debugElement.query(By.css('span.item-list-job-title')); + expect(jobTitleField).toBeNull(); + }); + }); +}); diff --git a/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/person/person-search-result-list-element.component.ts b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/person/person-search-result-list-element.component.ts new file mode 100644 index 0000000000..b4b4621261 --- /dev/null +++ b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/person/person-search-result-list-element.component.ts @@ -0,0 +1,18 @@ +import { Component } from '@angular/core'; +import { SearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/search-result-list-element.component'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { ViewMode } from '../../../../../core/shared/view-mode.model'; +import { Item } from '../../../../../core/shared/item.model'; + +@listableObjectComponent('PersonSearchResult', ViewMode.ListElement) +@Component({ + selector: 'ds-person-search-result-list-element', + styleUrls: ['./person-search-result-list-element.component.scss'], + templateUrl: './person-search-result-list-element.component.html' +}) +/** + * The component for displaying a list element for an item search result of the type Person + */ +export class PersonSearchResultListElementComponent extends SearchResultListElementComponent { +} diff --git a/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/project/project-search-result-list-element.component.html b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/project/project-search-result-list-element.component.html new file mode 100644 index 0000000000..95bff99e7e --- /dev/null +++ b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/project/project-search-result-list-element.component.html @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + diff --git a/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/project/project-search-result-list-element.component.scss b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/project/project-search-result-list-element.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/project/project-search-result-list-element.component.spec.ts b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/project/project-search-result-list-element.component.spec.ts new file mode 100644 index 0000000000..89eaad162b --- /dev/null +++ b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/project/project-search-result-list-element.component.spec.ts @@ -0,0 +1,94 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { of as observableOf } from 'rxjs'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { ProjectSearchResultListElementComponent } from './project-search-result-list-element.component'; +import { Item } from '../../../../../core/shared/item.model'; +import { TruncatePipe } from '../../../../../shared/utils/truncate.pipe'; +import { TruncatableService } from '../../../../../shared/truncatable/truncatable.service'; + +let projectListElementComponent: ProjectSearchResultListElementComponent; +let fixture: ComponentFixture; + +const mockItemWithMetadata: ItemSearchResult = Object.assign( + new ItemSearchResult(), + { + indexableObject: Object.assign(new Item(), { + bundles: observableOf({}), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + // 'project.identifier.status': [ + // { + // language: 'en_US', + // value: 'A status about the project' + // } + // ] + } + }) + }); + +const mockItemWithoutMetadata: ItemSearchResult = Object.assign( + new ItemSearchResult(), + { + indexableObject: Object.assign(new Item(), { + bundles: observableOf({}), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ] + } + }) + }); + +describe('ProjectSearchResultListElementComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ProjectSearchResultListElementComponent, TruncatePipe], + providers: [ + { provide: TruncatableService, useValue: {} } + ], + + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(ProjectSearchResultListElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(ProjectSearchResultListElementComponent); + projectListElementComponent = fixture.componentInstance; + + })); + + // describe('When the item has a status', () => { + // beforeEach(() => { + // projectListElementComponent.item = mockItemWithMetadata; + // fixture.detectChanges(); + // }); + // + // it('should show the status span', () => { + // const statusField = fixture.debugElement.query(By.css('span.item-list-status')); + // expect(statusField).not.toBeNull(); + // }); + // }); + // + // describe('When the item has no status', () => { + // beforeEach(() => { + // projectListElementComponent.item = mockItemWithoutMetadata; + // fixture.detectChanges(); + // }); + // + // it('should not show the status span', () => { + // const statusField = fixture.debugElement.query(By.css('span.item-list-status')); + // expect(statusField).toBeNull(); + // }); + // }); +}); diff --git a/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/project/project-search-result-list-element.component.ts b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/project/project-search-result-list-element.component.ts new file mode 100644 index 0000000000..faa15add31 --- /dev/null +++ b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/project/project-search-result-list-element.component.ts @@ -0,0 +1,18 @@ +import { Component } from '@angular/core'; +import { SearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/search-result-list-element.component'; +import { ItemSearchResult } from '../../../../../shared/object-collection/shared/item-search-result.model'; +import { Item } from '../../../../../core/shared/item.model'; +import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { ViewMode } from '../../../../../core/shared/view-mode.model'; + +@listableObjectComponent('ProjectSearchResult', ViewMode.ListElement) +@Component({ + selector: 'ds-project-search-result-list-element', + styleUrls: ['./project-search-result-list-element.component.scss'], + templateUrl: './project-search-result-list-element.component.html' +}) +/** + * The component for displaying a list element for an item search result of the type Project + */ +export class ProjectSearchResultListElementComponent extends SearchResultListElementComponent { +} diff --git a/src/app/entity-groups/research-entities/item-pages/orgunit/orgunit.component.html b/src/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.html similarity index 65% rename from src/app/entity-groups/research-entities/item-pages/orgunit/orgunit.component.html rename to src/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.html index 92ac3eac30..4d97868b58 100644 --- a/src/app/entity-groups/research-entities/item-pages/orgunit/orgunit.component.html +++ b/src/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.html @@ -1,47 +1,50 @@

- {{'orgunit.page.titleprefix' | translate}} + {{'orgunit.page.titleprefix' | translate}}

- + - - - -
- diff --git a/src/app/entity-groups/research-entities/item-pages/orgunit/orgunit.component.scss b/src/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.scss similarity index 100% rename from src/app/entity-groups/research-entities/item-pages/orgunit/orgunit.component.scss rename to src/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.scss diff --git a/src/app/entity-groups/research-entities/item-pages/orgunit/orgunit.component.spec.ts b/src/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.spec.ts similarity index 94% rename from src/app/entity-groups/research-entities/item-pages/orgunit/orgunit.component.spec.ts rename to src/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.spec.ts index f1b5b7e08f..8bfedbed21 100644 --- a/src/app/entity-groups/research-entities/item-pages/orgunit/orgunit.component.spec.ts +++ b/src/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.spec.ts @@ -2,7 +2,7 @@ import { Item } from '../../../../core/shared/item.model'; import { RemoteData } from '../../../../core/data/remote-data'; import { PaginatedList } from '../../../../core/data/paginated-list'; import { PageInfo } from '../../../../core/shared/page-info.model'; -import { OrgunitComponent } from './orgunit.component'; +import { OrgUnitComponent } from './org-unit.component'; import { of as observableOf } from 'rxjs'; import { createRelationshipsObservable, @@ -47,4 +47,4 @@ const mockItem: Item = Object.assign(new Item(), { relationships: createRelationshipsObservable() }); -describe('OrgUnitComponent', getItemPageFieldsTest(mockItem, OrgunitComponent)); +describe('OrgUnitComponent', getItemPageFieldsTest(mockItem, OrgUnitComponent)); diff --git a/src/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.ts b/src/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.ts new file mode 100644 index 0000000000..d9d4461bfa --- /dev/null +++ b/src/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.ts @@ -0,0 +1,16 @@ +import { Component } from '@angular/core'; +import { ItemComponent } from '../../../../+item-page/simple/item-types/shared/item.component'; +import { listableObjectComponent } from '../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; + +@listableObjectComponent('OrgUnit', ViewMode.StandalonePage) +@Component({ + selector: 'ds-org-unit', + styleUrls: ['./org-unit.component.scss'], + templateUrl: './org-unit.component.html' +}) +/** + * The component for displaying metadata and relations of an item of the type Organisation Unit + */ +export class OrgUnitComponent extends ItemComponent { +} diff --git a/src/app/entity-groups/research-entities/item-pages/orgunit/orgunit.component.ts b/src/app/entity-groups/research-entities/item-pages/orgunit/orgunit.component.ts deleted file mode 100644 index 031ca14ebb..0000000000 --- a/src/app/entity-groups/research-entities/item-pages/orgunit/orgunit.component.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { Observable } from 'rxjs'; -import { Item } from '../../../../core/shared/item.model'; -import { ItemViewMode, rendersItemType } from '../../../../shared/items/item-type-decorator'; -import { isNotEmpty } from '../../../../shared/empty.util'; -import { ItemComponent } from '../../../../+item-page/simple/item-types/shared/item.component'; -import { getRelatedItemsByTypeLabel } from '../../../../+item-page/simple/item-types/shared/item-relationships-utils'; - -@rendersItemType('OrgUnit', ItemViewMode.Full) -@Component({ - selector: 'ds-orgunit', - styleUrls: ['./orgunit.component.scss'], - templateUrl: './orgunit.component.html' -}) -/** - * The component for displaying metadata and relations of an item of the type Organisation Unit - */ -export class OrgunitComponent extends ItemComponent implements OnInit { - /** - * The people related to this organisation unit - */ - people$: Observable; - - /** - * The projects related to this organisation unit - */ - projects$: Observable; - - /** - * The publications related to this organisation unit - */ - publications$: Observable; - - ngOnInit(): void { - super.ngOnInit(); - - if (isNotEmpty(this.resolvedRelsAndTypes$)) { - this.people$ = this.resolvedRelsAndTypes$.pipe( - getRelatedItemsByTypeLabel(this.item.id, 'isPersonOfOrgUnit') - ); - - this.projects$ = this.resolvedRelsAndTypes$.pipe( - getRelatedItemsByTypeLabel(this.item.id, 'isProjectOfOrgUnit') - ); - - this.publications$ = this.resolvedRelsAndTypes$.pipe( - getRelatedItemsByTypeLabel(this.item.id, 'isPublicationOfOrgUnit') - ); - } - }} diff --git a/src/app/entity-groups/research-entities/item-pages/person/person.component.html b/src/app/entity-groups/research-entities/item-pages/person/person.component.html index 04d7b9e062..ff675ab057 100644 --- a/src/app/entity-groups/research-entities/item-pages/person/person.component.html +++ b/src/app/entity-groups/research-entities/item-pages/person/person.component.html @@ -1,57 +1,59 @@

- {{'person.page.titleprefix' | translate}} + {{'person.page.titleprefix' | translate}}

- + - - + - - +
-
diff --git a/src/app/entity-groups/research-entities/item-pages/person/person.component.ts b/src/app/entity-groups/research-entities/item-pages/person/person.component.ts index 8b36175b96..15c7184702 100644 --- a/src/app/entity-groups/research-entities/item-pages/person/person.component.ts +++ b/src/app/entity-groups/research-entities/item-pages/person/person.component.ts @@ -1,14 +1,9 @@ -import { Component, Inject } from '@angular/core'; -import { Observable , of as observableOf } from 'rxjs'; -import { Item } from '../../../../core/shared/item.model'; -import { ItemViewMode, rendersItemType } from '../../../../shared/items/item-type-decorator'; -import { ITEM } from '../../../../shared/items/switcher/item-type-switcher.component'; -import { SearchFixedFilterService } from '../../../../+search-page/search-filters/search-filter/search-fixed-filter.service'; -import { isNotEmpty } from '../../../../shared/empty.util'; +import { Component } from '@angular/core'; import { ItemComponent } from '../../../../+item-page/simple/item-types/shared/item.component'; -import { getRelatedItemsByTypeLabel } from '../../../../+item-page/simple/item-types/shared/item-relationships-utils'; +import { listableObjectComponent } from '../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; -@rendersItemType('Person', ItemViewMode.Full) +@listableObjectComponent('Person', ViewMode.StandalonePage) @Component({ selector: 'ds-person', styleUrls: ['./person.component.scss'], @@ -18,55 +13,4 @@ import { getRelatedItemsByTypeLabel } from '../../../../+item-page/simple/item-t * The component for displaying metadata and relations of an item of the type Person */ export class PersonComponent extends ItemComponent { - /** - * The publications related to this person - */ - publications$: Observable; - - /** - * The projects related to this person - */ - projects$: Observable; - - /** - * The organisation units related to this person - */ - orgUnits$: Observable; - - /** - * The applied fixed filter - */ - fixedFilter$: Observable; - - /** - * The query used for applying the fixed filter - */ - fixedFilterQuery: string; - - constructor( - @Inject(ITEM) public item: Item, - private fixedFilterService: SearchFixedFilterService - ) { - super(item); - } - ngOnInit(): void { - super.ngOnInit(); - - if (isNotEmpty(this.resolvedRelsAndTypes$)) { - this.publications$ = this.resolvedRelsAndTypes$.pipe( - getRelatedItemsByTypeLabel(this.item.id, 'isPublicationOfAuthor') - ); - - this.projects$ = this.resolvedRelsAndTypes$.pipe( - getRelatedItemsByTypeLabel(this.item.id, 'isProjectOfPerson') - ); - - this.orgUnits$ = this.resolvedRelsAndTypes$.pipe( - getRelatedItemsByTypeLabel(this.item.id, 'isOrgUnitOfPerson') - ); - - this.fixedFilterQuery = this.fixedFilterService.getQueryByRelations('isAuthorOfPublication', this.item.id); - this.fixedFilter$ = observableOf('publication'); - } - } } diff --git a/src/app/entity-groups/research-entities/item-pages/project/project.component.html b/src/app/entity-groups/research-entities/item-pages/project/project.component.html index 4e9a130b8c..bb6ce21cd1 100644 --- a/src/app/entity-groups/research-entities/item-pages/project/project.component.html +++ b/src/app/entity-groups/research-entities/item-pages/project/project.component.html @@ -1,55 +1,60 @@

- {{'project.page.titleprefix' | translate}} + {{'project.page.titleprefix' | translate}}

- + - + + [parentItem]="object" + [itemType]="'OrgUnit'" + [metadataField]="'project.contributor.other'" + [label]="'project.page.contributor' | translate"> - - - +
- - diff --git a/src/app/entity-groups/research-entities/item-pages/project/project.component.ts b/src/app/entity-groups/research-entities/item-pages/project/project.component.ts index 13c2b54ba4..8ac424af5b 100644 --- a/src/app/entity-groups/research-entities/item-pages/project/project.component.ts +++ b/src/app/entity-groups/research-entities/item-pages/project/project.component.ts @@ -1,13 +1,9 @@ -import { Component, OnInit } from '@angular/core'; -import { Observable } from 'rxjs'; -import { Item } from '../../../../core/shared/item.model'; -import { MetadataRepresentation } from '../../../../core/shared/metadata-representation/metadata-representation.model'; -import { ItemViewMode, rendersItemType } from '../../../../shared/items/item-type-decorator'; -import { isNotEmpty } from '../../../../shared/empty.util'; +import { Component } from '@angular/core'; import { ItemComponent } from '../../../../+item-page/simple/item-types/shared/item.component'; -import { getRelatedItemsByTypeLabel } from '../../../../+item-page/simple/item-types/shared/item-relationships-utils'; +import { listableObjectComponent } from '../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; -@rendersItemType('Project', ItemViewMode.Full) +@listableObjectComponent('Project', ViewMode.StandalonePage) @Component({ selector: 'ds-project', styleUrls: ['./project.component.scss'], @@ -16,44 +12,5 @@ import { getRelatedItemsByTypeLabel } from '../../../../+item-page/simple/item-t /** * The component for displaying metadata and relations of an item of the type Project */ -export class ProjectComponent extends ItemComponent implements OnInit { - /** - * The contributors related to this project - */ - contributors$: Observable; - - /** - * The people related to this project - */ - people$: Observable; - - /** - * The publications related to this project - */ - publications$: Observable; - - /** - * The organisation units related to this project - */ - orgUnits$: Observable; - - ngOnInit(): void { - super.ngOnInit(); - - if (isNotEmpty(this.resolvedRelsAndTypes$)) { - this.contributors$ = this.buildRepresentations('OrgUnit', 'project.contributor.other'); - - this.people$ = this.resolvedRelsAndTypes$.pipe( - getRelatedItemsByTypeLabel(this.item.id, 'isPersonOfProject') - ); - - this.publications$ = this.resolvedRelsAndTypes$.pipe( - getRelatedItemsByTypeLabel(this.item.id, 'isPublicationOfProject') - ); - - this.orgUnits$ = this.resolvedRelsAndTypes$.pipe( - getRelatedItemsByTypeLabel(this.item.id, 'isOrgUnitOfProject') - ); - } - } +export class ProjectComponent extends ItemComponent { } diff --git a/src/app/entity-groups/research-entities/item-list-elements/orgunit/orgunit-metadata-list-element.component.html b/src/app/entity-groups/research-entities/metadata-representations/org-unit/org-unit-item-metadata-list-element.component.html similarity index 100% rename from src/app/entity-groups/research-entities/item-list-elements/orgunit/orgunit-metadata-list-element.component.html rename to src/app/entity-groups/research-entities/metadata-representations/org-unit/org-unit-item-metadata-list-element.component.html diff --git a/src/app/entity-groups/research-entities/metadata-representations/org-unit/org-unit-item-metadata-list-element.component.spec.ts b/src/app/entity-groups/research-entities/metadata-representations/org-unit/org-unit-item-metadata-list-element.component.spec.ts new file mode 100644 index 0000000000..7d27b605ec --- /dev/null +++ b/src/app/entity-groups/research-entities/metadata-representations/org-unit/org-unit-item-metadata-list-element.component.spec.ts @@ -0,0 +1,49 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { By } from '@angular/platform-browser'; +import { ItemMetadataRepresentation } from '../../../../core/shared/metadata-representation/item/item-metadata-representation.model'; +import { OrgUnitItemMetadataListElementComponent } from './org-unit-item-metadata-list-element.component'; +import { Item } from '../../../../core/shared/item.model'; +import { TooltipModule } from 'ngx-bootstrap'; +import { MetadataValue } from '../../../../core/shared/metadata.models'; + +const description = 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.'; +const organisation = 'Anonymous'; +const mockItem = Object.assign(new Item(), { metadata: { 'dc.description': [{ value: description }], 'organization.legalName': [{ value: organisation }] } }); +const virtMD = Object.assign(new MetadataValue(), { value: organisation }); +const mockItemMetadataRepresentation = Object.assign(new ItemMetadataRepresentation(virtMD), mockItem); + +describe('OrgUnitItemMetadataListElementComponent', () => { + let comp: OrgUnitItemMetadataListElementComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [TooltipModule.forRoot()], + declarations: [OrgUnitItemMetadataListElementComponent], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(OrgUnitItemMetadataListElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(OrgUnitItemMetadataListElementComponent); + comp = fixture.componentInstance; + comp.metadataRepresentation = mockItemMetadataRepresentation; + fixture.detectChanges(); + })); + + it('should show the name of the organisation as a link', () => { + const linkText = fixture.debugElement.query(By.css('a')).nativeElement.textContent; + expect(linkText).toBe(organisation); + }); + + it('should show the description on hover over the link in a tooltip', () => { + const link = fixture.debugElement.query(By.css('a')); + link.triggerEventHandler('mouseover', null); + fixture.detectChanges(); + const tooltip = fixture.debugElement.query(By.css('.item-list-job-title')).nativeElement.textContent; + expect(tooltip).toBe(description); + }); +}); diff --git a/src/app/entity-groups/research-entities/metadata-representations/org-unit/org-unit-item-metadata-list-element.component.ts b/src/app/entity-groups/research-entities/metadata-representations/org-unit/org-unit-item-metadata-list-element.component.ts new file mode 100644 index 0000000000..183bebe10c --- /dev/null +++ b/src/app/entity-groups/research-entities/metadata-representations/org-unit/org-unit-item-metadata-list-element.component.ts @@ -0,0 +1,15 @@ +import { Component } from '@angular/core'; +import { metadataRepresentationComponent } from '../../../../shared/metadata-representation/metadata-representation.decorator'; +import { MetadataRepresentationType } from '../../../../core/shared/metadata-representation/metadata-representation.model'; +import { ItemMetadataRepresentationListElementComponent } from '../../../../shared/object-list/metadata-representation-list-element/item/item-metadata-representation-list-element.component'; + +@metadataRepresentationComponent('OrgUnit', MetadataRepresentationType.Item) +@Component({ + selector: 'ds-org-unit-item-metadata-list-element', + templateUrl: './org-unit-item-metadata-list-element.component.html' +}) +/** + * The component for displaying an item of the type OrgUnit as a metadata field + */ +export class OrgUnitItemMetadataListElementComponent extends ItemMetadataRepresentationListElementComponent { +} diff --git a/src/app/entity-groups/research-entities/item-list-elements/person/person-metadata-list-element.component.html b/src/app/entity-groups/research-entities/metadata-representations/person/person-item-metadata-list-element.component.html similarity index 100% rename from src/app/entity-groups/research-entities/item-list-elements/person/person-metadata-list-element.component.html rename to src/app/entity-groups/research-entities/metadata-representations/person/person-item-metadata-list-element.component.html diff --git a/src/app/entity-groups/research-entities/metadata-representations/person/person-item-metadata-list-element.component.spec.ts b/src/app/entity-groups/research-entities/metadata-representations/person/person-item-metadata-list-element.component.spec.ts new file mode 100644 index 0000000000..1081e45884 --- /dev/null +++ b/src/app/entity-groups/research-entities/metadata-representations/person/person-item-metadata-list-element.component.spec.ts @@ -0,0 +1,51 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { By } from '@angular/platform-browser'; +import { ItemMetadataRepresentation } from '../../../../core/shared/metadata-representation/item/item-metadata-representation.model'; +import { Item } from '../../../../core/shared/item.model'; +import { PersonItemMetadataListElementComponent } from './person-item-metadata-list-element.component'; +import { TooltipModule } from 'ngx-bootstrap'; +import { MetadataValue } from '../../../../core/shared/metadata.models'; + +const jobTitle ='Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.'; +const firstName = 'Joe'; +const lastName = 'Anonymous'; +const mockItem = Object.assign(new Item(), { metadata: { 'person.jobTitle': [{ value: jobTitle }], 'person.givenName': [{ value: firstName }], 'person.familyName': [{ value: lastName }] } }); +const virtMD = Object.assign(new MetadataValue(), { value: lastName + ', ' + firstName }); + +const mockItemMetadataRepresentation = Object.assign(new ItemMetadataRepresentation(virtMD), mockItem); + +describe('PersonItemMetadataListElementComponent', () => { + let comp: PersonItemMetadataListElementComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [TooltipModule.forRoot()], + declarations: [PersonItemMetadataListElementComponent], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(PersonItemMetadataListElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(PersonItemMetadataListElementComponent); + comp = fixture.componentInstance; + comp.metadataRepresentation = mockItemMetadataRepresentation; + fixture.detectChanges(); + })); + + it('should show the person\'s name as a link', () => { + const linkText = fixture.debugElement.query(By.css('a')).nativeElement.textContent; + expect(linkText).toBe(lastName + ', ' + firstName); + }); + + it('should show the description on hover over the link in a tooltip', () => { + const link = fixture.debugElement.query(By.css('a')); + link.triggerEventHandler('mouseover', null); + fixture.detectChanges(); + const tooltip = fixture.debugElement.query(By.css('.item-list-job-title')).nativeElement.textContent; + expect(tooltip).toBe(jobTitle); + }); +}); diff --git a/src/app/entity-groups/research-entities/metadata-representations/person/person-item-metadata-list-element.component.ts b/src/app/entity-groups/research-entities/metadata-representations/person/person-item-metadata-list-element.component.ts new file mode 100644 index 0000000000..f3d0a28fda --- /dev/null +++ b/src/app/entity-groups/research-entities/metadata-representations/person/person-item-metadata-list-element.component.ts @@ -0,0 +1,15 @@ +import { Component } from '@angular/core'; +import { metadataRepresentationComponent } from '../../../../shared/metadata-representation/metadata-representation.decorator'; +import { MetadataRepresentationType } from '../../../../core/shared/metadata-representation/metadata-representation.model'; +import { ItemMetadataRepresentationListElementComponent } from '../../../../shared/object-list/metadata-representation-list-element/item/item-metadata-representation-list-element.component'; + +@metadataRepresentationComponent('Person', MetadataRepresentationType.Item) +@Component({ + selector: 'ds-person-item-metadata-list-element', + templateUrl: './person-item-metadata-list-element.component.html' +}) +/** + * The component for displaying an item of the type Person as a metadata field + */ +export class PersonItemMetadataListElementComponent extends ItemMetadataRepresentationListElementComponent { +} diff --git a/src/app/entity-groups/research-entities/research-entities.module.ts b/src/app/entity-groups/research-entities/research-entities.module.ts index 099fa2a6a3..8829318f34 100644 --- a/src/app/entity-groups/research-entities/research-entities.module.ts +++ b/src/app/entity-groups/research-entities/research-entities.module.ts @@ -2,31 +2,43 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { SharedModule } from '../../shared/shared.module'; import { ItemPageModule } from '../../+item-page/item-page.module'; -import { OrgunitComponent } from './item-pages/orgunit/orgunit.component'; +import { OrgUnitComponent } from './item-pages/org-unit/org-unit.component'; import { PersonComponent } from './item-pages/person/person.component'; import { ProjectComponent } from './item-pages/project/project.component'; -import { OrgUnitListElementComponent } from './item-list-elements/orgunit/orgunit-list-element.component'; -import { OrgUnitMetadataListElementComponent } from './item-list-elements/orgunit/orgunit-metadata-list-element.component'; -import { PersonMetadataListElementComponent } from './item-list-elements/person/person-metadata-list-element.component'; +import { OrgUnitListElementComponent } from './item-list-elements/org-unit/org-unit-list-element.component'; import { PersonListElementComponent } from './item-list-elements/person/person-list-element.component'; import { ProjectListElementComponent } from './item-list-elements/project/project-list-element.component'; import { TooltipModule } from 'ngx-bootstrap'; import { PersonGridElementComponent } from './item-grid-elements/person/person-grid-element.component'; -import { OrgunitGridElementComponent } from './item-grid-elements/orgunit/orgunit-grid-element.component'; +import { OrgUnitGridElementComponent } from './item-grid-elements/org-unit/org-unit-grid-element.component'; import { ProjectGridElementComponent } from './item-grid-elements/project/project-grid-element.component'; +import { OrgUnitSearchResultListElementComponent } from './item-list-elements/search-result-list-elements/org-unit/org-unit-search-result-list-element.component'; +import { PersonSearchResultListElementComponent } from './item-list-elements/search-result-list-elements/person/person-search-result-list-element.component'; +import { ProjectSearchResultListElementComponent } from './item-list-elements/search-result-list-elements/project/project-search-result-list-element.component'; +import { PersonSearchResultGridElementComponent } from './item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component'; +import { OrgUnitSearchResultGridElementComponent } from './item-grid-elements/search-result-grid-elements/org-unit/org-unit-search-result-grid-element.component'; +import { ProjectSearchResultGridElementComponent } from './item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component'; +import { PersonItemMetadataListElementComponent } from './metadata-representations/person/person-item-metadata-list-element.component'; +import { OrgUnitItemMetadataListElementComponent } from './metadata-representations/org-unit/org-unit-item-metadata-list-element.component'; const ENTRY_COMPONENTS = [ - OrgunitComponent, + OrgUnitComponent, PersonComponent, ProjectComponent, OrgUnitListElementComponent, - OrgUnitMetadataListElementComponent, + OrgUnitItemMetadataListElementComponent, PersonListElementComponent, - PersonMetadataListElementComponent, + PersonItemMetadataListElementComponent, ProjectListElementComponent, PersonGridElementComponent, - OrgunitGridElementComponent, - ProjectGridElementComponent + OrgUnitGridElementComponent, + ProjectGridElementComponent, + OrgUnitSearchResultListElementComponent, + PersonSearchResultListElementComponent, + ProjectSearchResultListElementComponent, + PersonSearchResultGridElementComponent, + OrgUnitSearchResultGridElementComponent, + ProjectSearchResultGridElementComponent ]; @NgModule({ diff --git a/src/app/shared/browse-by/browse-by.component.html b/src/app/shared/browse-by/browse-by.component.html index c4b235f277..09d3cd3d60 100644 --- a/src/app/shared/browse-by/browse-by.component.html +++ b/src/app/shared/browse-by/browse-by.component.html @@ -25,7 +25,7 @@
  • - +
diff --git a/src/app/shared/dso-selector/dso-selector/dso-selector.component.html b/src/app/shared/dso-selector/dso-selector/dso-selector.component.html index 662144823d..e2eda4dcfd 100644 --- a/src/app/shared/dso-selector/dso-selector/dso-selector.component.html +++ b/src/app/shared/dso-selector/dso-selector/dso-selector.component.html @@ -15,6 +15,6 @@ class="list-group-item list-group-item-action border-0 list-entry" title="{{ listEntry.indexableObject.name }}" (click)="onSelect.emit(listEntry.indexableObject)" #listEntryElement> - +
diff --git a/src/app/shared/dso-selector/dso-selector/dso-selector.component.ts b/src/app/shared/dso-selector/dso-selector/dso-selector.component.ts index 04501e4923..af26f3f04f 100644 --- a/src/app/shared/dso-selector/dso-selector/dso-selector.component.ts +++ b/src/app/shared/dso-selector/dso-selector/dso-selector.component.ts @@ -19,6 +19,7 @@ import { RemoteData } from '../../../core/data/remote-data'; import { PaginatedList } from '../../../core/data/paginated-list'; import { SearchResult } from '../../../+search-page/search-result.model'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; +import { ViewMode } from '../../../core/shared/view-mode.model'; @Component({ selector: 'ds-dso-selector', @@ -31,7 +32,10 @@ import { DSpaceObject } from '../../../core/shared/dspace-object.model'; * The user can search the list by using the input field */ export class DSOSelectorComponent implements OnInit { - + /** + * The view mode of the listed objects + */ + viewMode = ViewMode.ListElement; /** * The initially selected DSO's uuid */ diff --git a/src/app/shared/input-suggestions/dso-input-suggestions/dso-input-suggestions.component.html b/src/app/shared/input-suggestions/dso-input-suggestions/dso-input-suggestions.component.html index 2b605ccdc6..7515b830b9 100644 --- a/src/app/shared/input-suggestions/dso-input-suggestions/dso-input-suggestions.component.html +++ b/src/app/shared/input-suggestions/dso-input-suggestions/dso-input-suggestions.component.html @@ -1,5 +1,5 @@
@@ -14,9 +14,7 @@ diff --git a/src/app/shared/input-suggestions/dso-input-suggestions/dso-input-suggestions.component.ts b/src/app/shared/input-suggestions/dso-input-suggestions/dso-input-suggestions.component.ts index bb1272f076..cf3658d5c9 100644 --- a/src/app/shared/input-suggestions/dso-input-suggestions/dso-input-suggestions.component.ts +++ b/src/app/shared/input-suggestions/dso-input-suggestions/dso-input-suggestions.component.ts @@ -2,6 +2,8 @@ import { Component, forwardRef, Input } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { InputSuggestionsComponent } from '../input-suggestions.component'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; +import { ViewMode } from '../../../core/shared/view-mode.model'; +import { CollectionElementLinkType } from '../../object-collection/collection-element-link.type'; @Component({ selector: 'ds-dso-input-suggestions', @@ -22,6 +24,16 @@ import { DSpaceObject } from '../../../core/shared/dspace-object.model'; * Component representing a form with a autocomplete functionality for DSpaceObjects */ export class DsoInputSuggestionsComponent extends InputSuggestionsComponent { + /** + * The view mode of the listed object suggestions + */ + viewMode = ViewMode.ListElement; + + /** + * The available link types + */ + linkTypes = CollectionElementLinkType; + /** * The suggestions that should be shown */ diff --git a/src/app/shared/input-suggestions/input-suggestions.component.scss b/src/app/shared/input-suggestions/input-suggestions.component.scss index eb0db5ed42..263c315d30 100644 --- a/src/app/shared/input-suggestions/input-suggestions.component.scss +++ b/src/app/shared/input-suggestions/input-suggestions.component.scss @@ -5,19 +5,9 @@ white-space: normal; word-break: break-word; padding: $input-padding-y $input-padding-x; - position: relative; - &:focus { outline: none; } - - .click-blocker { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - } } } diff --git a/src/app/shared/items/item-type-decorator.ts b/src/app/shared/items/item-type-decorator.ts deleted file mode 100644 index 3a040ae5bf..0000000000 --- a/src/app/shared/items/item-type-decorator.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { hasNoValue, hasValue } from '../empty.util'; -import { MetadataRepresentationType } from '../../core/shared/metadata-representation/metadata-representation.model'; - -export enum ItemViewMode { - Element = 'element', - Card = 'card', - Full = 'full', - Metadata = 'metadata' -} - -export const DEFAULT_ITEM_TYPE = 'Default'; -export const DEFAULT_VIEW_MODE = ItemViewMode.Element; -export const NO_REPRESENTATION_TYPE = MetadataRepresentationType.None; -export const DEFAULT_REPRESENTATION_TYPE = MetadataRepresentationType.PlainText; - -const map = new Map(); - -/** - * Decorator used for rendering simple item pages by type and viewMode (and optionally a representationType) - * @param type - * @param viewMode - * @param representationType - */ -export function rendersItemType(type: string, viewMode: string, representationType?: MetadataRepresentationType) { - return function decorator(component: any) { - if (hasNoValue(map.get(viewMode))) { - map.set(viewMode, new Map()); - } - if (hasNoValue(map.get(viewMode).get(type))) { - map.get(viewMode).set(type, new Map()); - } - if (hasNoValue(representationType)) { - representationType = NO_REPRESENTATION_TYPE; - } - if (hasValue(map.get(viewMode).get(type).get(representationType))) { - throw new Error(`There can't be more than one component to render Metadata of type "${type}" in view mode "${viewMode}" with representation type "${representationType}"`); - } - map.get(viewMode).get(type).set(representationType, component); - }; -} - -/** - * Get the component used for rendering an item by type and viewMode (and optionally a representationType) - * @param type - * @param viewMode - * @param representationType - */ -export function getComponentByItemType(type: string, viewMode: string, representationType?: MetadataRepresentationType) { - if (hasNoValue(representationType)) { - representationType = NO_REPRESENTATION_TYPE; - } - if (hasNoValue(map.get(viewMode))) { - viewMode = DEFAULT_VIEW_MODE; - } - if (hasNoValue(map.get(viewMode).get(type))) { - type = DEFAULT_ITEM_TYPE; - } - let representationComponent = map.get(viewMode).get(type).get(representationType); - if (hasNoValue(representationComponent)) { - representationComponent = map.get(viewMode).get(type).get(DEFAULT_REPRESENTATION_TYPE); - } - if (hasNoValue(representationComponent)) { - representationComponent = map.get(viewMode).get(type).get(NO_REPRESENTATION_TYPE); - } - return representationComponent; -} diff --git a/src/app/shared/items/switcher/item-type-switcher.component.html b/src/app/shared/items/switcher/item-type-switcher.component.html deleted file mode 100644 index f2ea5784fc..0000000000 --- a/src/app/shared/items/switcher/item-type-switcher.component.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/app/shared/items/switcher/item-type-switcher.component.scss b/src/app/shared/items/switcher/item-type-switcher.component.scss deleted file mode 100644 index 45a533cd01..0000000000 --- a/src/app/shared/items/switcher/item-type-switcher.component.scss +++ /dev/null @@ -1 +0,0 @@ -@import '../../../../styles/variables'; diff --git a/src/app/shared/items/switcher/item-type-switcher.component.spec.ts b/src/app/shared/items/switcher/item-type-switcher.component.spec.ts deleted file mode 100644 index 1c1612744a..0000000000 --- a/src/app/shared/items/switcher/item-type-switcher.component.spec.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { ItemTypeSwitcherComponent } from './item-type-switcher.component'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { PageInfo } from '../../../core/shared/page-info.model'; -import { Item } from '../../../core/shared/item.model'; -import { PaginatedList } from '../../../core/data/paginated-list'; -import * as decorator from '../item-type-decorator'; -import { getComponentByItemType, ItemViewMode } from '../item-type-decorator'; -import { ItemMetadataRepresentation } from '../../../core/shared/metadata-representation/item/item-metadata-representation.model'; -import { createSuccessfulRemoteDataObject$ } from '../../testing/utils'; -import createSpy = jasmine.createSpy; - -const relationType = 'type'; -const mockItem: Item = Object.assign(new Item(), { - bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), - metadata: { - 'dc.title': [ - { - language: 'en_US', - value: 'test item' - } - ], - 'relationship.type': [ - { - language: 'en_US', - value: relationType - } - ] - } -}); -const mockItemMetadataRepresentation = Object.assign(new ItemMetadataRepresentation(Object.assign({})), mockItem); -let viewMode = ItemViewMode.Full; - -describe('ItemTypeSwitcherComponent', () => { - let comp: ItemTypeSwitcherComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ ItemTypeSwitcherComponent ], - schemas: [ NO_ERRORS_SCHEMA ] - }).compileComponents(); // compile template and css - })); - - beforeEach(async(() => { - fixture = TestBed.createComponent(ItemTypeSwitcherComponent); - comp = fixture.componentInstance; - comp.object = mockItem; - comp.viewMode = viewMode; - spyOnProperty(decorator, 'getComponentByItemType').and.returnValue(createSpy('getComponentByItemType')) - })); - - describe('when the injected object is of type Item', () => { - beforeEach(() => { - viewMode = ItemViewMode.Full; - comp.object = mockItem; - comp.viewMode = viewMode; - }); - - describe('when calling getComponent', () => { - beforeEach(() => { - (comp as any).getComponent(); - }); - - it('should call getComponentByItemType with parameters type and viewMode', () => { - expect(decorator.getComponentByItemType).toHaveBeenCalledWith(relationType, viewMode); - }); - }); - }); - - describe('when the injected object is of type MetadataRepresentation', () => { - beforeEach(() => { - viewMode = ItemViewMode.Metadata; - comp.object = mockItemMetadataRepresentation; - comp.viewMode = viewMode; - }); - - describe('when calling getComponent', () => { - beforeEach(() => { - (comp as any).getComponent(); - }); - - it('should call getComponentByItemType with parameters type, viewMode and representationType', () => { - expect(decorator.getComponentByItemType).toHaveBeenCalledWith(relationType, viewMode, mockItemMetadataRepresentation.representationType); - }); - }); - }); - -}); diff --git a/src/app/shared/items/switcher/item-type-switcher.component.ts b/src/app/shared/items/switcher/item-type-switcher.component.ts deleted file mode 100644 index cd061bc1dd..0000000000 --- a/src/app/shared/items/switcher/item-type-switcher.component.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { Component, InjectionToken, Injector, Input, OnInit } from '@angular/core'; -import { SearchResult } from '../../../+search-page/search-result.model'; -import { Item } from '../../../core/shared/item.model'; -import { hasValue } from '../../empty.util'; -import { ItemSearchResult } from '../../object-collection/shared/item-search-result.model'; -import { getComponentByItemType } from '../item-type-decorator'; -import { MetadataRepresentation } from '../../../core/shared/metadata-representation/metadata-representation.model'; - -export const ITEM: InjectionToken = new InjectionToken('item'); - -@Component({ - selector: 'ds-item-type-switcher', - styleUrls: ['./item-type-switcher.component.scss'], - templateUrl: './item-type-switcher.component.html' -}) -/** - * Component for determining what component to use depending on the item's relationship type (relationship.type) - */ -export class ItemTypeSwitcherComponent implements OnInit { - /** - * The item or metadata to determine the component for - */ - @Input() object: Item | SearchResult | MetadataRepresentation; - - /** - * The preferred view-mode to display - */ - @Input() viewMode: string; - - /** - * The object injector used to inject the item into the child component - */ - objectInjector: Injector; - - component: any; - - constructor(private injector: Injector) { - } - - ngOnInit(): void { - this.objectInjector = Injector.create({ - providers: [{ provide: ITEM, useFactory: () => this.object, deps:[] }], - parent: this.injector - }); - this.component = this.getComponent(); - } - - /** - * Fetch the component depending on the item's relationship type - * @returns {string} - */ - private getComponent(): string { - if (hasValue((this.object as any).representationType)) { - const metadataRepresentation = this.object as MetadataRepresentation; - return getComponentByItemType(metadataRepresentation.itemType, this.viewMode, metadataRepresentation.representationType); - } - - let item: Item; - if (hasValue((this.object as any).indexableObject)) { - const searchResult = this.object as ItemSearchResult; - item = searchResult.indexableObject; - } else { - item = this.object as Item; - } - - const type = item.firstMetadataValue('relationship.type'); - return getComponentByItemType(type, this.viewMode); - } -} diff --git a/src/app/shared/metadata-representation/metadata-representation-loader.component.html b/src/app/shared/metadata-representation/metadata-representation-loader.component.html new file mode 100644 index 0000000000..3979c238ad --- /dev/null +++ b/src/app/shared/metadata-representation/metadata-representation-loader.component.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/app/shared/metadata-representation/metadata-representation-loader.component.spec.ts b/src/app/shared/metadata-representation/metadata-representation-loader.component.spec.ts new file mode 100644 index 0000000000..4097fb99c4 --- /dev/null +++ b/src/app/shared/metadata-representation/metadata-representation-loader.component.spec.ts @@ -0,0 +1,63 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ChangeDetectionStrategy, ComponentFactoryResolver, NO_ERRORS_SCHEMA } from '@angular/core'; +import { Context } from '../../core/shared/context.model'; +import { MetadataRepresentation, MetadataRepresentationType } from '../../core/shared/metadata-representation/metadata-representation.model'; +import { MetadataRepresentationLoaderComponent } from './metadata-representation-loader.component'; +import { PlainTextMetadataListElementComponent } from '../object-list/metadata-representation-list-element/plain-text/plain-text-metadata-list-element.component'; +import { spyOnExported } from '../testing/utils'; +import { MetadataRepresentationDirective } from './metadata-representation.directive'; +import * as metadataRepresentationDecorator from './metadata-representation.decorator'; + +const testType = 'TestType'; +const testContext = Context.Search; +const testRepresentationType = MetadataRepresentationType.Item; + +class TestType implements MetadataRepresentation { + get itemType(): string { + return testType; + } + + get representationType(): MetadataRepresentationType { + return testRepresentationType; + } + + getValue(): string { + return ''; + } +} +describe('MetadataRepresentationLoaderComponent', () => { + let comp: MetadataRepresentationLoaderComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [], + declarations: [MetadataRepresentationLoaderComponent, PlainTextMetadataListElementComponent, MetadataRepresentationDirective], + schemas: [NO_ERRORS_SCHEMA], + providers: [ComponentFactoryResolver] + }).overrideComponent(MetadataRepresentationLoaderComponent, { + set: { + changeDetection: ChangeDetectionStrategy.Default, + entryComponents: [PlainTextMetadataListElementComponent] + } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(MetadataRepresentationLoaderComponent); + comp = fixture.componentInstance; + + comp.mdRepresentation = new TestType(); + comp.context = testContext; + + spyOnExported(metadataRepresentationDecorator, 'getMetadataRepresentationComponent').and.returnValue(PlainTextMetadataListElementComponent); + fixture.detectChanges(); + + })); + + describe('When the component is rendered', () => { + it('should call the getMetadataRepresentationComponent function with the right entity type, representation type and context', () => { + expect(metadataRepresentationDecorator.getMetadataRepresentationComponent).toHaveBeenCalledWith(testType, testRepresentationType, testContext); + }) + }); +}); diff --git a/src/app/shared/metadata-representation/metadata-representation-loader.component.ts b/src/app/shared/metadata-representation/metadata-representation-loader.component.ts new file mode 100644 index 0000000000..eb385b5afd --- /dev/null +++ b/src/app/shared/metadata-representation/metadata-representation-loader.component.ts @@ -0,0 +1,56 @@ +import { Component, ComponentFactoryResolver, InjectionToken, Injector, Input, OnInit, ViewChild } from '@angular/core'; +import { MetadataRepresentation } from '../../core/shared/metadata-representation/metadata-representation.model'; +import { getMetadataRepresentationComponent } from './metadata-representation.decorator'; +import { Context } from '../../core/shared/context.model'; +import { GenericConstructor } from '../../core/shared/generic-constructor'; +import { MetadataRepresentationListElementComponent } from '../object-list/metadata-representation-list-element/metadata-representation-list-element.component'; +import { MetadataRepresentationDirective } from './metadata-representation.directive'; + +@Component({ + selector: 'ds-metadata-representation-loader', + // styleUrls: ['./metadata-representation-loader.component.scss'], + templateUrl: './metadata-representation-loader.component.html' +}) +/** + * Component for determining what component to use depending on the item's relationship type (relationship.type), its metadata representation and, optionally, its context + */ +export class MetadataRepresentationLoaderComponent implements OnInit { + /** + * The item or metadata to determine the component for + */ + @Input() mdRepresentation: MetadataRepresentation; + + /** + * The optional context + */ + @Input() context: Context; + + /** + * Directive to determine where the dynamic child component is located + */ + @ViewChild(MetadataRepresentationDirective) mdRepDirective: MetadataRepresentationDirective; + + constructor(private componentFactoryResolver: ComponentFactoryResolver) { + } + + /** + * Set up the dynamic child component + */ + ngOnInit(): void { + const componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.getComponent()); + + const viewContainerRef = this.mdRepDirective.viewContainerRef; + viewContainerRef.clear(); + + const componentRef = viewContainerRef.createComponent(componentFactory); + (componentRef.instance as MetadataRepresentationListElementComponent).metadataRepresentation = this.mdRepresentation; + } + + /** + * Fetch the component depending on the item's relationship type, metadata representation type and context + * @returns {string} + */ + private getComponent(): GenericConstructor { + return getMetadataRepresentationComponent(this.mdRepresentation.itemType, this.mdRepresentation.representationType, this.context); + } +} diff --git a/src/app/shared/metadata-representation/metadata-representation.decorator.spec.ts b/src/app/shared/metadata-representation/metadata-representation.decorator.spec.ts new file mode 100644 index 0000000000..0ca7ebb9b9 --- /dev/null +++ b/src/app/shared/metadata-representation/metadata-representation.decorator.spec.ts @@ -0,0 +1,63 @@ +import { DEFAULT_ENTITY_TYPE, DEFAULT_REPRESENTATION_TYPE, getMetadataRepresentationComponent, metadataRepresentationComponent } from './metadata-representation.decorator'; +import { MetadataRepresentationType } from '../../core/shared/metadata-representation/metadata-representation.model'; +import { Context } from '../../core/shared/context.model'; +import * as uuidv4 from 'uuid/v4'; + +describe('MetadataRepresentation decorator function', () => { + const type1 = 'TestType'; + const type2 = 'TestType2'; + const type3 = 'TestType3'; + const type4 = 'RandomType'; + let prefix; + /* tslint:disable:max-classes-per-file */ + class Test1PlainText {}; + class Test1Authority {}; + class Test2Item {}; + class Test2ItemSubmission {}; + class Test3ItemSubmission {}; + /* tslint:enable:max-classes-per-file */ + + beforeEach(() => { + prefix = uuidv4(); + init(prefix); + }); + + function init(key) { + metadataRepresentationComponent(key + type1, MetadataRepresentationType.PlainText)(Test1PlainText); + metadataRepresentationComponent(key + type1, MetadataRepresentationType.AuthorityControlled)(Test1Authority); + + metadataRepresentationComponent(key + type2, MetadataRepresentationType.Item)(Test2Item); + metadataRepresentationComponent(key + type2, MetadataRepresentationType.Item, Context.Workspace)(Test2ItemSubmission); + + metadataRepresentationComponent(key + type3, MetadataRepresentationType.Item, Context.Workspace)(Test3ItemSubmission); + } + + describe('If there\'s an exact match', () => { + it('should return the matching class', () => { + const component = getMetadataRepresentationComponent(prefix + type3, MetadataRepresentationType.Item, Context.Workspace); + expect(component).toEqual(Test3ItemSubmission); + }); + }); + + describe('If there isn\'nt an exact match', () => { + describe('If there is a match for the entity type and representation type', () => { + it('should return the class with the matching entity type and representation type and default context', () => { + const component = getMetadataRepresentationComponent(prefix + type1, MetadataRepresentationType.AuthorityControlled, Context.Workspace); + expect(component).toEqual(Test1Authority); + }); + }); + describe('If there isn\'t a match for the representation type', () => { + it('should return the class with the matching entity type and the default representation type and default context', () => { + const component = getMetadataRepresentationComponent(prefix + type1, MetadataRepresentationType.Item); + expect(component).toEqual(Test1PlainText); + }); + describe('If there isn\'t a match for the entity type', () => { + it('should return the class with the default entity type and the default representation type and default context', () => { + const defaultComponent = getMetadataRepresentationComponent(DEFAULT_ENTITY_TYPE, DEFAULT_REPRESENTATION_TYPE); + const component = getMetadataRepresentationComponent(prefix + type4, MetadataRepresentationType.AuthorityControlled); + expect(component).toEqual(defaultComponent); + }); + }); + }); + }); +}); diff --git a/src/app/shared/metadata-representation/metadata-representation.decorator.ts b/src/app/shared/metadata-representation/metadata-representation.decorator.ts new file mode 100644 index 0000000000..a5ea26aa89 --- /dev/null +++ b/src/app/shared/metadata-representation/metadata-representation.decorator.ts @@ -0,0 +1,56 @@ +import { MetadataRepresentationType } from '../../core/shared/metadata-representation/metadata-representation.model'; +import { hasNoValue, hasValue } from '../empty.util'; +import { Context } from '../../core/shared/context.model'; + +export const map = new Map(); + +export const DEFAULT_ENTITY_TYPE = 'Publication'; +export const DEFAULT_REPRESENTATION_TYPE = MetadataRepresentationType.PlainText; +export const DEFAULT_CONTEXT = Context.Undefined; + +/** + * Decorator function to store metadata representation mapping + * @param entityType The entity type the component represents + * @param mdRepresentationType The metadata representation type the component represents + * @param context The optional context the component represents + */ +export function metadataRepresentationComponent(entityType: string, mdRepresentationType: MetadataRepresentationType, context: Context = DEFAULT_CONTEXT) { + return function decorator(component: any) { + if (hasNoValue(map.get(entityType))) { + map.set(entityType, new Map()); + } + if (hasNoValue(map.get(entityType).get(mdRepresentationType))) { + map.get(entityType).set(mdRepresentationType, new Map()); + } + + if (hasValue(map.get(entityType).get(mdRepresentationType).get(context))) { + throw new Error(`There can't be more than one component to render Entity of type "${entityType}" in MetadataRepresentation "${mdRepresentationType}" with context "${context}"`); + } + map.get(entityType).get(mdRepresentationType).set(context, component); + } +} + +/** + * Getter to retrieve a matching component by entity type, metadata representation and context + * @param entityType The entity type to match + * @param mdRepresentationType The metadata representation to match + * @param context The context to match + */ +export function getMetadataRepresentationComponent(entityType: string, mdRepresentationType: MetadataRepresentationType, context: Context = DEFAULT_CONTEXT) { + const mapForEntity = map.get(entityType); + if (hasValue(mapForEntity)) { + const entityAndMDRepMap = mapForEntity.get(mdRepresentationType); + if (hasValue(entityAndMDRepMap)) { + if (hasValue(entityAndMDRepMap.get(context))) { + return entityAndMDRepMap.get(context); + } + if (hasValue(entityAndMDRepMap.get(DEFAULT_CONTEXT))) { + return entityAndMDRepMap.get(DEFAULT_CONTEXT); + } + } + if (hasValue(mapForEntity.get(DEFAULT_REPRESENTATION_TYPE))) { + return mapForEntity.get(DEFAULT_REPRESENTATION_TYPE).get(DEFAULT_CONTEXT); + } + } + return map.get(DEFAULT_ENTITY_TYPE).get(DEFAULT_REPRESENTATION_TYPE).get(DEFAULT_CONTEXT); +} diff --git a/src/app/shared/metadata-representation/metadata-representation.directive.ts b/src/app/shared/metadata-representation/metadata-representation.directive.ts new file mode 100644 index 0000000000..9ff0573baf --- /dev/null +++ b/src/app/shared/metadata-representation/metadata-representation.directive.ts @@ -0,0 +1,11 @@ +import { Directive, ViewContainerRef } from '@angular/core'; + +@Directive({ + selector: '[dsMetadataRepresentation]', +}) +/** + * Directive used as a hook to know where to inject the dynamic metadata representation component + */ +export class MetadataRepresentationDirective { + constructor(public viewContainerRef: ViewContainerRef) { } +} diff --git a/src/app/shared/mocks/mock-remote-data-build.service.ts b/src/app/shared/mocks/mock-remote-data-build.service.ts index 888327bbda..2e492daf14 100644 --- a/src/app/shared/mocks/mock-remote-data-build.service.ts +++ b/src/app/shared/mocks/mock-remote-data-build.service.ts @@ -6,8 +6,10 @@ import { RequestEntry } from '../../core/data/request.reducer'; import { hasValue } from '../empty.util'; import { NormalizedObject } from '../../core/cache/models/normalized-object.model'; import { createSuccessfulRemoteDataObject$ } from '../testing/utils'; +import { PaginatedList } from '../../core/data/paginated-list'; +import { PageInfo } from '../../core/shared/page-info.model'; -export function getMockRemoteDataBuildService(toRemoteDataObservable$?: Observable>): RemoteDataBuildService { +export function getMockRemoteDataBuildService(toRemoteDataObservable$?: Observable>, buildList$?: Observable>>): RemoteDataBuildService { return { toRemoteDataObservable: (requestEntry$: Observable, payload$: Observable) => { @@ -20,7 +22,14 @@ export function getMockRemoteDataBuildService(toRemoteDataObservable$?: Observab } }, buildSingle: (href$: string | Observable) => createSuccessfulRemoteDataObject$({}), - build: (normalized: NormalizedObject) => Object.create({}) + build: (normalized: NormalizedObject) => Object.create({}), + buildList: (href$: string | Observable) => { + if (hasValue(buildList$)) { + return buildList$; + } else { + return createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])) + } + } } as RemoteDataBuildService; } diff --git a/src/app/shared/mocks/mock-search-service.ts b/src/app/shared/mocks/mock-search-service.ts new file mode 100644 index 0000000000..20da2049d1 --- /dev/null +++ b/src/app/shared/mocks/mock-search-service.ts @@ -0,0 +1,12 @@ +import { of as observableOf } from 'rxjs'; +import { SearchService } from '../../+search-page/search-service/search.service'; + +export function getMockSearchService(): SearchService { + return jasmine.createSpyObj('searchService', { + search: '', + getEndpoint: observableOf('discover/search/objects'), + getSearchLink: '/mydspace', + getScopes: observableOf(['test-scope']), + setServiceOptions: {} + }); +} diff --git a/src/app/shared/mydspace-actions/claimed-task/claimed-task-actions.component.spec.ts b/src/app/shared/mydspace-actions/claimed-task/claimed-task-actions.component.spec.ts index 5084b3e9fe..edf6ae4195 100644 --- a/src/app/shared/mydspace-actions/claimed-task/claimed-task-actions.component.spec.ts +++ b/src/app/shared/mydspace-actions/claimed-task/claimed-task-actions.component.spec.ts @@ -18,6 +18,10 @@ import { ClaimedTask } from '../../../core/tasks/models/claimed-task-object.mode import { WorkflowItem } from '../../../core/submission/models/workflowitem.model'; import { createSuccessfulRemoteDataObject } from '../../testing/utils'; import { CoreModule } from '../../../core/core.module'; +import { getMockSearchService } from '../../mocks/mock-search-service'; +import { getMockRequestService } from '../../mocks/mock-request.service'; +import { SearchService } from '../../../+search-page/search-service/search.service'; +import { RequestService } from '../../../core/data/request.service'; let component: ClaimedTaskActionsComponent; let fixture: ComponentFixture; @@ -32,8 +36,12 @@ const mockDataService = jasmine.createSpyObj('ClaimedTaskDataService', { returnToPoolTask: jasmine.createSpy('returnToPoolTask'), }); +const searchService = getMockSearchService(); + +const requestServce = getMockRequestService(); + const item = Object.assign(new Item(), { - bitstreams: observableOf({}), + bundles: observableOf({}), metadata: { 'dc.title': [ { @@ -83,6 +91,8 @@ describe('ClaimedTaskActionsComponent', () => { { provide: NotificationsService, useValue: new NotificationsServiceStub() }, { provide: Router, useValue: new RouterStub() }, { provide: ClaimedTaskDataService, useValue: mockDataService }, + { provide: SearchService, useValue: searchService }, + { provide: RequestService, useValue: requestServce } ], schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(ClaimedTaskActionsComponent, { diff --git a/src/app/shared/mydspace-actions/claimed-task/claimed-task-actions.component.ts b/src/app/shared/mydspace-actions/claimed-task/claimed-task-actions.component.ts index 0ddb24ec2f..6355b4eca1 100644 --- a/src/app/shared/mydspace-actions/claimed-task/claimed-task-actions.component.ts +++ b/src/app/shared/mydspace-actions/claimed-task/claimed-task-actions.component.ts @@ -13,9 +13,11 @@ import { WorkflowItem } from '../../../core/submission/models/workflowitem.model import { RemoteData } from '../../../core/data/remote-data'; import { MyDSpaceActionsComponent } from '../mydspace-actions'; import { NotificationsService } from '../../notifications/notifications.service'; +import { SearchService } from '../../../+search-page/search-service/search.service'; +import { RequestService } from '../../../core/data/request.service'; /** - * This component represents mydspace actions related to ClaimedTask object. + * This component represents actions related to ClaimedTask object. */ @Component({ selector: 'ds-claimed-task-actions', @@ -56,12 +58,16 @@ export class ClaimedTaskActionsComponent extends MyDSpaceActionsComponent; @@ -21,7 +25,7 @@ let mockObject: Item; const mockDataService = {}; mockObject = Object.assign(new Item(), { - bitstreams: observableOf({}), + bundles: observableOf({}), metadata: { 'dc.title': [ { @@ -50,6 +54,10 @@ mockObject = Object.assign(new Item(), { } }); +const searchService = getMockSearchService() + +const requestServce = getMockRequestService(); + describe('ItemActionsComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ @@ -67,6 +75,8 @@ describe('ItemActionsComponent', () => { { provide: Router, useValue: new RouterStub() }, { provide: ItemDataService, useValue: mockDataService }, { provide: NotificationsService, useValue: new NotificationsServiceStub() }, + { provide: SearchService, useValue: searchService }, + { provide: RequestService, useValue: requestServce } ], schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(ItemActionsComponent, { diff --git a/src/app/shared/mydspace-actions/item/item-actions.component.ts b/src/app/shared/mydspace-actions/item/item-actions.component.ts index eeb6e49ad9..7f6307c5ec 100644 --- a/src/app/shared/mydspace-actions/item/item-actions.component.ts +++ b/src/app/shared/mydspace-actions/item/item-actions.component.ts @@ -7,6 +7,8 @@ import { MyDSpaceActionsComponent } from '../mydspace-actions'; import { ItemDataService } from '../../../core/data/item-data.service'; import { Item } from '../../../core/shared/item.model'; import { NotificationsService } from '../../notifications/notifications.service'; +import { SearchService } from '../../../+search-page/search-service/search.service'; +import { RequestService } from '../../../core/data/request.service'; /** * This component represents mydspace actions related to Item object. @@ -31,12 +33,16 @@ export class ItemActionsComponent extends MyDSpaceActionsComponent(); this.objectDataService = injector.get(factory.getConstructor(objectType)); } @@ -57,13 +66,18 @@ export abstract class MyDSpaceActionsComponent { return false; }; - this.router.navigated = false; - const url = decodeURIComponent(this.router.url); - this.router.navigateByUrl(url); + // This assures that the search cache is empty before reloading mydspace. + // See https://github.com/DSpace/dspace-angular/pull/468 + this.searchService.getEndpoint().pipe( + take(1), + tap((cachedHref) => this.requestService.removeByHrefSubstring(cachedHref)) + ).subscribe(() => this.router.navigateByUrl(url)); } /** diff --git a/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.spec.ts b/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.spec.ts index c06cec3422..f9d88d610a 100644 --- a/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.spec.ts +++ b/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.spec.ts @@ -17,6 +17,10 @@ import { PoolTaskActionsComponent } from './pool-task-actions.component'; import { PoolTask } from '../../../core/tasks/models/pool-task-object.model'; import { WorkflowItem } from '../../../core/submission/models/workflowitem.model'; import { createSuccessfulRemoteDataObject } from '../../testing/utils'; +import { getMockRequestService } from '../../mocks/mock-request.service'; +import { SearchService } from '../../../+search-page/search-service/search.service'; +import { RequestService } from '../../../core/data/request.service'; +import { getMockSearchService } from '../../mocks/mock-search-service'; let component: PoolTaskActionsComponent; let fixture: ComponentFixture; @@ -29,8 +33,12 @@ const mockDataService = jasmine.createSpyObj('PoolTaskDataService', { claimTask: jasmine.createSpy('claimTask') }); +const searchService = getMockSearchService(); + +const requestServce = getMockRequestService(); + const item = Object.assign(new Item(), { - bitstreams: observableOf({}), + bundles: observableOf({}), metadata: { 'dc.title': [ { @@ -80,6 +88,8 @@ describe('PoolTaskActionsComponent', () => { { provide: NotificationsService, useValue: new NotificationsServiceStub() }, { provide: Router, useValue: new RouterStub() }, { provide: PoolTaskDataService, useValue: mockDataService }, + { provide: SearchService, useValue: searchService }, + { provide: RequestService, useValue: requestServce } ], schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(PoolTaskActionsComponent, { @@ -167,4 +177,14 @@ describe('PoolTaskActionsComponent', () => { }); })); + it('should clear the object cache by href', async(() => { + component.reload(); + fixture.detectChanges(); + + fixture.whenStable().then(() => { + expect(searchService.getEndpoint).toHaveBeenCalled(); + expect(requestServce.removeByHrefSubstring).toHaveBeenCalledWith('discover/search/objects'); + }); + })); + }); diff --git a/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.ts b/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.ts index 2124c0d9b6..b284be6f0b 100644 --- a/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.ts +++ b/src/app/shared/mydspace-actions/pool-task/pool-task-actions.component.ts @@ -13,6 +13,8 @@ import { PoolTaskDataService } from '../../../core/tasks/pool-task-data.service' import { isNotUndefined } from '../../empty.util'; import { MyDSpaceActionsComponent } from '../mydspace-actions'; import { NotificationsService } from '../../notifications/notifications.service'; +import { SearchService } from '../../../+search-page/search-service/search.service'; +import { RequestService } from '../../../core/data/request.service'; /** * This component represents mydspace actions related to PoolTask object. @@ -47,12 +49,16 @@ export class PoolTaskActionsComponent extends MyDSpaceActionsComponent; @@ -23,8 +27,12 @@ let mockObject: WorkflowItem; const mockDataService = {}; +const searchService = getMockSearchService(); + +const requestServce = getMockRequestService(); + const item = Object.assign(new Item(), { - bitstreams: observableOf({}), + bundles: observableOf({}), metadata: { 'dc.title': [ { @@ -72,6 +80,8 @@ describe('WorkflowitemActionsComponent', () => { { provide: Router, useValue: new RouterStub() }, { provide: WorkflowItemDataService, useValue: mockDataService }, { provide: NotificationsService, useValue: new NotificationsServiceStub() }, + { provide: SearchService, useValue: searchService }, + { provide: RequestService, useValue: requestServce } ], schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(WorkflowitemActionsComponent, { diff --git a/src/app/shared/mydspace-actions/workflowitem/workflowitem-actions.component.ts b/src/app/shared/mydspace-actions/workflowitem/workflowitem-actions.component.ts index 71f854c5e7..45e777cef8 100644 --- a/src/app/shared/mydspace-actions/workflowitem/workflowitem-actions.component.ts +++ b/src/app/shared/mydspace-actions/workflowitem/workflowitem-actions.component.ts @@ -7,9 +7,11 @@ import { MyDSpaceActionsComponent } from '../mydspace-actions'; import { WorkflowItem } from '../../../core/submission/models/workflowitem.model'; import { WorkflowItemDataService } from '../../../core/submission/workflowitem-data.service'; import { NotificationsService } from '../../notifications/notifications.service'; +import { SearchService } from '../../../+search-page/search-service/search.service'; +import { RequestService } from '../../../core/data/request.service'; /** - * This component represents mydspace actions related to WorkflowItem object. + * This component represents actions related to WorkflowItem object. */ @Component({ selector: 'ds-workflowitem-actions', @@ -30,12 +32,16 @@ export class WorkflowitemActionsComponent extends MyDSpaceActionsComponent; @@ -28,8 +32,12 @@ const mockDataService = jasmine.createSpyObj('WorkspaceitemDataService', { delete: jasmine.createSpy('delete') }); +const searchService = getMockSearchService(); + +const requestServce = getMockRequestService(); + const item = Object.assign(new Item(), { - bitstreams: observableOf({}), + bundles: observableOf({}), metadata: { 'dc.title': [ { @@ -62,6 +70,7 @@ mockObject = Object.assign(new WorkspaceItem(), { item: observableOf(rd), id: '1 describe('WorkspaceitemActionsComponent', () => { beforeEach(async(() => { + TestBed.configureTestingModule({ imports: [ NgbModule.forRoot(), @@ -78,6 +87,8 @@ describe('WorkspaceitemActionsComponent', () => { { provide: NotificationsService, useValue: new NotificationsServiceStub() }, { provide: Router, useValue: new RouterStub() }, { provide: WorkspaceitemDataService, useValue: mockDataService }, + { provide: SearchService, useValue: searchService }, + { provide: RequestService, useValue: requestServce }, NgbModal ], schemas: [NO_ERRORS_SCHEMA] @@ -161,4 +172,14 @@ describe('WorkspaceitemActionsComponent', () => { expect(notificationsServiceStub.error).toHaveBeenCalled(); }); })); + + it('should clear the object cache by href', async(() => { + component.reload(); + fixture.detectChanges(); + + fixture.whenStable().then(() => { + expect(searchService.getEndpoint).toHaveBeenCalled(); + expect(requestServce.removeByHrefSubstring).toHaveBeenCalledWith('discover/search/objects'); + }); + })); }); diff --git a/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.ts b/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.ts index 69214e800e..0a5e18ff3d 100644 --- a/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.ts +++ b/src/app/shared/mydspace-actions/workspaceitem/workspaceitem-actions.component.ts @@ -1,4 +1,4 @@ -import { Component, Injector, Input } from '@angular/core'; +import { Component, Injector, Input, OnDestroy } from '@angular/core'; import { Router } from '@angular/router'; import { BehaviorSubject } from 'rxjs'; @@ -8,11 +8,12 @@ import { TranslateService } from '@ngx-translate/core'; import { WorkspaceItem } from '../../../core/submission/models/workspaceitem.model'; import { MyDSpaceActionsComponent } from '../mydspace-actions'; import { WorkspaceitemDataService } from '../../../core/submission/workspaceitem-data.service'; -import { ResourceType } from '../../../core/shared/resource-type'; import { NotificationsService } from '../../notifications/notifications.service'; +import { SearchService } from '../../../+search-page/search-service/search.service'; +import { RequestService } from '../../../core/data/request.service'; /** - * This component represents mydspace actions related to WorkspaceItem object. + * This component represents actions related to WorkspaceItem object. */ @Component({ selector: 'ds-workspaceitem-actions', @@ -40,13 +41,17 @@ export class WorkspaceitemActionsComponent extends MyDSpaceActionsComponent + *ngIf="(currentMode$ | async) === viewModeEnum.ListElement"> + *ngIf="(currentMode$ | async) === viewModeEnum.GridElement"> + [linkType]="linkType" + [context]="context" + *ngIf="(currentMode$ | async) === viewModeEnum.DetailedListElement"> diff --git a/src/app/shared/object-collection/object-collection.component.spec.ts b/src/app/shared/object-collection/object-collection.component.spec.ts index 3b30666757..ceea03c367 100644 --- a/src/app/shared/object-collection/object-collection.component.spec.ts +++ b/src/app/shared/object-collection/object-collection.component.spec.ts @@ -1,11 +1,11 @@ import { ObjectCollectionComponent } from './object-collection.component'; -import { SetViewMode } from '../view-mode'; import { By } from '@angular/platform-browser'; import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { NO_ERRORS_SCHEMA } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { of as observableOf } from 'rxjs'; import { RouterStub } from '../testing/router-stub'; +import { ViewMode } from '../../core/shared/view-mode.model'; describe('ObjectCollectionComponent', () => { let fixture: ComponentFixture; @@ -36,14 +36,14 @@ describe('ObjectCollectionComponent', () => { })); it('should only show the grid component when the viewmode is set to grid', () => { - objectCollectionComponent.currentMode$ = observableOf(SetViewMode.Grid); + objectCollectionComponent.currentMode$ = observableOf(ViewMode.GridElement); expect(fixture.debugElement.query(By.css('ds-object-grid'))).toBeDefined(); expect(fixture.debugElement.query(By.css('ds-object-list'))).toBeNull(); }); it('should only show the list component when the viewmode is set to list', () => { - objectCollectionComponent.currentMode$ = observableOf(SetViewMode.List); + objectCollectionComponent.currentMode$ = observableOf(ViewMode.ListElement); expect(fixture.debugElement.query(By.css('ds-object-list'))).toBeDefined(); expect(fixture.debugElement.query(By.css('ds-object-grid'))).toBeNull(); diff --git a/src/app/shared/object-collection/object-collection.component.ts b/src/app/shared/object-collection/object-collection.component.ts index 526fc95781..955c21a26a 100644 --- a/src/app/shared/object-collection/object-collection.component.ts +++ b/src/app/shared/object-collection/object-collection.component.ts @@ -1,13 +1,4 @@ -import { - ChangeDetectorRef, - Component, - EventEmitter, - Input, - OnChanges, - OnInit, - Output, - SimpleChanges -} from '@angular/core'; +import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { Observable } from 'rxjs'; @@ -18,22 +9,61 @@ import { PageInfo } from '../../core/shared/page-info.model'; import { PaginationComponentOptions } from '../pagination/pagination-component-options.model'; import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model'; import { ListableObject } from './shared/listable-object.model'; -import { SetViewMode } from '../view-mode'; -import { hasValue, isEmpty, isNotEmpty } from '../empty.util'; +import { isNotEmpty } from '../empty.util'; +import { ViewMode } from '../../core/shared/view-mode.model'; +import { CollectionElementLinkType } from './collection-element-link.type'; +import { PaginatedList } from '../../core/data/paginated-list'; +import { Context } from '../../core/shared/context.model'; +/** + * Component that can render a list of listable objects in different view modes + */ @Component({ selector: 'ds-viewable-collection', styleUrls: ['./object-collection.component.scss'], templateUrl: './object-collection.component.html', }) export class ObjectCollectionComponent implements OnInit { + /** + * The list of listable objects to render in this component + */ + @Input() objects: RemoteData>; - @Input() objects: RemoteData; + /** + * The current pagination configuration + */ @Input() config?: PaginationComponentOptions; + + /** + * The current sorting configuration + */ @Input() sortConfig: SortOptions; + + /** + * Whether or not the list elements have a border or not + */ @Input() hasBorder = false; + + /** + * Whether or not to hide the gear to change the sort and pagination configuration + */ @Input() hideGear = false; + + /** + * The link type of the rendered list elements + */ + @Input() linkType: CollectionElementLinkType; + + /** + * The context of the rendered list elements + */ + @Input() context: Context; + + /** + * the page info of the list + */ pageInfo: Observable; + /** * An event fired when the page is changed. * Event's payload equals to the newly selected page. @@ -52,6 +82,9 @@ export class ObjectCollectionComponent implements OnInit { */ @Output() sortDirectionChange: EventEmitter = new EventEmitter(); + /** + * An event fired one of the pagination parameters is changed + */ @Output() paginationChange: EventEmitter = new EventEmitter(); /** @@ -59,9 +92,16 @@ export class ObjectCollectionComponent implements OnInit { * Event's payload equals to the newly selected sort field. */ @Output() sortFieldChange: EventEmitter = new EventEmitter(); - data: any = {}; - currentMode$: Observable; - viewModeEnum = SetViewMode; + + /** + * Emits the current view mode + */ + currentMode$: Observable; + + /** + * The available view modes + */ + viewModeEnum = ViewMode; ngOnInit(): void { this.currentMode$ = this.route @@ -69,7 +109,7 @@ export class ObjectCollectionComponent implements OnInit { .pipe( filter((params) => isNotEmpty(params.view)), map((params) => params.view), - startWith(SetViewMode.List) + startWith(ViewMode.ListElement) ); } @@ -87,22 +127,39 @@ export class ObjectCollectionComponent implements OnInit { private router: Router) { } + /** + * Updates the page + * @param event The new page number + */ onPageChange(event) { this.pageChange.emit(event); } - + /** + * Updates the page size + * @param event The new page size + */ onPageSizeChange(event) { this.pageSizeChange.emit(event); } - + /** + * Updates the sort direction + * @param event The new sort direction + */ onSortDirectionChange(event) { this.sortDirectionChange.emit(event); } - + /** + * Updates the sort field + * @param event The new sort field + */ onSortFieldChange(event) { this.sortFieldChange.emit(event); } + /** + * Updates the pagination + * @param event The new pagination + */ onPaginationChange(event) { this.paginationChange.emit(event); } diff --git a/src/app/shared/object-collection/shared/claimed-task-my-dspace-result.model.ts b/src/app/shared/object-collection/shared/claimed-task-search-result.model.ts similarity index 56% rename from src/app/shared/object-collection/shared/claimed-task-my-dspace-result.model.ts rename to src/app/shared/object-collection/shared/claimed-task-search-result.model.ts index 051bfe6d9f..4a7bf97850 100644 --- a/src/app/shared/object-collection/shared/claimed-task-my-dspace-result.model.ts +++ b/src/app/shared/object-collection/shared/claimed-task-search-result.model.ts @@ -1,11 +1,10 @@ import { ClaimedTask } from '../../../core/tasks/models/claimed-task-object.model'; import { SearchResult } from '../../../+search-page/search-result.model'; -import { MyDSpaceConfigurationValueType } from '../../../+my-dspace-page/my-dspace-configuration-value-type'; import { searchResultFor } from '../../../+search-page/search-service/search-result-element-decorator'; /** * Represents a search result object of a ClaimedTask object */ -@searchResultFor(ClaimedTask, MyDSpaceConfigurationValueType.Workflow) -export class ClaimedTaskMyDSpaceResult extends SearchResult { +@searchResultFor(ClaimedTask) +export class ClaimedTaskSearchResult extends SearchResult { } diff --git a/src/app/shared/object-collection/shared/dso-element-decorator.spec.ts b/src/app/shared/object-collection/shared/dso-element-decorator.spec.ts deleted file mode 100644 index 12da0f5b36..0000000000 --- a/src/app/shared/object-collection/shared/dso-element-decorator.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { SetViewMode } from '../../view-mode'; -import { renderElementsFor } from './dso-element-decorator'; -import { Item } from '../../../core/shared/item.model'; - -describe('ElementDecorator', () => { - const gridDecorator = renderElementsFor(Item, SetViewMode.Grid); - const listDecorator = renderElementsFor(Item, SetViewMode.List); - it('should have a decorator for both list and grid', () => { - expect(listDecorator.length).not.toBeNull(); - expect(gridDecorator.length).not.toBeNull(); - }); - it('should have 2 separate decorators for grid and list', () => { - expect(listDecorator).not.toEqual(gridDecorator); - }); - -}); diff --git a/src/app/shared/object-collection/shared/dso-element-decorator.ts b/src/app/shared/object-collection/shared/dso-element-decorator.ts deleted file mode 100644 index 4e4d37579a..0000000000 --- a/src/app/shared/object-collection/shared/dso-element-decorator.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { GenericConstructor } from '../../../core/shared/generic-constructor'; -import { ListableObject } from './listable-object.model'; -import { SetViewMode } from '../../view-mode'; - -const dsoElementMap = new Map(); -export function renderElementsFor(listable: GenericConstructor, viewMode: SetViewMode) { - return function decorator(objectElement: any) { - if (!objectElement) { - return; - } - if (!dsoElementMap.get(viewMode)) { - dsoElementMap.set(viewMode, new Map()); - } - dsoElementMap.get(viewMode).set(listable, objectElement); - }; -} - -export function rendersDSOType(listable: GenericConstructor, viewMode: SetViewMode) { - return dsoElementMap.get(viewMode).get(listable); -} diff --git a/src/app/shared/object-collection/shared/item-my-dspace-result.model.ts b/src/app/shared/object-collection/shared/item-my-dspace-result.model.ts deleted file mode 100644 index 92724a762f..0000000000 --- a/src/app/shared/object-collection/shared/item-my-dspace-result.model.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Item } from '../../../core/shared/item.model'; -import { SearchResult } from '../../../+search-page/search-result.model'; -import { searchResultFor } from '../../../+search-page/search-service/search-result-element-decorator'; -import { MyDSpaceConfigurationValueType } from '../../../+my-dspace-page/my-dspace-configuration-value-type'; - -/** - * Represents a search result object of a Item object - */ -@searchResultFor(Item, MyDSpaceConfigurationValueType.Workspace) -export class ItemMyDSpaceResult extends SearchResult { -} diff --git a/src/app/shared/object-collection/shared/item-search-result.model.ts b/src/app/shared/object-collection/shared/item-search-result.model.ts index f20b3db1e3..d38968ce76 100644 --- a/src/app/shared/object-collection/shared/item-search-result.model.ts +++ b/src/app/shared/object-collection/shared/item-search-result.model.ts @@ -1,7 +1,22 @@ import { SearchResult } from '../../../+search-page/search-result.model'; import { Item } from '../../../core/shared/item.model'; import { searchResultFor } from '../../../+search-page/search-service/search-result-element-decorator'; +import { GenericConstructor } from '../../../core/shared/generic-constructor'; +import { ListableObject } from './listable-object.model'; @searchResultFor(Item) export class ItemSearchResult extends SearchResult { + + /** + * Method that returns as which type of object this object should be rendered + */ + getRenderTypes(): Array> { + return this.indexableObject.getRenderTypes().map((type) => { + if (typeof type === 'string') { + return type + 'SearchResult' + } else { + return this.constructor as GenericConstructor; + } + }); + } } diff --git a/src/app/shared/object-collection/shared/listable-object.model.ts b/src/app/shared/object-collection/shared/listable-object.model.ts index 07c626cda2..d7eaf0750f 100644 --- a/src/app/shared/object-collection/shared/listable-object.model.ts +++ b/src/app/shared/object-collection/shared/listable-object.model.ts @@ -1 +1,10 @@ -export interface ListableObject {} +import { TypedObject } from '../../../core/cache/object-cache.reducer'; +import { GenericConstructor } from '../../../core/shared/generic-constructor'; + +export interface ListableObject extends TypedObject { + + /** + * Method that returns as which type of object this object should be rendered + */ + getRenderTypes(): Array>; +} diff --git a/src/app/shared/object-collection/shared/listable-object/listable-object-component-loader.component.html b/src/app/shared/object-collection/shared/listable-object/listable-object-component-loader.component.html new file mode 100644 index 0000000000..ef9a817424 --- /dev/null +++ b/src/app/shared/object-collection/shared/listable-object/listable-object-component-loader.component.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/app/shared/object-collection/shared/listable-object/listable-object-component-loader.component.spec.ts b/src/app/shared/object-collection/shared/listable-object/listable-object-component-loader.component.spec.ts new file mode 100644 index 0000000000..f470f566f0 --- /dev/null +++ b/src/app/shared/object-collection/shared/listable-object/listable-object-component-loader.component.spec.ts @@ -0,0 +1,58 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ChangeDetectionStrategy, ComponentFactoryResolver, NO_ERRORS_SCHEMA } from '@angular/core'; +import { ListableObjectComponentLoaderComponent } from './listable-object-component-loader.component'; +import { ListableObject } from '../listable-object.model'; +import { GenericConstructor } from '../../../../core/shared/generic-constructor'; +import { Context } from '../../../../core/shared/context.model'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; +import * as listableObjectDecorators from './listable-object.decorator'; +import { PublicationListElementComponent } from '../../../object-list/item-list-element/item-types/publication/publication-list-element.component'; +import { ListableObjectDirective } from './listable-object.directive'; +import { spyOnExported } from '../../../testing/utils'; + +const testType = 'TestType'; +const testContext = Context.Search; +const testViewMode = ViewMode.StandalonePage; + +class TestType implements ListableObject { + getRenderTypes(): Array> { + return [testType]; + } +} + +describe('ListableObjectComponentLoaderComponent', () => { + let comp: ListableObjectComponentLoaderComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [], + declarations: [ListableObjectComponentLoaderComponent, PublicationListElementComponent, ListableObjectDirective], + schemas: [NO_ERRORS_SCHEMA], + providers: [ComponentFactoryResolver] + }).overrideComponent(ListableObjectComponentLoaderComponent, { + set: { + changeDetection: ChangeDetectionStrategy.Default, + entryComponents: [PublicationListElementComponent] + } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(ListableObjectComponentLoaderComponent); + comp = fixture.componentInstance; + + comp.object = new TestType(); + comp.viewMode = testViewMode; + comp.context = testContext; + spyOnExported(listableObjectDecorators, 'getListableObjectComponent').and.returnValue(PublicationListElementComponent); + fixture.detectChanges(); + + })); + + describe('When the component is rendered', () => { + it('should call the getListableObjectComponent function with the right types, view mode and context', () => { + expect(listableObjectDecorators.getListableObjectComponent).toHaveBeenCalledWith([testType], testViewMode, testContext); + }) + }); +}); diff --git a/src/app/shared/object-collection/shared/listable-object/listable-object-component-loader.component.ts b/src/app/shared/object-collection/shared/listable-object/listable-object-component-loader.component.ts new file mode 100644 index 0000000000..648298b0fe --- /dev/null +++ b/src/app/shared/object-collection/shared/listable-object/listable-object-component-loader.component.ts @@ -0,0 +1,74 @@ +import { Component, ComponentFactoryResolver, Input, OnInit, ViewChild } from '@angular/core'; +import { ListableObject } from '../listable-object.model'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; +import { Context } from '../../../../core/shared/context.model'; +import { getListableObjectComponent } from './listable-object.decorator'; +import { GenericConstructor } from '../../../../core/shared/generic-constructor'; +import { ListableObjectDirective } from './listable-object.directive'; +import { CollectionElementLinkType } from '../../collection-element-link.type'; + +@Component({ + selector: 'ds-listable-object-component-loader', + // styleUrls: ['./listable-object-component-loader.component.scss'], + templateUrl: './listable-object-component-loader.component.html' +}) +/** + * Component for determining what component to use depending on the item's relationship type (relationship.type) + */ +export class ListableObjectComponentLoaderComponent implements OnInit { + /** + * The item or metadata to determine the component for + */ + @Input() object: ListableObject; + + /** + * The index of the object in the list + */ + @Input() index: number; + + /** + * The preferred view-mode to display + */ + @Input() viewMode: ViewMode; + + /** + * The context of listable object + */ + @Input() context: Context; + + /** + * The type of link used to render the links inside the listable object + */ + @Input() linkType: CollectionElementLinkType; + + /** + * Directive hook used to place the dynamic child component + */ + @ViewChild(ListableObjectDirective) listableObjectDirective: ListableObjectDirective; + + constructor(private componentFactoryResolver: ComponentFactoryResolver) { + } + + /** + * Setup the dynamic child component + */ + ngOnInit(): void { + const componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.getComponent()); + + const viewContainerRef = this.listableObjectDirective.viewContainerRef; + viewContainerRef.clear(); + + const componentRef = viewContainerRef.createComponent(componentFactory); + (componentRef.instance as any).object = this.object; + (componentRef.instance as any).index = this.index; + (componentRef.instance as any).linkType = this.linkType; + } + + /** + * Fetch the component depending on the item's relationship type, view mode and context + * @returns {GenericConstructor} + */ + private getComponent(): GenericConstructor { + return getListableObjectComponent(this.object.getRenderTypes(), this.viewMode, this.context) + } +} diff --git a/src/app/shared/object-collection/shared/listable-object/listable-object.decorator.spec.ts b/src/app/shared/object-collection/shared/listable-object/listable-object.decorator.spec.ts new file mode 100644 index 0000000000..0143984bd6 --- /dev/null +++ b/src/app/shared/object-collection/shared/listable-object/listable-object.decorator.spec.ts @@ -0,0 +1,71 @@ +import { Item } from '../../../../core/shared/item.model'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; +import { getListableObjectComponent, listableObjectComponent } from './listable-object.decorator'; +import { Context } from '../../../../core/shared/context.model'; + +describe('ListableObject decorator function', () => { + const type1 = 'TestType'; + const type2 = 'TestType2'; + const type3 = 'TestType3'; + + /* tslint:disable:max-classes-per-file */ + class Test1List {}; + class Test1Grid {}; + class Test2List {}; + class Test2ListSubmission {}; + class Test3List {}; + class Test3DetailedSubmission {}; + /* tslint:enable:max-classes-per-file */ + + beforeEach(() => { + listableObjectComponent(type1, ViewMode.ListElement)(Test1List); + listableObjectComponent(type1, ViewMode.GridElement)(Test1Grid); + + listableObjectComponent(type2, ViewMode.ListElement)(Test2List); + listableObjectComponent(type2, ViewMode.ListElement, Context.Workspace)(Test2ListSubmission); + + listableObjectComponent(type3, ViewMode.ListElement)(Test3List); + listableObjectComponent(type3, ViewMode.DetailedListElement, Context.Workspace)(Test3DetailedSubmission); + }); + + const gridDecorator = listableObjectComponent('Item', ViewMode.GridElement); + const listDecorator = listableObjectComponent('Item', ViewMode.ListElement); + it('should have a decorator for both list and grid', () => { + expect(listDecorator.length).not.toBeNull(); + expect(gridDecorator.length).not.toBeNull(); + }); + it('should have 2 separate decorators for grid and list', () => { + expect(listDecorator).not.toEqual(gridDecorator); + }); + + describe('If there\'s an exact match', () => { + it('should return the matching class', () => { + const component = getListableObjectComponent([type3], ViewMode.DetailedListElement, Context.Workspace); + expect(component).toEqual(Test3DetailedSubmission); + + const component2 = getListableObjectComponent([type3, type2], ViewMode.ListElement, Context.Workspace); + expect(component2).toEqual(Test2ListSubmission); + }); + }); + + describe('If there isn\'nt an exact match', () => { + describe('If there is a match for one of the entity types and the view mode', () => { + it('should return the class with the matching entity type and view mode and default context', () => { + const component = getListableObjectComponent([type3], ViewMode.ListElement, Context.Workspace); + expect(component).toEqual(Test3List); + + const component2 = getListableObjectComponent([type3, type1], ViewMode.GridElement, Context.Workspace); + expect(component2).toEqual(Test1Grid); + }); + }); + describe('If there isn\'t a match for the representation type', () => { + it('should return the class with the matching entity type and the default view mode and default context', () => { + const component = getListableObjectComponent([type1], ViewMode.DetailedListElement); + expect(component).toEqual(Test1List); + + const component2 = getListableObjectComponent([type2, type1], ViewMode.DetailedListElement); + expect(component2).toEqual(Test2List); + }); + }); + }); +}); diff --git a/src/app/shared/object-collection/shared/listable-object/listable-object.decorator.ts b/src/app/shared/object-collection/shared/listable-object/listable-object.decorator.ts new file mode 100644 index 0000000000..66110516bb --- /dev/null +++ b/src/app/shared/object-collection/shared/listable-object/listable-object.decorator.ts @@ -0,0 +1,62 @@ +import { ViewMode } from '../../../../core/shared/view-mode.model'; +import { Context } from '../../../../core/shared/context.model'; +import { hasNoValue, hasValue } from '../../../empty.util'; +import { DEFAULT_CONTEXT } from '../../../metadata-representation/metadata-representation.decorator'; +import { GenericConstructor } from '../../../../core/shared/generic-constructor'; +import { ListableObject } from '../listable-object.model'; + +export const DEFAULT_VIEW_MODE = ViewMode.ListElement; + +const map = new Map(); + +/** + * Decorator used for rendering a listable object + * @param type The object type or entity type the component represents + * @param viewMode The view mode the component represents + * @param context The optional context the component represents + */ +export function listableObjectComponent(objectType: string | GenericConstructor, viewMode: ViewMode, context: Context = DEFAULT_CONTEXT) { + return function decorator(component: any) { + if (hasNoValue(objectType)) { + return; + } + if (hasNoValue(map.get(objectType))) { + map.set(objectType, new Map()); + } + if (hasNoValue(map.get(objectType).get(viewMode))) { + map.get(objectType).set(viewMode, new Map()); + } + map.get(objectType).get(viewMode).set(context, component); + }; +} + +/** + * Getter to retrieve the matching listable object component + * @param types The types of which one should match the listable component + * @param viewMode The view mode that should match the components + * @param context The context that should match the components + */ +export function getListableObjectComponent(types: Array>, viewMode: ViewMode, context: Context = DEFAULT_CONTEXT) { + let bestMatch; + let bestMatchValue = 0; + for (const type of types) { + const typeMap = map.get(type); + if (hasValue(typeMap)) { + const typeModeMap = typeMap.get(viewMode); + if (hasValue(typeModeMap)) { + if (hasValue(typeModeMap.get(context))) { + return typeModeMap.get(context); + } + if (bestMatchValue < 2 && hasValue(typeModeMap.get(DEFAULT_CONTEXT))) { + bestMatchValue = 2; + bestMatch = typeModeMap.get(DEFAULT_CONTEXT); + } + } + if (bestMatchValue < 1 && hasValue(typeMap.get(DEFAULT_VIEW_MODE).get(DEFAULT_CONTEXT))) { + bestMatchValue = 1; + bestMatch = typeMap.get(DEFAULT_VIEW_MODE).get(DEFAULT_CONTEXT); + } + } + } + return bestMatch; +} diff --git a/src/app/shared/object-collection/shared/listable-object/listable-object.directive.ts b/src/app/shared/object-collection/shared/listable-object/listable-object.directive.ts new file mode 100644 index 0000000000..93c06961f4 --- /dev/null +++ b/src/app/shared/object-collection/shared/listable-object/listable-object.directive.ts @@ -0,0 +1,11 @@ +import { Directive, ViewContainerRef } from '@angular/core'; + +@Directive({ + selector: '[dsListableObject]', +}) +/** + * Directive used as a hook to know where to inject the dynamic listable object component + */ +export class ListableObjectDirective { + constructor(public viewContainerRef: ViewContainerRef) { } +} diff --git a/src/app/shared/object-collection/shared/object-collection-element/abstract-listable-element.component.ts b/src/app/shared/object-collection/shared/object-collection-element/abstract-listable-element.component.ts index d52036b5dc..c09f7df18c 100644 --- a/src/app/shared/object-collection/shared/object-collection-element/abstract-listable-element.component.ts +++ b/src/app/shared/object-collection/shared/object-collection-element/abstract-listable-element.component.ts @@ -1,13 +1,24 @@ -import { Component, Inject } from '@angular/core'; +import { Component, Input } from '@angular/core'; import { ListableObject } from '../listable-object.model'; +import { CollectionElementLinkType } from '../../collection-element-link.type'; @Component({ selector: 'ds-abstract-object-element', template: ``, }) -export class AbstractListableElementComponent { - object: T; - public constructor(@Inject('objectElementProvider') public listableObject: ListableObject) { - this.object = listableObject as T; - } +export class AbstractListableElementComponent { + /** + * The object to render in this list element + */ + @Input() object: T; + + /** + * The link type to determine the type of link rendered in this element + */ + @Input() linkType: CollectionElementLinkType; + + /** + * The available link types + */ + linkTypes = CollectionElementLinkType; } diff --git a/src/app/shared/object-collection/shared/pool-task-my-dspace-result.model.ts b/src/app/shared/object-collection/shared/pool-task-search-result.model.ts similarity index 56% rename from src/app/shared/object-collection/shared/pool-task-my-dspace-result.model.ts rename to src/app/shared/object-collection/shared/pool-task-search-result.model.ts index 1bc2c4c4c2..0af55d31a4 100644 --- a/src/app/shared/object-collection/shared/pool-task-my-dspace-result.model.ts +++ b/src/app/shared/object-collection/shared/pool-task-search-result.model.ts @@ -1,11 +1,10 @@ import { PoolTask } from '../../../core/tasks/models/pool-task-object.model'; import { SearchResult } from '../../../+search-page/search-result.model'; -import { MyDSpaceConfigurationValueType } from '../../../+my-dspace-page/my-dspace-configuration-value-type'; import { searchResultFor } from '../../../+search-page/search-service/search-result-element-decorator'; /** * Represents a search result object of a PoolTask object */ -@searchResultFor(PoolTask, MyDSpaceConfigurationValueType.Workflow) -export class PoolTaskMyDSpaceResult extends SearchResult { +@searchResultFor(PoolTask) +export class PoolTaskSearchResult extends SearchResult { } diff --git a/src/app/shared/object-collection/shared/workflowitem-my-dspace-result.model.ts b/src/app/shared/object-collection/shared/workflow-item-search-result.model.ts similarity index 56% rename from src/app/shared/object-collection/shared/workflowitem-my-dspace-result.model.ts rename to src/app/shared/object-collection/shared/workflow-item-search-result.model.ts index d91c03b549..5684976e25 100644 --- a/src/app/shared/object-collection/shared/workflowitem-my-dspace-result.model.ts +++ b/src/app/shared/object-collection/shared/workflow-item-search-result.model.ts @@ -1,11 +1,10 @@ import { WorkflowItem } from '../../../core/submission/models/workflowitem.model'; import { SearchResult } from '../../../+search-page/search-result.model'; -import { MyDSpaceConfigurationValueType } from '../../../+my-dspace-page/my-dspace-configuration-value-type'; import { searchResultFor } from '../../../+search-page/search-service/search-result-element-decorator'; /** * Represents a search result object of a WorkflowItem object */ -@searchResultFor(WorkflowItem, MyDSpaceConfigurationValueType.Workspace) -export class WorkflowitemMyDSpaceResult extends SearchResult { +@searchResultFor(WorkflowItem) +export class WorkflowItemSearchResult extends SearchResult { } diff --git a/src/app/shared/object-collection/shared/workspaceitem-my-dspace-result.model.ts b/src/app/shared/object-collection/shared/workspace-item-search-result.model.ts similarity index 56% rename from src/app/shared/object-collection/shared/workspaceitem-my-dspace-result.model.ts rename to src/app/shared/object-collection/shared/workspace-item-search-result.model.ts index b7bd5e31d6..12fde0f8f1 100644 --- a/src/app/shared/object-collection/shared/workspaceitem-my-dspace-result.model.ts +++ b/src/app/shared/object-collection/shared/workspace-item-search-result.model.ts @@ -1,11 +1,10 @@ import { WorkspaceItem } from '../../../core/submission/models/workspaceitem.model'; -import { MyDSpaceConfigurationValueType } from '../../../+my-dspace-page/my-dspace-configuration-value-type'; import { searchResultFor } from '../../../+search-page/search-service/search-result-element-decorator'; import { SearchResult } from '../../../+search-page/search-result.model'; /** * Represents a search result object of a WorkspaceItem object */ -@searchResultFor(WorkspaceItem, MyDSpaceConfigurationValueType.Workspace) -export class WorkspaceitemMyDSpaceResult extends SearchResult { +@searchResultFor(WorkspaceItem) +export class WorkspaceItemSearchResult extends SearchResult { } diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component.html b/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component.html similarity index 100% rename from src/app/shared/object-detail/my-dspace-result-detail-element/claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component.html rename to src/app/shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component.html diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component.spec.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component.spec.ts similarity index 68% rename from src/app/shared/object-detail/my-dspace-result-detail-element/claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component.spec.ts rename to src/app/shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component.spec.ts index f57eb6420e..074ce56f92 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component.spec.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component.spec.ts @@ -5,24 +5,23 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { of as observableOf } from 'rxjs'; import { Item } from '../../../../core/shared/item.model'; -import { ClaimedMyDSpaceResultDetailElementComponent } from './claimed-my-dspace-result-detail-element.component'; -import { ClaimedTaskMyDSpaceResult } from '../../../object-collection/shared/claimed-task-my-dspace-result.model'; +import { ClaimedTaskSearchResultDetailElementComponent } from './claimed-task-search-result-detail-element.component'; import { ClaimedTask } from '../../../../core/tasks/models/claimed-task-object.model'; -import { RemoteData } from '../../../../core/data/remote-data'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model'; import { createSuccessfulRemoteDataObject } from '../../../testing/utils'; +import { ClaimedTaskSearchResult } from '../../../object-collection/shared/claimed-task-search-result.model'; -let component: ClaimedMyDSpaceResultDetailElementComponent; -let fixture: ComponentFixture; +let component: ClaimedTaskSearchResultDetailElementComponent; +let fixture: ComponentFixture; const compIndex = 1; -const mockResultObject: ClaimedTaskMyDSpaceResult = new ClaimedTaskMyDSpaceResult(); +const mockResultObject: ClaimedTaskSearchResult = new ClaimedTaskSearchResult(); mockResultObject.hitHighlights = {}; const item = Object.assign(new Item(), { - bitstreams: observableOf({}), + bundles: observableOf({}), metadata: { 'dc.title': [ { @@ -55,23 +54,19 @@ const workflowitem = Object.assign(new WorkflowItem(), { item: observableOf(rdIt const rdWorkflowitem = createSuccessfulRemoteDataObject(workflowitem); mockResultObject.indexableObject = Object.assign(new ClaimedTask(), { workflowitem: observableOf(rdWorkflowitem) }); -describe('ClaimedMyDSpaceResultDetailElementComponent', () => { +describe('ClaimedTaskSearchResultDetailElementComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [NoopAnimationsModule], - declarations: [ClaimedMyDSpaceResultDetailElementComponent], - providers: [ - { provide: 'objectElementProvider', useValue: (mockResultObject) }, - { provide: 'indexElementProvider', useValue: (compIndex) } - ], + declarations: [ClaimedTaskSearchResultDetailElementComponent], schemas: [NO_ERRORS_SCHEMA] - }).overrideComponent(ClaimedMyDSpaceResultDetailElementComponent, { + }).overrideComponent(ClaimedTaskSearchResultDetailElementComponent, { set: { changeDetection: ChangeDetectionStrategy.Default } }).compileComponents(); })); beforeEach(async(() => { - fixture = TestBed.createComponent(ClaimedMyDSpaceResultDetailElementComponent); + fixture = TestBed.createComponent(ClaimedTaskSearchResultDetailElementComponent); component = fixture.componentInstance; })); diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component.ts similarity index 52% rename from src/app/shared/object-detail/my-dspace-result-detail-element/claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component.ts rename to src/app/shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component.ts index 581d52c05f..72ffca4b98 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-my-dspace-result/claimed-my-dspace-result-detail-element.component.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/claimed-task-search-result/claimed-task-search-result-detail-element.component.ts @@ -1,32 +1,29 @@ -import { Component, Inject } from '@angular/core'; +import { Component } from '@angular/core'; import { Observable } from 'rxjs'; import { find } from 'rxjs/operators'; -import { renderElementsFor } from '../../../object-collection/shared/dso-element-decorator'; import { RemoteData } from '../../../../core/data/remote-data'; import { ViewMode } from '../../../../core/shared/view-mode.model'; import { isNotUndefined } from '../../../empty.util'; -import { ListableObject } from '../../../object-collection/shared/listable-object.model'; import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model'; import { ClaimedTask } from '../../../../core/tasks/models/claimed-task-object.model'; -import { ClaimedTaskMyDSpaceResult } from '../../../object-collection/shared/claimed-task-my-dspace-result.model'; -import { MyDSpaceResultDetailElementComponent } from '../my-dspace-result-detail-element.component'; +import { SearchResultDetailElementComponent } from '../search-result-detail-element.component'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; -import { SetViewMode } from '../../../view-mode'; +import { listableObjectComponent } from '../../../object-collection/shared/listable-object/listable-object.decorator'; +import { ClaimedTaskSearchResult } from '../../../object-collection/shared/claimed-task-search-result.model'; /** - * This component renders claimed task object for the mydspace result in the detail view. + * This component renders claimed task object for the search result in the detail view. */ @Component({ - selector: 'ds-claimed-my-dspace-result-detail-element', - styleUrls: ['../my-dspace-result-detail-element.component.scss'], - templateUrl: './claimed-my-dspace-result-detail-element.component.html' + selector: 'ds-claimed-task-search-result-detail-element', + styleUrls: ['../search-result-detail-element.component.scss'], + templateUrl: './claimed-task-search-result-detail-element.component.html' }) -@renderElementsFor(ClaimedTaskMyDSpaceResult, SetViewMode.Detail) -@renderElementsFor(ClaimedTask, SetViewMode.Detail) -export class ClaimedMyDSpaceResultDetailElementComponent extends MyDSpaceResultDetailElementComponent { +@listableObjectComponent(ClaimedTaskSearchResult, ViewMode.DetailedListElement) +export class ClaimedTaskSearchResultDetailElementComponent extends SearchResultDetailElementComponent { /** * A boolean representing if to show submitter information @@ -43,19 +40,16 @@ export class ClaimedMyDSpaceResultDetailElementComponent extends MyDSpaceResultD */ public workflowitem: WorkflowItem; - constructor(@Inject('objectElementProvider') public listable: ListableObject) { - super(listable); - } - /** * Initialize all instance variables */ ngOnInit() { + super.ngOnInit(); this.initWorkflowItem(this.dso.workflowitem as Observable>); } /** - * Retrieve workflowitem from result object + * Retrieve workflow item from result object */ initWorkflowItem(wfi$: Observable>) { wfi$.pipe( diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/item-detail-preview-field.component.spec.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/item-detail-preview-field.component.spec.ts index ff5224a1a2..a81cef5a7d 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/item-detail-preview-field.component.spec.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/item-detail-preview-field.component.spec.ts @@ -15,7 +15,7 @@ let component: ItemDetailPreviewFieldComponent; let fixture: ComponentFixture; const mockItemWithAuthorAndDate: Item = Object.assign(new Item(), { - bitstreams: observableOf({}), + bundles: observableOf({}), metadata: { 'dc.contributor.author': [ { diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/item-detail-preview-field.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/item-detail-preview-field.component.ts index b53d0a6b2d..2456913080 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/item-detail-preview-field.component.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview-field/item-detail-preview-field.component.ts @@ -1,8 +1,8 @@ import { Component, Input } from '@angular/core'; import { Metadata } from '../../../../../core/shared/metadata.utils'; -import { MyDSpaceResult } from '../../../../../+my-dspace-page/my-dspace-result.model'; import { Item } from '../../../../../core/shared/item.model'; +import { SearchResult } from '../../../../../+search-page/search-result.model'; /** * This component show values for the given item metadata @@ -19,9 +19,9 @@ export class ItemDetailPreviewFieldComponent { @Input() item: Item; /** - * The mydspace result object + * The search result object */ - @Input() object: MyDSpaceResult; + @Input() object: SearchResult; /** * The metadata label diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.ts index fa15c71168..0e808321ae 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component.ts @@ -7,7 +7,7 @@ import { Item } from '../../../../core/shared/item.model'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; import { fadeInOut } from '../../../animations/fade'; import { Bitstream } from '../../../../core/shared/bitstream.model'; -import { MyDSpaceResult } from '../../../../+my-dspace-page/my-dspace-result.model'; +import { SearchResult } from '../../../../+search-page/search-result.model'; import { FileService } from '../../../../core/shared/file.service'; import { HALEndpointService } from '../../../../core/shared/hal-endpoint.service'; @@ -28,9 +28,9 @@ export class ItemDetailPreviewComponent { @Input() item: Item; /** - * The mydspace result object + * The search result object */ - @Input() object: MyDSpaceResult; + @Input() object: SearchResult; /** * Represent item's status diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/item-my-dspace-result/item-my-dspace-result-detail-element.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/item-my-dspace-result/item-my-dspace-result-detail-element.component.ts deleted file mode 100644 index 26f63deb83..0000000000 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/item-my-dspace-result/item-my-dspace-result-detail-element.component.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Component } from '@angular/core'; - -import { renderElementsFor } from '../../../object-collection/shared/dso-element-decorator'; -import { ViewMode } from '../../../../core/shared/view-mode.model'; -import { Item } from '../../../../core/shared/item.model'; -import { ItemMyDSpaceResult } from '../../../object-collection/shared/item-my-dspace-result.model'; -import { MyDSpaceResultDetailElementComponent } from '../my-dspace-result-detail-element.component'; -import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; -import { SetViewMode } from '../../../view-mode'; - -/** - * This component renders item object for the mydspace result in the detail view. - */ -@Component({ - selector: 'ds-workspaceitem-my-dspace-result-detail-element', - styleUrls: ['../my-dspace-result-detail-element.component.scss', './item-my-dspace-result-detail-element.component.scss'], - templateUrl: './item-my-dspace-result-detail-element.component.html' -}) - -@renderElementsFor(ItemMyDSpaceResult, SetViewMode.Detail) -export class ItemMyDSpaceResultDetailElementComponent extends MyDSpaceResultDetailElementComponent { - - /** - * Represent item's status - */ - public status = MyDspaceItemStatusType.ARCHIVED; - -} diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/item-my-dspace-result/item-my-dspace-result-detail-element.component.html b/src/app/shared/object-detail/my-dspace-result-detail-element/item-search-result/item-search-result-detail-element.component.html similarity index 100% rename from src/app/shared/object-detail/my-dspace-result-detail-element/item-my-dspace-result/item-my-dspace-result-detail-element.component.html rename to src/app/shared/object-detail/my-dspace-result-detail-element/item-search-result/item-search-result-detail-element.component.html diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/item-my-dspace-result/item-my-dspace-result-detail-element.component.scss b/src/app/shared/object-detail/my-dspace-result-detail-element/item-search-result/item-search-result-detail-element.component.scss similarity index 100% rename from src/app/shared/object-detail/my-dspace-result-detail-element/item-my-dspace-result/item-my-dspace-result-detail-element.component.scss rename to src/app/shared/object-detail/my-dspace-result-detail-element/item-search-result/item-search-result-detail-element.component.scss diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/item-my-dspace-result/item-my-dspace-result-detail-element.component.spec.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/item-search-result/item-search-result-detail-element.component.spec.ts similarity index 63% rename from src/app/shared/object-detail/my-dspace-result-detail-element/item-my-dspace-result/item-my-dspace-result-detail-element.component.spec.ts rename to src/app/shared/object-detail/my-dspace-result-detail-element/item-search-result/item-search-result-detail-element.component.spec.ts index c99f44cbae..b0db04f1da 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/item-my-dspace-result/item-my-dspace-result-detail-element.component.spec.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/item-search-result/item-search-result-detail-element.component.spec.ts @@ -5,20 +5,20 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { of as observableOf } from 'rxjs'; import { Item } from '../../../../core/shared/item.model'; -import { ItemMyDSpaceResultDetailElementComponent } from './item-my-dspace-result-detail-element.component'; +import { ItemSearchResultDetailElementComponent } from './item-search-result-detail-element.component'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; -import { ItemMyDSpaceResult } from '../../../object-collection/shared/item-my-dspace-result.model'; +import { ItemSearchResult } from '../../../object-collection/shared/item-search-result.model'; -let component: ItemMyDSpaceResultDetailElementComponent; -let fixture: ComponentFixture; +let component: ItemSearchResultDetailElementComponent; +let fixture: ComponentFixture; const compIndex = 1; -const mockResultObject: ItemMyDSpaceResult = new ItemMyDSpaceResult(); +const mockResultObject: ItemSearchResult = new ItemSearchResult(); mockResultObject.hitHighlights = {}; mockResultObject.indexableObject = Object.assign(new Item(), { - bitstreams: observableOf({}), + bundles: observableOf({}), metadata: { 'dc.title': [ { @@ -47,23 +47,19 @@ mockResultObject.indexableObject = Object.assign(new Item(), { } }); -describe('ItemMyDSpaceResultDetailElementComponent', () => { +describe('ItemSearchResultDetailElementComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [NoopAnimationsModule], - declarations: [ItemMyDSpaceResultDetailElementComponent], - providers: [ - { provide: 'objectElementProvider', useValue: (mockResultObject) }, - { provide: 'indexElementProvider', useValue: (compIndex) } - ], + declarations: [ItemSearchResultDetailElementComponent], schemas: [NO_ERRORS_SCHEMA] - }).overrideComponent(ItemMyDSpaceResultDetailElementComponent, { + }).overrideComponent(ItemSearchResultDetailElementComponent, { set: { changeDetection: ChangeDetectionStrategy.Default } }).compileComponents(); })); beforeEach(async(() => { - fixture = TestBed.createComponent(ItemMyDSpaceResultDetailElementComponent); + fixture = TestBed.createComponent(ItemSearchResultDetailElementComponent); component = fixture.componentInstance; })); diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/item-search-result/item-search-result-detail-element.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/item-search-result/item-search-result-detail-element.component.ts new file mode 100644 index 0000000000..7e611ec3c8 --- /dev/null +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/item-search-result/item-search-result-detail-element.component.ts @@ -0,0 +1,27 @@ +import { Component } from '@angular/core'; + +import { ViewMode } from '../../../../core/shared/view-mode.model'; +import { Item } from '../../../../core/shared/item.model'; +import { SearchResultDetailElementComponent } from '../search-result-detail-element.component'; +import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; +import { listableObjectComponent } from '../../../object-collection/shared/listable-object/listable-object.decorator'; +import { ItemSearchResult } from '../../../object-collection/shared/item-search-result.model'; + +/** + * This component renders item object for the search result in the detail view. + */ +@Component({ + selector: 'ds-item-search-result-detail-element', + styleUrls: ['../search-result-detail-element.component.scss', './item-search-result-detail-element.component.scss'], + templateUrl: './item-search-result-detail-element.component.html' +}) + +@listableObjectComponent(Item, ViewMode.DetailedListElement) +export class ItemSearchResultDetailElementComponent extends SearchResultDetailElementComponent { + + /** + * Represent item's status + */ + public status = MyDspaceItemStatusType.ARCHIVED; + +} diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/pool-my-dspace-result/pool-my-dspace-result-detail-element.component.html b/src/app/shared/object-detail/my-dspace-result-detail-element/pool-search-result/pool-search-result-detail-element.component.html similarity index 100% rename from src/app/shared/object-detail/my-dspace-result-detail-element/pool-my-dspace-result/pool-my-dspace-result-detail-element.component.html rename to src/app/shared/object-detail/my-dspace-result-detail-element/pool-search-result/pool-search-result-detail-element.component.html diff --git a/src/app/shared/object-list/my-dspace-result-list-element/pool-my-dspace-result/pool-my-dspace-result-list-element.component.spec.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/pool-search-result/pool-search-result-detail-element.component.spec.ts similarity index 76% rename from src/app/shared/object-list/my-dspace-result-list-element/pool-my-dspace-result/pool-my-dspace-result-list-element.component.spec.ts rename to src/app/shared/object-detail/my-dspace-result-detail-element/pool-search-result/pool-search-result-detail-element.component.spec.ts index 22804a3a30..f6e48cd2a5 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/pool-my-dspace-result/pool-my-dspace-result-list-element.component.spec.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/pool-search-result/pool-search-result-detail-element.component.spec.ts @@ -5,24 +5,23 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { of as observableOf } from 'rxjs'; import { Item } from '../../../../core/shared/item.model'; -import { PoolMyDSpaceResultListElementComponent } from './pool-my-dspace-result-list-element.component'; -import { PoolTaskMyDSpaceResult } from '../../../object-collection/shared/pool-task-my-dspace-result.model'; import { PoolTask } from '../../../../core/tasks/models/pool-task-object.model'; -import { RemoteData } from '../../../../core/data/remote-data'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model'; import { createSuccessfulRemoteDataObject } from '../../../testing/utils'; +import { PoolSearchResultDetailElementComponent } from './pool-search-result-detail-element.component'; +import { PoolTaskSearchResult } from '../../../object-collection/shared/pool-task-search-result.model'; -let component: PoolMyDSpaceResultListElementComponent; -let fixture: ComponentFixture; +let component: PoolSearchResultDetailElementComponent; +let fixture: ComponentFixture; const compIndex = 1; -const mockResultObject: PoolTaskMyDSpaceResult = new PoolTaskMyDSpaceResult(); +const mockResultObject: PoolTaskSearchResult = new PoolTaskSearchResult(); mockResultObject.hitHighlights = {}; const item = Object.assign(new Item(), { - bitstreams: observableOf({}), + bundles: observableOf({}), metadata: { 'dc.title': [ { @@ -55,23 +54,23 @@ const workflowitem = Object.assign(new WorkflowItem(), { item: observableOf(rdIt const rdWorkflowitem = createSuccessfulRemoteDataObject(workflowitem); mockResultObject.indexableObject = Object.assign(new PoolTask(), { workflowitem: observableOf(rdWorkflowitem) }); -describe('PoolMyDSpaceResultListElementComponent', () => { +describe('PoolSearchResultDetailElementComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [NoopAnimationsModule], - declarations: [PoolMyDSpaceResultListElementComponent], + declarations: [PoolSearchResultDetailElementComponent], providers: [ { provide: 'objectElementProvider', useValue: (mockResultObject) }, { provide: 'indexElementProvider', useValue: (compIndex) } ], schemas: [NO_ERRORS_SCHEMA] - }).overrideComponent(PoolMyDSpaceResultListElementComponent, { + }).overrideComponent(PoolSearchResultDetailElementComponent, { set: { changeDetection: ChangeDetectionStrategy.Default } }).compileComponents(); })); beforeEach(async(() => { - fixture = TestBed.createComponent(PoolMyDSpaceResultListElementComponent); + fixture = TestBed.createComponent(PoolSearchResultDetailElementComponent); component = fixture.componentInstance; })); diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/pool-my-dspace-result/pool-my-dspace-result-detail-lement.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/pool-search-result/pool-search-result-detail-element.component.ts similarity index 54% rename from src/app/shared/object-detail/my-dspace-result-detail-element/pool-my-dspace-result/pool-my-dspace-result-detail-lement.component.ts rename to src/app/shared/object-detail/my-dspace-result-detail-element/pool-search-result/pool-search-result-detail-element.component.ts index 0b5b6c6524..95de372713 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/pool-my-dspace-result/pool-my-dspace-result-detail-lement.component.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/pool-search-result/pool-search-result-detail-element.component.ts @@ -1,30 +1,28 @@ -import { Component, Inject } from '@angular/core'; +import { Component } from '@angular/core'; import { Observable } from 'rxjs'; import { find } from 'rxjs/operators'; -import { renderElementsFor } from '../../../object-collection/shared/dso-element-decorator'; import { RemoteData } from '../../../../core/data/remote-data'; import { isNotUndefined } from '../../../empty.util'; -import { ListableObject } from '../../../object-collection/shared/listable-object.model'; import { PoolTask } from '../../../../core/tasks/models/pool-task-object.model'; -import { PoolTaskMyDSpaceResult } from '../../../object-collection/shared/pool-task-my-dspace-result.model'; -import { MyDSpaceResultDetailElementComponent } from '../my-dspace-result-detail-element.component'; +import { SearchResultDetailElementComponent } from '../search-result-detail-element.component'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; -import { SetViewMode } from '../../../view-mode'; import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; +import { listableObjectComponent } from '../../../object-collection/shared/listable-object/listable-object.decorator'; +import { PoolTaskSearchResult } from '../../../object-collection/shared/pool-task-search-result.model'; /** - * This component renders pool task object for the mydspace result in the detail view. + * This component renders pool task object for the search result in the detail view. */ @Component({ - selector: 'ds-pool-my-dspace-result-detail-element', - styleUrls: ['../my-dspace-result-detail-element.component.scss'], - templateUrl: './pool-my-dspace-result-detail-element.component.html', + selector: 'ds-pool-search-result-detail-element', + styleUrls: ['../search-result-detail-element.component.scss'], + templateUrl: './pool-search-result-detail-element.component.html', }) -@renderElementsFor(PoolTaskMyDSpaceResult, SetViewMode.Detail) -@renderElementsFor(PoolTask, SetViewMode.Detail) -export class PoolMyDSpaceResultDetailElementComponent extends MyDSpaceResultDetailElementComponent { +@listableObjectComponent(PoolTaskSearchResult, ViewMode.DetailedListElement) +export class PoolSearchResultDetailElementComponent extends SearchResultDetailElementComponent { /** * A boolean representing if to show submitter information @@ -41,14 +39,11 @@ export class PoolMyDSpaceResultDetailElementComponent extends MyDSpaceResultDeta */ public workflowitem: WorkflowItem; - constructor(@Inject('objectElementProvider') public listable: ListableObject) { - super(listable); - } - /** * Initialize all instance variables */ ngOnInit() { + super.ngOnInit(); this.initWorkflowItem(this.dso.workflowitem as Observable>); } diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/my-dspace-result-detail-element.component.scss b/src/app/shared/object-detail/my-dspace-result-detail-element/search-result-detail-element.component.scss similarity index 100% rename from src/app/shared/object-detail/my-dspace-result-detail-element/my-dspace-result-detail-element.component.scss rename to src/app/shared/object-detail/my-dspace-result-detail-element/search-result-detail-element.component.scss diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/my-dspace-result-detail-element.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/search-result-detail-element.component.ts similarity index 68% rename from src/app/shared/object-detail/my-dspace-result-detail-element/my-dspace-result-detail-element.component.ts rename to src/app/shared/object-detail/my-dspace-result-detail-element/search-result-detail-element.component.ts index 47a44d3132..f1e9fe698c 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/my-dspace-result-detail-element.component.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/search-result-detail-element.component.ts @@ -1,16 +1,19 @@ -import { Component, Inject } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; -import { MyDSpaceResult } from '../../../+my-dspace-page/my-dspace-result.model'; import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component'; -import { ListableObject } from '../../object-collection/shared/listable-object.model'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { Metadata } from '../../../core/shared/metadata.utils'; +import { SearchResult } from '../../../+search-page/search-result.model'; +import { hasValue } from '../../empty.util'; +/** + * Component representing Search Results with ViewMode.DetailedElement + */ @Component({ - selector: 'ds-my-dspace-result-detail-element', + selector: 'ds-search-result-detail-element', template: `` }) -export class MyDSpaceResultDetailElementComponent, K extends DSpaceObject> extends AbstractListableElementComponent { +export class SearchResultDetailElementComponent, K extends DSpaceObject> extends AbstractListableElementComponent implements OnInit { /** * The result element object @@ -19,12 +22,11 @@ export class MyDSpaceResultDetailElementComponent, K /** * Initialize instance variables - * - * @param {ListableObject} detailable */ - public constructor(@Inject('objectElementProvider') public detailable: ListableObject) { - super(detailable); - this.dso = this.object.indexableObject; + ngOnInit(): void { + if (hasValue(this.object)) { + this.dso = this.object.indexableObject; + } } /** diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-detail-element.component.html b/src/app/shared/object-detail/my-dspace-result-detail-element/workflow-item-search-result/workflow-item-search-result-detail-element.component.html similarity index 100% rename from src/app/shared/object-detail/my-dspace-result-detail-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-detail-element.component.html rename to src/app/shared/object-detail/my-dspace-result-detail-element/workflow-item-search-result/workflow-item-search-result-detail-element.component.html diff --git a/src/app/shared/object-list/my-dspace-result-list-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-list-element.component.spec.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/workflow-item-search-result/workflow-item-search-result-detail-element.component.spec.ts similarity index 72% rename from src/app/shared/object-list/my-dspace-result-list-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-list-element.component.spec.ts rename to src/app/shared/object-detail/my-dspace-result-detail-element/workflow-item-search-result/workflow-item-search-result-detail-element.component.spec.ts index ab472b4014..4094e076f7 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-list-element.component.spec.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/workflow-item-search-result/workflow-item-search-result-detail-element.component.spec.ts @@ -5,23 +5,22 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { of as observableOf } from 'rxjs'; import { Item } from '../../../../core/shared/item.model'; -import { WorkflowitemMyDSpaceResultListElementComponent } from './workflowitem-my-dspace-result-list-element.component'; -import { WorkflowitemMyDSpaceResult } from '../../../object-collection/shared/workflowitem-my-dspace-result.model'; +import { WorkflowItemSearchResultDetailElementComponent } from './workflow-item-search-result-detail-element.component'; import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model'; -import { RemoteData } from '../../../../core/data/remote-data'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; import { createSuccessfulRemoteDataObject } from '../../../testing/utils'; +import { WorkflowItemSearchResult } from '../../../object-collection/shared/workflow-item-search-result.model'; -let component: WorkflowitemMyDSpaceResultListElementComponent; -let fixture: ComponentFixture; +let component: WorkflowItemSearchResultDetailElementComponent; +let fixture: ComponentFixture; const compIndex = 1; -const mockResultObject: WorkflowitemMyDSpaceResult = new WorkflowitemMyDSpaceResult(); +const mockResultObject: WorkflowItemSearchResult = new WorkflowItemSearchResult(); mockResultObject.hitHighlights = {}; const item = Object.assign(new Item(), { - bitstreams: observableOf({}), + bundles: observableOf({}), metadata: { 'dc.title': [ { @@ -52,23 +51,23 @@ const item = Object.assign(new Item(), { const rd = createSuccessfulRemoteDataObject(item); mockResultObject.indexableObject = Object.assign(new WorkflowItem(), { item: observableOf(rd) }); -describe('WorkflowitemMyDSpaceResultListElementComponent', () => { +describe('WorkflowItemSearchResultDetailElementComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [NoopAnimationsModule], - declarations: [WorkflowitemMyDSpaceResultListElementComponent], + declarations: [WorkflowItemSearchResultDetailElementComponent], providers: [ { provide: 'objectElementProvider', useValue: (mockResultObject) }, { provide: 'indexElementProvider', useValue: (compIndex) } ], schemas: [NO_ERRORS_SCHEMA] - }).overrideComponent(WorkflowitemMyDSpaceResultListElementComponent, { + }).overrideComponent(WorkflowItemSearchResultDetailElementComponent, { set: { changeDetection: ChangeDetectionStrategy.Default } }).compileComponents(); })); beforeEach(async(() => { - fixture = TestBed.createComponent(WorkflowitemMyDSpaceResultListElementComponent); + fixture = TestBed.createComponent(WorkflowItemSearchResultDetailElementComponent); component = fixture.componentInstance; })); diff --git a/src/app/shared/object-list/my-dspace-result-list-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-list-element.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/workflow-item-search-result/workflow-item-search-result-detail-element.component.ts similarity index 54% rename from src/app/shared/object-list/my-dspace-result-list-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-list-element.component.ts rename to src/app/shared/object-detail/my-dspace-result-detail-element/workflow-item-search-result/workflow-item-search-result-detail-element.component.ts index b5d11b8b13..23a8ad9e18 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-list-element.component.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/workflow-item-search-result/workflow-item-search-result-detail-element.component.ts @@ -1,31 +1,28 @@ -import { Component } from '@angular/core'; +import { Component, Inject } from '@angular/core'; -import { Observable } from 'rxjs'; -import { find } from 'rxjs/operators'; - -import { renderElementsFor } from '../../../object-collection/shared/dso-element-decorator'; -import { MyDSpaceResultListElementComponent, } from '../my-dspace-result-list-element.component'; import { ViewMode } from '../../../../core/shared/view-mode.model'; -import { RemoteData } from '../../../../core/data/remote-data'; -import { isNotUndefined } from '../../../empty.util'; -import { WorkflowitemMyDSpaceResult } from '../../../object-collection/shared/workflowitem-my-dspace-result.model'; -import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model'; import { Item } from '../../../../core/shared/item.model'; +import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model'; +import { SearchResultDetailElementComponent } from '../search-result-detail-element.component'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; -import { SetViewMode } from '../../../view-mode'; +import { Observable } from 'rxjs/internal/Observable'; +import { RemoteData } from '../../../../core/data/remote-data'; +import { find } from 'rxjs/operators'; +import { isNotUndefined } from '../../../empty.util'; +import { listableObjectComponent } from '../../../object-collection/shared/listable-object/listable-object.decorator'; +import { WorkflowItemSearchResult } from '../../../object-collection/shared/workflow-item-search-result.model'; /** - * This component renders workflowitem object for the mydspace result in the list view. + * This component renders workflowitem object for the search result in the detail view. */ @Component({ - selector: 'ds-workflowitem-my-dspace-result-list-element', - styleUrls: ['../my-dspace-result-list-element.component.scss'], - templateUrl: './workflowitem-my-dspace-result-list-element.component.html', + selector: 'ds-workflow-item-search-result-detail-element', + styleUrls: ['../search-result-detail-element.component.scss'], + templateUrl: './workflow-item-search-result-detail-element.component.html', }) -@renderElementsFor(WorkflowitemMyDSpaceResult, SetViewMode.List) -@renderElementsFor(WorkflowItem, SetViewMode.List) -export class WorkflowitemMyDSpaceResultListElementComponent extends MyDSpaceResultListElementComponent { +@listableObjectComponent(WorkflowItemSearchResult, ViewMode.DetailedListElement) +export class WorkflowItemSearchResultDetailElementComponent extends SearchResultDetailElementComponent { /** * The item object that belonging to the result object @@ -41,6 +38,7 @@ export class WorkflowitemMyDSpaceResultListElementComponent extends MyDSpaceResu * Initialize all instance variables */ ngOnInit() { + super.ngOnInit(); this.initItem(this.dso.item as Observable>); } diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-detail-element.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-detail-element.component.ts deleted file mode 100644 index c28f044e6e..0000000000 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-detail-element.component.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { Component, Inject } from '@angular/core'; - -import { renderElementsFor } from '../../../object-collection/shared/dso-element-decorator'; -import { ViewMode } from '../../../../core/shared/view-mode.model'; -import { Item } from '../../../../core/shared/item.model'; -import { ListableObject } from '../../../object-collection/shared/listable-object.model'; -import { WorkflowitemMyDSpaceResult } from '../../../object-collection/shared/workflowitem-my-dspace-result.model'; -import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model'; -import { MyDSpaceResultDetailElementComponent } from '../my-dspace-result-detail-element.component'; -import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; -import { Observable } from 'rxjs/internal/Observable'; -import { RemoteData } from '../../../../core/data/remote-data'; -import { find } from 'rxjs/operators'; -import { isNotUndefined } from '../../../empty.util'; -import { SetViewMode } from '../../../view-mode'; - -/** - * This component renders workflowitem object for the mydspace result in the detail view. - */ -@Component({ - selector: 'ds-workflowitem-my-dspace-result-detail-element', - styleUrls: ['../my-dspace-result-detail-element.component.scss'], - templateUrl: './workflowitem-my-dspace-result-detail-element.component.html', -}) - -@renderElementsFor(WorkflowitemMyDSpaceResult, SetViewMode.Detail) -@renderElementsFor(WorkflowItem, SetViewMode.Detail) -export class WorkflowitemMyDSpaceResultDetailElementComponent extends MyDSpaceResultDetailElementComponent { - - /** - * The item object that belonging to the result object - */ - public item: Item; - - /** - * Represent item's status - */ - public status = MyDspaceItemStatusType.WORKFLOW; - - constructor(@Inject('objectElementProvider') public listable: ListableObject) { - super(listable); - } - - /** - * Initialize all instance variables - */ - ngOnInit() { - this.initItem(this.dso.item as Observable>); - } - - /** - * Retrieve item from result object - */ - initItem(item$: Observable>) { - item$.pipe( - find((rd: RemoteData) => rd.hasSucceeded && isNotUndefined(rd.payload)) - ).subscribe((rd: RemoteData) => { - this.item = rd.payload; - }); - } - -} diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component.html b/src/app/shared/object-detail/my-dspace-result-detail-element/workspace-item-search-result/workspace-item-search-result-detail-element.component.html similarity index 100% rename from src/app/shared/object-detail/my-dspace-result-detail-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component.html rename to src/app/shared/object-detail/my-dspace-result-detail-element/workspace-item-search-result/workspace-item-search-result-detail-element.component.html diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/workspace-item-search-result/workspace-item-search-result-detail-element.component.scss b/src/app/shared/object-detail/my-dspace-result-detail-element/workspace-item-search-result/workspace-item-search-result-detail-element.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/shared/object-list/my-dspace-result-list-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component.spec.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/workspace-item-search-result/workspace-item-search-result-detail-element.component.spec.ts similarity index 72% rename from src/app/shared/object-list/my-dspace-result-list-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component.spec.ts rename to src/app/shared/object-detail/my-dspace-result-detail-element/workspace-item-search-result/workspace-item-search-result-detail-element.component.spec.ts index a1c2472d27..ac772620b1 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component.spec.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/workspace-item-search-result/workspace-item-search-result-detail-element.component.spec.ts @@ -5,23 +5,22 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { of as observableOf } from 'rxjs'; import { Item } from '../../../../core/shared/item.model'; -import { WorkspaceitemMyDSpaceResultListElementComponent } from './workspaceitem-my-dspace-result-list-element.component'; -import { WorkspaceitemMyDSpaceResult } from '../../../object-collection/shared/workspaceitem-my-dspace-result.model'; +import { WorkspaceItemSearchResultDetailElementComponent } from './workspace-item-search-result-detail-element.component'; import { WorkspaceItem } from '../../../../core/submission/models/workspaceitem.model'; -import { RemoteData } from '../../../../core/data/remote-data'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; import { createSuccessfulRemoteDataObject } from '../../../testing/utils'; +import { WorkflowItemSearchResult } from '../../../object-collection/shared/workflow-item-search-result.model'; -let component: WorkspaceitemMyDSpaceResultListElementComponent; -let fixture: ComponentFixture; +let component: WorkspaceItemSearchResultDetailElementComponent; +let fixture: ComponentFixture; const compIndex = 1; -const mockResultObject: WorkspaceitemMyDSpaceResult = new WorkspaceitemMyDSpaceResult(); +const mockResultObject: WorkflowItemSearchResult = new WorkflowItemSearchResult(); mockResultObject.hitHighlights = {}; const item = Object.assign(new Item(), { - bitstreams: observableOf({}), + bundles: observableOf({}), metadata: { 'dc.title': [ { @@ -52,23 +51,23 @@ const item = Object.assign(new Item(), { const rd = createSuccessfulRemoteDataObject(item); mockResultObject.indexableObject = Object.assign(new WorkspaceItem(), { item: observableOf(rd) }); -describe('WorkspaceitemMyDSpaceResultListElementComponent', () => { +describe('WorkspaceItemSearchResultDetailElementComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [NoopAnimationsModule], - declarations: [WorkspaceitemMyDSpaceResultListElementComponent], + declarations: [WorkspaceItemSearchResultDetailElementComponent], providers: [ { provide: 'objectElementProvider', useValue: (mockResultObject) }, { provide: 'indexElementProvider', useValue: (compIndex) } ], schemas: [NO_ERRORS_SCHEMA] - }).overrideComponent(WorkspaceitemMyDSpaceResultListElementComponent, { + }).overrideComponent(WorkspaceItemSearchResultDetailElementComponent, { set: { changeDetection: ChangeDetectionStrategy.Default } }).compileComponents(); })); beforeEach(async(() => { - fixture = TestBed.createComponent(WorkspaceitemMyDSpaceResultListElementComponent); + fixture = TestBed.createComponent(WorkspaceItemSearchResultDetailElementComponent); component = fixture.componentInstance; })); diff --git a/src/app/shared/object-list/my-dspace-result-list-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/workspace-item-search-result/workspace-item-search-result-detail-element.component.ts similarity index 55% rename from src/app/shared/object-list/my-dspace-result-list-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component.ts rename to src/app/shared/object-detail/my-dspace-result-detail-element/workspace-item-search-result/workspace-item-search-result-detail-element.component.ts index 118965c64a..746fd02889 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component.ts +++ b/src/app/shared/object-detail/my-dspace-result-detail-element/workspace-item-search-result/workspace-item-search-result-detail-element.component.ts @@ -3,33 +3,32 @@ import { Component } from '@angular/core'; import { Observable } from 'rxjs'; import { find } from 'rxjs/operators'; -import { renderElementsFor } from '../../../object-collection/shared/dso-element-decorator'; -import { MyDSpaceResultListElementComponent, } from '../my-dspace-result-list-element.component'; -import { ViewMode } from '../../../../core/shared/view-mode.model'; import { WorkspaceItem } from '../../../../core/submission/models/workspaceitem.model'; -import { WorkspaceitemMyDSpaceResult } from '../../../object-collection/shared/workspaceitem-my-dspace-result.model'; +import { Item } from '../../../../core/shared/item.model'; import { RemoteData } from '../../../../core/data/remote-data'; import { isNotUndefined } from '../../../empty.util'; -import { Item } from '../../../../core/shared/item.model'; +import { SearchResultDetailElementComponent } from '../search-result-detail-element.component'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; -import { SetViewMode } from '../../../view-mode'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; +import { listableObjectComponent } from '../../../object-collection/shared/listable-object/listable-object.decorator'; +import { WorkspaceItemSearchResult } from '../../../object-collection/shared/workspace-item-search-result.model'; /** - * This component renders workspaceitem object for the mydspace result in the list view. + * This component renders workspace item object for the search result in the detail view. */ @Component({ - selector: 'ds-workspaceitem-my-dspace-result-list-element', - styleUrls: ['../my-dspace-result-list-element.component.scss', './workspaceitem-my-dspace-result-list-element.component.scss'], - templateUrl: './workspaceitem-my-dspace-result-list-element.component.html', + selector: 'ds-workspace-item-search-result-detail-element', + styleUrls: ['../search-result-detail-element.component.scss', './workspace-item-search-result-detail-element.component.scss'], + templateUrl: './workspace-item-search-result-detail-element.component.html', }) -@renderElementsFor(WorkspaceitemMyDSpaceResult, SetViewMode.List) -export class WorkspaceitemMyDSpaceResultListElementComponent extends MyDSpaceResultListElementComponent { +@listableObjectComponent(WorkspaceItemSearchResult, ViewMode.DetailedListElement) +export class WorkspaceItemSearchResultDetailElementComponent extends SearchResultDetailElementComponent { /** * The item object that belonging to the result object */ - item: Item; + public item: Item; /** * Represent item's status @@ -40,6 +39,7 @@ export class WorkspaceitemMyDSpaceResultListElementComponent extends MyDSpaceRes * Initialize all instance variables */ ngOnInit() { + super.ngOnInit(); this.initItem(this.dso.item as Observable>); } diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component.ts b/src/app/shared/object-detail/my-dspace-result-detail-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component.ts deleted file mode 100644 index af735ecb1e..0000000000 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { Component, Inject } from '@angular/core'; - -import { Observable } from 'rxjs'; -import { find } from 'rxjs/operators'; - -import { renderElementsFor } from '../../../object-collection/shared/dso-element-decorator'; -import { - WorkspaceItem -} from '../../../../core/submission/models/workspaceitem.model'; -import { WorkspaceitemMyDSpaceResult } from '../../../object-collection/shared/workspaceitem-my-dspace-result.model'; -import { Item } from '../../../../core/shared/item.model'; -import { RemoteData } from '../../../../core/data/remote-data'; -import { isNotUndefined } from '../../../empty.util'; -import { ListableObject } from '../../../object-collection/shared/listable-object.model'; -import { MyDSpaceResultDetailElementComponent } from '../my-dspace-result-detail-element.component'; -import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; -import { SetViewMode } from '../../../view-mode'; - -/** - * This component renders workspaceitem object for the mydspace result in the detail view. - */ -@Component({ - selector: 'ds-workspaceitem-my-dspace-result-detail-element', - styleUrls: ['../my-dspace-result-detail-element.component.scss', './workspaceitem-my-dspace-result-detail-element.component.scss'], - templateUrl: './workspaceitem-my-dspace-result-detail-element.component.html', -}) - -@renderElementsFor(WorkspaceitemMyDSpaceResult, SetViewMode.Detail) -@renderElementsFor(WorkspaceItem, SetViewMode.Detail) -export class WorkspaceitemMyDSpaceResultDetailElementComponent extends MyDSpaceResultDetailElementComponent { - - /** - * The item object that belonging to the result object - */ - public item: Item; - - /** - * Represent item's status - */ - status = MyDspaceItemStatusType.WORKSPACE; - - constructor(@Inject('objectElementProvider') public listable: ListableObject) { - super(listable); - } - - /** - * Initialize all instance variables - */ - ngOnInit() { - this.initItem(this.dso.item as Observable>); - } - - /** - * Retrieve item from result object - */ - initItem(item$: Observable>) { - item$.pipe( - find((rd: RemoteData) => rd.hasSucceeded && isNotUndefined(rd.payload)) - ).subscribe((rd: RemoteData) => { - this.item = rd.payload; - }); - } -} diff --git a/src/app/shared/object-detail/object-detail.component.html b/src/app/shared/object-detail/object-detail.component.html index a57a23027e..7fef7d9689 100644 --- a/src/app/shared/object-detail/object-detail.component.html +++ b/src/app/shared/object-detail/object-detail.component.html @@ -14,9 +14,9 @@
- +
- - + + diff --git a/src/app/shared/object-detail/object-detail.component.scss b/src/app/shared/object-detail/object-detail.component.scss index 9a077e3e08..e0a4e3abdc 100644 --- a/src/app/shared/object-detail/object-detail.component.scss +++ b/src/app/shared/object-detail/object-detail.component.scss @@ -1,9 +1,9 @@ @import '../../../styles/variables'; @import '../../../styles/mixins'; -ds-wrapper-detail-element ::ng-deep { +:host::ng-deep { div.thumbnail > img { height: $card-thumbnail-height; width: 100%; } -} +} \ No newline at end of file diff --git a/src/app/shared/object-detail/object-detail.component.spec.ts b/src/app/shared/object-detail/object-detail.component.spec.ts index 651e6a89a8..7bec565562 100644 --- a/src/app/shared/object-detail/object-detail.component.spec.ts +++ b/src/app/shared/object-detail/object-detail.component.spec.ts @@ -9,6 +9,7 @@ import { PaginatedList } from '../../core/data/paginated-list'; import { PageInfo } from '../../core/shared/page-info.model'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { createSuccessfulRemoteDataObject } from '../testing/utils'; +import { DSpaceObject } from '../../core/shared/dspace-object.model'; describe('ObjectDetailComponent', () => { let comp: ObjectDetailComponent; @@ -16,16 +17,16 @@ describe('ObjectDetailComponent', () => { const testEvent = {test: 'test'}; const testObjects = [ - { one: 1 }, - { two: 2 }, - { three: 3 }, - { four: 4 }, - { five: 5 }, - { six: 6 }, - { seven: 7 }, - { eight: 8 }, - { nine: 9 }, - { ten: 10 } + Object.assign (new DSpaceObject(), { one: 1 }), + Object.assign (new DSpaceObject(), { two: 2 }), + Object.assign (new DSpaceObject(), { three: 3 }), + Object.assign (new DSpaceObject(), { four: 4 }), + Object.assign (new DSpaceObject(), { five: 5 }), + Object.assign (new DSpaceObject(), { six: 6 }), + Object.assign (new DSpaceObject(), { seven: 7 }), + Object.assign (new DSpaceObject(), { eight: 8 }), + Object.assign (new DSpaceObject(), { nine: 9 }), + Object.assign (new DSpaceObject(), { ten: 10 }), ]; const pageInfo = Object.assign(new PageInfo(), {elementsPerPage: 1, totalElements: 10, totalPages: 10, currentPage: 1}) const mockRD = createSuccessfulRemoteDataObject(new PaginatedList(pageInfo, testObjects)); diff --git a/src/app/shared/object-detail/object-detail.component.ts b/src/app/shared/object-detail/object-detail.component.ts index 3187a2cd1b..fb68316251 100644 --- a/src/app/shared/object-detail/object-detail.component.ts +++ b/src/app/shared/object-detail/object-detail.component.ts @@ -15,6 +15,9 @@ import { fadeIn } from '../animations/fade'; import { ListableObject } from '../object-collection/shared/listable-object.model'; import { PaginationComponentOptions } from '../pagination/pagination-component-options.model'; +import { ViewMode } from '../../core/shared/view-mode.model'; +import { Context } from '../../core/shared/context.model'; +import { CollectionElementLinkType } from '../object-collection/collection-element-link.type'; /** * This component renders a paginated set of results in the detail view. @@ -28,6 +31,10 @@ import { PaginationComponentOptions } from '../pagination/pagination-component-o animations: [fadeIn] }) export class ObjectDetailComponent { + /** + * The view mode of this component + */ + viewMode = ViewMode.DetailedListElement; /** * Pagination options object @@ -49,6 +56,16 @@ export class ObjectDetailComponent { */ @Input() hidePagerWhenSinglePage = true; + /** + * The link type of the rendered listable elements + */ + @Input() linkType: CollectionElementLinkType; + + /** + * The context of the rendered listable elements + */ + @Input() context: Context; + /** * The list of objects to paginate */ diff --git a/src/app/shared/object-detail/wrapper-detail-element/wrapper-detail-element.component.html b/src/app/shared/object-detail/wrapper-detail-element/wrapper-detail-element.component.html deleted file mode 100644 index ef7254b97c..0000000000 --- a/src/app/shared/object-detail/wrapper-detail-element/wrapper-detail-element.component.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/app/shared/object-detail/wrapper-detail-element/wrapper-detail-element.component.scss b/src/app/shared/object-detail/wrapper-detail-element/wrapper-detail-element.component.scss deleted file mode 100644 index 51a7fc6a55..0000000000 --- a/src/app/shared/object-detail/wrapper-detail-element/wrapper-detail-element.component.scss +++ /dev/null @@ -1,2 +0,0 @@ -@import '../../../../styles/variables'; - diff --git a/src/app/shared/object-detail/wrapper-detail-element/wrapper-detail-element.component.spec.ts b/src/app/shared/object-detail/wrapper-detail-element/wrapper-detail-element.component.spec.ts deleted file mode 100644 index e54ae58398..0000000000 --- a/src/app/shared/object-detail/wrapper-detail-element/wrapper-detail-element.component.spec.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { By } from '@angular/platform-browser'; -import { ActivatedRoute, Router } from '@angular/router'; - -import { of as observableOf } from 'rxjs'; - -import { RouterStub } from '../../testing/router-stub'; -import { WrapperDetailElementComponent } from './wrapper-detail-element.component'; - -let wrapperDetailElementComponent: WrapperDetailElementComponent; -let fixture: ComponentFixture; -const queryParam = 'test query'; -const scopeParam = '7669c72a-3f2a-451f-a3b9-9210e7a4c02f'; -const activatedRouteStub = { - queryParams: observableOf({ - query: queryParam, - scope: scopeParam - }) -}; - -describe('WrapperDetailElementComponent', () => { - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ WrapperDetailElementComponent ], - providers: [ - { provide: ActivatedRoute, useValue: activatedRouteStub }, - { provide: Router, useClass: RouterStub }, - { provide: 'objectElementProvider', useFactory: (WrapperDetailElementComponent)} - ], - - schemas: [ NO_ERRORS_SCHEMA ] - }).compileComponents(); // compile template and css - })); - - beforeEach(async(() => { - fixture = TestBed.createComponent(WrapperDetailElementComponent); - wrapperDetailElementComponent = fixture.componentInstance; - })); - - it('should show the wrapper element containing the detail object',() => { - expect(fixture.debugElement.query(By.css('ds-workspaceitem-my-dspace-result-detail-element'))).toBeDefined(); - }) -}); diff --git a/src/app/shared/object-detail/wrapper-detail-element/wrapper-detail-element.component.ts b/src/app/shared/object-detail/wrapper-detail-element/wrapper-detail-element.component.ts deleted file mode 100644 index 2ca8069b16..0000000000 --- a/src/app/shared/object-detail/wrapper-detail-element/wrapper-detail-element.component.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { Component, Injector, Input, OnInit } from '@angular/core'; - -import { ViewMode } from '../../../core/shared/view-mode.model'; -import { GenericConstructor } from '../../../core/shared/generic-constructor'; -import { rendersDSOType } from '../../object-collection/shared/dso-element-decorator'; -import { ListableObject } from '../../object-collection/shared/listable-object.model'; -import { SetViewMode } from '../../view-mode'; - -/** - * This component renders a wrapper for an object in the detail view. - */ -@Component({ - selector: 'ds-wrapper-detail-element', - styleUrls: ['./wrapper-detail-element.component.scss'], - templateUrl: './wrapper-detail-element.component.html' -}) -export class WrapperDetailElementComponent implements OnInit { - - /** - * The listable object. - */ - @Input() object: ListableObject; - - /** - * The instance of the injector. - */ - objectInjector: Injector; - - detailElement: any; - - /** - * Initialize instance variables - * - * @param {Injector} injector - */ - constructor(private injector: Injector) { - } - - /** - * Initialize injector - */ - ngOnInit(): void { - this.objectInjector = Injector.create({ - providers: [{ provide: 'objectElementProvider', useFactory: () => (this.object), deps:[] }], - parent: this.injector - }); - this.detailElement = this.getDetailElement(); - } - - /** - * Return class name for the object to inject - */ - private getDetailElement(): string { - const f: GenericConstructor = this.object.constructor as GenericConstructor; - return rendersDSOType(f, SetViewMode.Detail); - } -} diff --git a/src/app/shared/object-grid/collection-grid-element/collection-grid-element.component.html b/src/app/shared/object-grid/collection-grid-element/collection-grid-element.component.html index 9fecb51b9a..0b1a85d0ef 100644 --- a/src/app/shared/object-grid/collection-grid-element/collection-grid-element.component.html +++ b/src/app/shared/object-grid/collection-grid-element/collection-grid-element.component.html @@ -1,14 +1,17 @@
- + + + + +

{{object.name}}

{{object.shortDescription}}

-
- View +
+ View
-
diff --git a/src/app/shared/object-grid/collection-grid-element/collection-grid-element.component.ts b/src/app/shared/object-grid/collection-grid-element/collection-grid-element.component.ts index af6027aa1a..6f8bf5264e 100644 --- a/src/app/shared/object-grid/collection-grid-element/collection-grid-element.component.ts +++ b/src/app/shared/object-grid/collection-grid-element/collection-grid-element.component.ts @@ -1,15 +1,18 @@ import { Component, Inject } from '@angular/core'; import { Collection } from '../../../core/shared/collection.model'; -import { renderElementsFor} from '../../object-collection/shared/dso-element-decorator'; -import { SetViewMode } from '../../view-mode'; import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component'; +import { ViewMode } from '../../../core/shared/view-mode.model'; +import { listableObjectComponent } from '../../object-collection/shared/listable-object/listable-object.decorator'; +/** + * Component representing a grid element for collection + */ @Component({ selector: 'ds-collection-grid-element', styleUrls: ['./collection-grid-element.component.scss'], templateUrl: './collection-grid-element.component.html' }) -@renderElementsFor(Collection, SetViewMode.Grid) +@listableObjectComponent(Collection, ViewMode.GridElement) export class CollectionGridElementComponent extends AbstractListableElementComponent {} diff --git a/src/app/shared/object-grid/community-grid-element/community-grid-element.component.html b/src/app/shared/object-grid/community-grid-element/community-grid-element.component.html index 31a9e8ad3d..eed29367fa 100644 --- a/src/app/shared/object-grid/community-grid-element/community-grid-element.component.html +++ b/src/app/shared/object-grid/community-grid-element/community-grid-element.component.html @@ -1,14 +1,17 @@
- - + + + + +

{{object.name}}

{{object.shortDescription}}

-
- View +
+ View
diff --git a/src/app/shared/object-grid/community-grid-element/community-grid-element.component.ts b/src/app/shared/object-grid/community-grid-element/community-grid-element.component.ts index 4f69e3e2c7..05c84b683b 100644 --- a/src/app/shared/object-grid/community-grid-element/community-grid-element.component.ts +++ b/src/app/shared/object-grid/community-grid-element/community-grid-element.component.ts @@ -1,15 +1,18 @@ -import { Component, Input, Inject } from '@angular/core'; +import { Component } from '@angular/core'; import { Community } from '../../../core/shared/community.model'; import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component'; -import { renderElementsFor} from '../../object-collection/shared/dso-element-decorator'; -import { SetViewMode } from '../../view-mode'; +import { ViewMode } from '../../../core/shared/view-mode.model'; +import { listableObjectComponent } from '../../object-collection/shared/listable-object/listable-object.decorator'; +/** + * Component representing a grid element for a community + */ @Component({ selector: 'ds-community-grid-element', styleUrls: ['./community-grid-element.component.scss'], templateUrl: './community-grid-element.component.html' }) -@renderElementsFor(Community, SetViewMode.Grid) +@listableObjectComponent(Community, ViewMode.GridElement) export class CommunityGridElementComponent extends AbstractListableElementComponent {} diff --git a/src/app/shared/object-grid/item-grid-element/item-grid-element.component.html b/src/app/shared/object-grid/item-grid-element/item-grid-element.component.html deleted file mode 100644 index 6bb2cfa99d..0000000000 --- a/src/app/shared/object-grid/item-grid-element/item-grid-element.component.html +++ /dev/null @@ -1,28 +0,0 @@ - -
- - - - -
-

{{object.firstMetadataValue('dc.title')}}

- - -

- {{author}} - ; - - {{object.firstMetadataValue("dc.date.issued")}} -

-
- - -

{{object.firstMetadataValue("dc.description.abstract")}}

-
- -
- View -
-
-
-
diff --git a/src/app/shared/object-grid/item-grid-element/item-grid-element.component.scss b/src/app/shared/object-grid/item-grid-element/item-grid-element.component.scss deleted file mode 100644 index 8b13789179..0000000000 --- a/src/app/shared/object-grid/item-grid-element/item-grid-element.component.scss +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/app/shared/object-grid/item-grid-element/item-grid-element.component.spec.ts b/src/app/shared/object-grid/item-grid-element/item-grid-element.component.spec.ts deleted file mode 100644 index bc6850d019..0000000000 --- a/src/app/shared/object-grid/item-grid-element/item-grid-element.component.spec.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { ItemGridElementComponent } from './item-grid-element.component'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; -import { By } from '@angular/platform-browser'; -import { TruncatePipe } from '../../utils/truncate.pipe'; -import { Item } from '../../../core/shared/item.model'; -import { of as observableOf } from 'rxjs'; - -let itemGridElementComponent: ItemGridElementComponent; -let fixture: ComponentFixture; - -const mockItemWithAuthorAndDate: Item = Object.assign(new Item(), { - bundles: observableOf({}), - metadata: { - 'dc.contributor.author': [ - { - language: 'en_US', - value: 'Smith, Donald' - } - ], - 'dc.date.issued': [ - { - language: null, - value: '2015-06-26' - } - ] - } -}); -const mockItemWithoutAuthorAndDate: Item = Object.assign(new Item(), { - bundles: observableOf({}), - metadata: { - 'dc.title': [ - { - language: 'en_US', - value: 'This is just another title' - } - ], - 'dc.type': [ - { - language: null, - value: 'Article' - } - ] - } -}); - -describe('ItemGridElementComponent', () => { - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ ItemGridElementComponent , TruncatePipe], - providers: [ - { provide: 'objectElementProvider', useValue: {mockItemWithAuthorAndDate}} - ], - - schemas: [ NO_ERRORS_SCHEMA ] - }).overrideComponent(ItemGridElementComponent, { - set: { changeDetection: ChangeDetectionStrategy.Default } - }).compileComponents(); - })); - - beforeEach(async(() => { - fixture = TestBed.createComponent(ItemGridElementComponent); - itemGridElementComponent = fixture.componentInstance; - - })); - - describe('When the item has an author', () => { - beforeEach(() => { - itemGridElementComponent.object = mockItemWithAuthorAndDate; - fixture.detectChanges(); - }); - - it('should show the author paragraph', () => { - const itemAuthorField = fixture.debugElement.query(By.css('p.item-authors')); - expect(itemAuthorField).not.toBeNull(); - }); - }); - - describe('When the item has no author', () => { - beforeEach(() => { - itemGridElementComponent.object = mockItemWithoutAuthorAndDate; - fixture.detectChanges(); - }); - - it('should not show the author paragraph', () => { - const itemAuthorField = fixture.debugElement.query(By.css('p.item-authors')); - expect(itemAuthorField).toBeNull(); - }); - }); - - describe('When the item has an issuedate', () => { - beforeEach(() => { - itemGridElementComponent.object = mockItemWithAuthorAndDate; - fixture.detectChanges(); - }); - - it('should show the issuedate span', () => { - const itemAuthorField = fixture.debugElement.query(By.css('span.item-date')); - expect(itemAuthorField).not.toBeNull(); - }); - }); - - describe('When the item has no issuedate', () => { - beforeEach(() => { - itemGridElementComponent.object = mockItemWithoutAuthorAndDate; - fixture.detectChanges(); - }); - - it('should not show the issuedate span', () => { - const dateField = fixture.debugElement.query(By.css('span.item-date')); - expect(dateField).toBeNull(); - }); - }); -}); diff --git a/src/app/shared/object-grid/item-grid-element/item-grid-element.component.ts b/src/app/shared/object-grid/item-grid-element/item-grid-element.component.ts deleted file mode 100644 index a4137b3c26..0000000000 --- a/src/app/shared/object-grid/item-grid-element/item-grid-element.component.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Component, Input, Inject } from '@angular/core'; - -import { Item } from '../../../core/shared/item.model'; -import { renderElementsFor} from '../../object-collection/shared/dso-element-decorator'; -import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component'; -import { SetViewMode } from '../../view-mode'; - -@Component({ - selector: 'ds-item-grid-element', - styleUrls: ['./item-grid-element.component.scss'], - templateUrl: './item-grid-element.component.html' -}) - -@renderElementsFor(Item, SetViewMode.Grid) -export class ItemGridElementComponent extends AbstractListableElementComponent {} diff --git a/src/app/shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.html b/src/app/shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.html index e735dbf107..81ee3ebcce 100644 --- a/src/app/shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.html +++ b/src/app/shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.html @@ -1,34 +1 @@ - -
- -
- - -
-
-
- - -

-
-

- - {{dso.firstMetadataValue('dc.date.issued')}} - , - - - -

-

- - - -

-
- View -
-
-
-
+ diff --git a/src/app/shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.spec.ts b/src/app/shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.spec.ts index eb3e0c589c..99a3e553f5 100644 --- a/src/app/shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.spec.ts +++ b/src/app/shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.spec.ts @@ -1,4 +1,4 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { async, TestBed } from '@angular/core/testing'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { TruncatePipe } from '../../../../utils/truncate.pipe'; import { TruncatableService } from '../../../../truncatable/truncatable.service'; @@ -6,16 +6,12 @@ import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; import { By } from '@angular/platform-browser'; import { PublicationGridElementComponent } from './publication-grid-element.component'; import { of as observableOf } from 'rxjs/internal/observable/of'; -import { ItemSearchResult } from '../../../../object-collection/shared/item-search-result.model'; import { Item } from '../../../../../core/shared/item.model'; -import { ITEM } from '../../../../items/switcher/item-type-switcher.component'; import { createSuccessfulRemoteDataObject$ } from '../../../../testing/utils'; import { PaginatedList } from '../../../../../core/data/paginated-list'; import { PageInfo } from '../../../../../core/shared/page-info.model'; -const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult(); -mockItemWithMetadata.hitHighlights = {}; -mockItemWithMetadata.indexableObject = Object.assign(new Item(), { +const mockItem = Object.assign(new Item(), { bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), metadata: { 'dc.title': [ @@ -45,83 +41,41 @@ mockItemWithMetadata.indexableObject = Object.assign(new Item(), { } }); -const mockItemWithoutMetadata: ItemSearchResult = new ItemSearchResult(); -mockItemWithoutMetadata.hitHighlights = {}; -mockItemWithoutMetadata.indexableObject = Object.assign(new Item(), { - bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), - metadata: { - 'dc.title': [ - { - language: 'en_US', - value: 'This is just another title' - } - ] - } -}); +describe('PublicationGridElementComponent', () => { + let comp; + let fixture; -describe('PublicationGridElementComponent', getEntityGridElementTestComponent(PublicationGridElementComponent, mockItemWithMetadata, mockItemWithoutMetadata, ['authors', 'date', 'abstract'])); + const truncatableServiceStub: any = { + isCollapsed: (id: number) => observableOf(true), + }; -/** - * Create test cases for a grid component of an entity. - * @param component The component's class - * @param searchResultWithMetadata An ItemSearchResult containing an item with metadata that should be displayed in the grid element - * @param searchResultWithoutMetadata An ItemSearchResult containing an item that's missing the metadata that should be displayed in the grid element - * @param fieldsToCheck A list of fields to check. The tests expect to find html elements with class ".item-${field}", so make sure they exist in the html template of the grid element. - * For example: If one of the fields to check is labeled "authors", the html template should contain at least one element with class ".item-authors" that's - * present when the author metadata is available. - */ -export function getEntityGridElementTestComponent(component, searchResultWithMetadata: ItemSearchResult, searchResultWithoutMetadata: ItemSearchResult, fieldsToCheck: string[]) { - return () => { - let comp; - let fixture; + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [NoopAnimationsModule], + declarations: [PublicationGridElementComponent, TruncatePipe], + providers: [ + { provide: TruncatableService, useValue: truncatableServiceStub }, + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(PublicationGridElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); - const truncatableServiceStub: any = { - isCollapsed: (id: number) => observableOf(true), - }; + beforeEach(async(() => { + fixture = TestBed.createComponent(PublicationGridElementComponent); + comp = fixture.componentInstance; + })); - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [NoopAnimationsModule], - declarations: [component, TruncatePipe], - providers: [ - { provide: TruncatableService, useValue: truncatableServiceStub }, - {provide: ITEM, useValue: searchResultWithoutMetadata} - ], - schemas: [NO_ERRORS_SCHEMA] - }).overrideComponent(component, { - set: { changeDetection: ChangeDetectionStrategy.Default } - }).compileComponents(); - })); - - beforeEach(async(() => { - fixture = TestBed.createComponent(component); - comp = fixture.componentInstance; - })); - - fieldsToCheck.forEach((field) => { - describe(`when the item has "${field}" metadata`, () => { - beforeEach(() => { - comp.dso = searchResultWithMetadata.indexableObject; - fixture.detectChanges(); - }); - - it(`should show the "${field}" field`, () => { - const itemAuthorField = fixture.debugElement.query(By.css(`.item-${field}`)); - expect(itemAuthorField).not.toBeNull(); - }); - }); - - describe(`when the item has no "${field}" metadata`, () => { - beforeEach(() => { - comp.dso = searchResultWithoutMetadata.indexableObject; - fixture.detectChanges(); - }); - - it(`should not show the "${field}" field`, () => { - const itemAuthorField = fixture.debugElement.query(By.css(`.item-${field}`)); - expect(itemAuthorField).toBeNull(); - }); - }); + describe(`when the publication is rendered`, () => { + beforeEach(() => { + comp.object = mockItem; + fixture.detectChanges(); }); - } -} + + it(`should contain a PublicationGridElementComponent`, () => { + const publicationGridElement = fixture.debugElement.query(By.css(`ds-publication-search-result-grid-element`)); + expect(publicationGridElement).not.toBeNull(); + }); + }); +}); diff --git a/src/app/shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.ts b/src/app/shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.ts index 1bcd028baf..8450150dcb 100644 --- a/src/app/shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.ts +++ b/src/app/shared/object-grid/item-grid-element/item-types/publication/publication-grid-element.component.ts @@ -1,10 +1,12 @@ -import { TypedItemSearchResultGridElementComponent } from '../typed-item-search-result-grid-element.component'; -import { DEFAULT_ITEM_TYPE, ItemViewMode, rendersItemType } from '../../../../items/item-type-decorator'; import { Component } from '@angular/core'; import { focusShadow } from '../../../../animations/focus'; +import { ViewMode } from '../../../../../core/shared/view-mode.model'; +import { listableObjectComponent } from '../../../../object-collection/shared/listable-object/listable-object.decorator'; +import { AbstractListableElementComponent } from '../../../../object-collection/shared/object-collection-element/abstract-listable-element.component'; +import { Item } from '../../../../../core/shared/item.model'; -@rendersItemType('Publication', ItemViewMode.Card) -@rendersItemType(DEFAULT_ITEM_TYPE, ItemViewMode.Card) +@listableObjectComponent('Publication', ViewMode.GridElement) +@listableObjectComponent(Item, ViewMode.GridElement) @Component({ selector: 'ds-publication-grid-element', styleUrls: ['./publication-grid-element.component.scss'], @@ -14,5 +16,5 @@ import { focusShadow } from '../../../../animations/focus'; /** * The component for displaying a grid element for an item of the type Publication */ -export class PublicationGridElementComponent extends TypedItemSearchResultGridElementComponent { +export class PublicationGridElementComponent extends AbstractListableElementComponent { } diff --git a/src/app/shared/object-grid/item-grid-element/item-types/typed-item-search-result-grid-element.component.spec.ts b/src/app/shared/object-grid/item-grid-element/item-types/typed-item-search-result-grid-element.component.spec.ts deleted file mode 100644 index e4ace8d0b2..0000000000 --- a/src/app/shared/object-grid/item-grid-element/item-types/typed-item-search-result-grid-element.component.spec.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { TruncatePipe } from '../../../utils/truncate.pipe'; -import { TruncatableService } from '../../../truncatable/truncatable.service'; -import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; -import { Item } from '../../../../core/shared/item.model'; -import { RemoteData } from '../../../../core/data/remote-data'; -import { PaginatedList } from '../../../../core/data/paginated-list'; -import { PageInfo } from '../../../../core/shared/page-info.model'; -import { ITEM } from '../../../items/switcher/item-type-switcher.component'; -import { ItemSearchResult } from '../../../object-collection/shared/item-search-result.model'; -import { createRelationshipsObservable } from '../../../../+item-page/simple/item-types/shared/item.component.spec'; -import { of as observableOf } from 'rxjs'; -import { MetadataMap } from '../../../../core/shared/metadata.models'; -import { TypedItemSearchResultGridElementComponent } from './typed-item-search-result-grid-element.component'; - -const mockItem: Item = Object.assign(new Item(), { - bitstreams: observableOf(new RemoteData(false, false, true, null, new PaginatedList(new PageInfo(), []))), - metadata: [], - relationships: createRelationshipsObservable() -}); -const mockSearchResult = { - indexableObject: mockItem as Item, - hitHighlights: new MetadataMap() -} as ItemSearchResult; - -describe('TypedItemSearchResultGridElementComponent', () => { - let comp: TypedItemSearchResultGridElementComponent; - let fixture: ComponentFixture; - - describe('when injecting an Item', () => { - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [TypedItemSearchResultGridElementComponent, TruncatePipe], - providers: [ - {provide: TruncatableService, useValue: {}}, - {provide: ITEM, useValue: mockItem} - ], - - schemas: [NO_ERRORS_SCHEMA] - }).overrideComponent(TypedItemSearchResultGridElementComponent, { - set: {changeDetection: ChangeDetectionStrategy.Default} - }).compileComponents(); - })); - - beforeEach(async(() => { - fixture = TestBed.createComponent(TypedItemSearchResultGridElementComponent); - comp = fixture.componentInstance; - })); - - it('should initiate item, object and dso correctly', () => { - expect(comp.item).toBe(mockItem); - expect(comp.dso).toBe(mockItem); - expect(comp.object.indexableObject).toBe(mockItem); - }) - }); - - describe('when injecting an ItemSearchResult', () => { - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [TypedItemSearchResultGridElementComponent, TruncatePipe], - providers: [ - {provide: TruncatableService, useValue: {}}, - {provide: ITEM, useValue: mockSearchResult} - ], - - schemas: [NO_ERRORS_SCHEMA] - }).overrideComponent(TypedItemSearchResultGridElementComponent, { - set: {changeDetection: ChangeDetectionStrategy.Default} - }).compileComponents(); - })); - - beforeEach(async(() => { - fixture = TestBed.createComponent(TypedItemSearchResultGridElementComponent); - comp = fixture.componentInstance; - })); - - it('should initiate item, object and dso correctly', () => { - expect(comp.item).toBe(mockItem); - expect(comp.dso).toBe(mockItem); - expect(comp.object.indexableObject).toBe(mockItem); - }) - }); -}); diff --git a/src/app/shared/object-grid/item-grid-element/item-types/typed-item-search-result-grid-element.component.ts b/src/app/shared/object-grid/item-grid-element/item-types/typed-item-search-result-grid-element.component.ts deleted file mode 100644 index f4f470c052..0000000000 --- a/src/app/shared/object-grid/item-grid-element/item-types/typed-item-search-result-grid-element.component.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { ItemSearchResult } from '../../../object-collection/shared/item-search-result.model'; -import { Item } from '../../../../core/shared/item.model'; -import { SearchResultGridElementComponent } from '../../search-result-grid-element/search-result-grid-element.component'; -import { TruncatableService } from '../../../truncatable/truncatable.service'; -import { Component, Inject } from '@angular/core'; -import { ITEM } from '../../../items/switcher/item-type-switcher.component'; -import { hasValue } from '../../../empty.util'; -import { MetadataMap } from '../../../../core/shared/metadata.models'; - -/** - * A generic component for displaying item grid elements - */ -@Component({ - selector: 'ds-item-search-result-grid-element', - template: '' -}) -export class TypedItemSearchResultGridElementComponent extends SearchResultGridElementComponent { - item: Item; - - constructor( - protected truncatableService: TruncatableService, - @Inject(ITEM) public obj: Item | ItemSearchResult, - ) { - super(undefined, truncatableService); - if (hasValue((obj as any).indexableObject)) { - this.object = obj as ItemSearchResult; - this.dso = this.object.indexableObject; - } else { - this.object = { - indexableObject: obj as Item, - hitHighlights: new MetadataMap() - }; - this.dso = obj as Item; - } - this.item = this.dso; - } -} diff --git a/src/app/shared/object-grid/object-grid.component.html b/src/app/shared/object-grid/object-grid.component.html index 9d1f8f5ea2..348536bfed 100644 --- a/src/app/shared/object-grid/object-grid.component.html +++ b/src/app/shared/object-grid/object-grid.component.html @@ -13,11 +13,11 @@
- +
- - + + diff --git a/src/app/shared/object-grid/object-grid.component.scss b/src/app/shared/object-grid/object-grid.component.scss index 8f19309d89..fb883a1f07 100644 --- a/src/app/shared/object-grid/object-grid.component.scss +++ b/src/app/shared/object-grid/object-grid.component.scss @@ -1,6 +1,6 @@ $ds-wrapper-grid-spacing: $spacer/2; -ds-wrapper-grid-element ::ng-deep { +:host ::ng-deep { div.thumbnail > img { height: $card-thumbnail-height; width: 100%; diff --git a/src/app/shared/object-grid/object-grid.component.ts b/src/app/shared/object-grid/object-grid.component.ts index e539ca5714..2da4abe13b 100644 --- a/src/app/shared/object-grid/object-grid.component.ts +++ b/src/app/shared/object-grid/object-grid.component.ts @@ -20,6 +20,9 @@ import { HostWindowService, WidthCategory } from '../host-window.service'; import { ListableObject } from '../object-collection/shared/listable-object.model'; import { PaginationComponentOptions } from '../pagination/pagination-component-options.model'; +import { ViewMode } from '../../core/shared/view-mode.model'; +import { Context } from '../../core/shared/context.model'; +import { CollectionElementLinkType } from '../object-collection/collection-element-link.type'; @Component({ changeDetection: ChangeDetectionStrategy.Default, @@ -31,17 +34,57 @@ import { PaginationComponentOptions } from '../pagination/pagination-component-o }) export class ObjectGridComponent implements OnInit { + /** + * The view mode of the this component + */ + viewMode = ViewMode.GridElement; + /** + * The current pagination configuration + */ @Input() config: PaginationComponentOptions; + + /** + * The current sort configuration + */ @Input() sortConfig: SortOptions; + + /** + * The whether or not the gear is hidden + */ @Input() hideGear = false; + + /** + * Whether or not the pager is visible when there is only a single page of results + */ @Input() hidePagerWhenSinglePage = true; + + /** + * The link type of the listable elements + */ + @Input() linkType: CollectionElementLinkType; + + /** + * The context of the listable elements + */ + @Input() context: Context; + + /** + * Behavior subject to output the current listable objects + */ private _objects$: BehaviorSubject>>; + /** + * Setter to make sure the observable is turned into an observable + * @param objects The new objects to output + */ @Input() set objects(objects: RemoteData>) { this._objects$.next(objects); } + /** + * Getter to return the current objects + */ get objects() { return this._objects$.getValue(); } @@ -76,7 +119,10 @@ export class ObjectGridComponent implements OnInit { */ @Output() sortDirectionChange: EventEmitter = new EventEmitter(); - @Output() paginationChange: EventEmitter = new EventEmitter(); + /** + * An event fired when on of the pagination parameters changes + */ + @Output() paginationChange: EventEmitter = new EventEmitter(); /** * An event fired when the sort field is changed. @@ -90,6 +136,9 @@ export class ObjectGridComponent implements OnInit { this._objects$ = new BehaviorSubject(undefined); } + /** + * Initialize the instance variables + */ ngOnInit(): void { const nbColumns$ = this.hostWindow.widthCategory.pipe( map((widthCat: WidthCategory) => { @@ -133,22 +182,40 @@ export class ObjectGridComponent implements OnInit { })); } + /** + * Emits the current page when it changes + * @param event The new page + */ onPageChange(event) { this.pageChange.emit(event); } - + /** + * Emits the current page size when it changes + * @param event The new page size + */ onPageSizeChange(event) { this.pageSizeChange.emit(event); } - + /** + * Emits the current sort direction when it changes + * @param event The new sort direction + */ onSortDirectionChange(event) { this.sortDirectionChange.emit(event); } + /** + * Emits the current sort field when it changes + * @param event The new sort field + */ onSortFieldChange(event) { this.sortFieldChange.emit(event); } + /** + * Emits the current pagination when it changes + * @param event The new pagination + */ onPaginationChange(event) { this.paginationChange.emit(event); } diff --git a/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.html b/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.html index 91548d945d..0c45316e30 100644 --- a/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.html +++ b/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.html @@ -1,13 +1,17 @@
- + + + + +

{{dso.name}}

{{dso.shortDescription}}

-
- View +
+ View
diff --git a/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.ts b/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.ts index 61cc5dca1c..a834327736 100644 --- a/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.ts +++ b/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.ts @@ -1,16 +1,18 @@ import { Component } from '@angular/core'; -import { renderElementsFor} from '../../../object-collection/shared/dso-element-decorator'; import { SearchResultGridElementComponent } from '../search-result-grid-element.component'; import { Collection } from '../../../../core/shared/collection.model'; -import { SetViewMode } from '../../../view-mode'; import { CollectionSearchResult } from '../../../object-collection/shared/collection-search-result.model'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; +import { listableObjectComponent } from '../../../object-collection/shared/listable-object/listable-object.decorator'; @Component({ selector: 'ds-collection-search-result-grid-element', styleUrls: ['../search-result-grid-element.component.scss', 'collection-search-result-grid-element.component.scss'], templateUrl: 'collection-search-result-grid-element.component.html' }) - -@renderElementsFor(CollectionSearchResult, SetViewMode.Grid) +/** + * Component representing a grid element for a collection search result + */ +@listableObjectComponent(CollectionSearchResult, ViewMode.GridElement) export class CollectionSearchResultGridElementComponent extends SearchResultGridElementComponent {} diff --git a/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.html b/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.html index 95094a6fa1..d0a9aa700e 100644 --- a/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.html +++ b/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.html @@ -1,14 +1,17 @@
- - + + + + +

{{dso.name}}

{{dso.shortDescription}}

-
- View +
+ View
diff --git a/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.ts b/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.ts index d445e27ed6..e726c3e803 100644 --- a/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.ts +++ b/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.ts @@ -1,17 +1,18 @@ import { Component } from '@angular/core'; import { Community } from '../../../../core/shared/community.model'; -import { renderElementsFor } from '../../../object-collection/shared/dso-element-decorator'; import { SearchResultGridElementComponent } from '../search-result-grid-element.component'; -import { SetViewMode } from '../../../view-mode'; import { CommunitySearchResult } from '../../../object-collection/shared/community-search-result.model'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; +import { listableObjectComponent } from '../../../object-collection/shared/listable-object/listable-object.decorator'; @Component({ selector: 'ds-community-search-result-grid-element', styleUrls: ['../search-result-grid-element.component.scss', 'community-search-result-grid-element.component.scss'], templateUrl: 'community-search-result-grid-element.component.html' }) - -@renderElementsFor(CommunitySearchResult, SetViewMode.Grid) +/** + * Component representing a grid element for a community search result + */ +@listableObjectComponent(CommunitySearchResult, ViewMode.GridElement) export class CommunitySearchResultGridElementComponent extends SearchResultGridElementComponent { - } diff --git a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.html b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.html deleted file mode 100644 index d433c7acf2..0000000000 --- a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.scss b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.scss deleted file mode 100644 index d61f3ccf55..0000000000 --- a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.scss +++ /dev/null @@ -1,12 +0,0 @@ -.card { - a > div { - position: relative; - .thumbnail-overlay { - height: 100%; - position: absolute; - top: 0; - width: 100%; - background-color: map-get($theme-colors, primary); - } - } -} diff --git a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.spec.ts b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.spec.ts deleted file mode 100644 index 282478ec33..0000000000 --- a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.spec.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { ItemSearchResultGridElementComponent } from './item-search-result-grid-element.component'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { of as observableOf } from 'rxjs'; -import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; -import { By } from '@angular/platform-browser'; -import { TruncatePipe } from '../../../utils/truncate.pipe'; -import { Item } from '../../../../core/shared/item.model'; -import { TruncatableService } from '../../../truncatable/truncatable.service'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { ItemSearchResult } from '../../../object-collection/shared/item-search-result.model'; -import { ItemViewMode } from '../../../items/item-type-decorator'; - -let itemSearchResultGridElementComponent: ItemSearchResultGridElementComponent; -let fixture: ComponentFixture; - -const truncatableServiceStub: any = { - isCollapsed: (id: number) => observableOf(true), -}; - -const type = 'authorOfPublication'; - -const mockItemWithRelationshipType: ItemSearchResult = new ItemSearchResult(); -mockItemWithRelationshipType.hitHighlights = {}; -mockItemWithRelationshipType.indexableObject = Object.assign(new Item(), { - bitstreams: observableOf({}), - metadata: { - 'relationship.type': [ - { - language: 'en_US', - value: type - } - ] - } -}); - -describe('ItemSearchResultGridElementComponent', () => { - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [NoopAnimationsModule], - declarations: [ItemSearchResultGridElementComponent, TruncatePipe], - providers: [ - { provide: TruncatableService, useValue: truncatableServiceStub }, - { provide: 'objectElementProvider', useValue: (mockItemWithRelationshipType) } - ], - schemas: [NO_ERRORS_SCHEMA] - }).overrideComponent(ItemSearchResultGridElementComponent, { - set: { changeDetection: ChangeDetectionStrategy.Default } - }).compileComponents(); - })); - - beforeEach(async(() => { - fixture = TestBed.createComponent(ItemSearchResultGridElementComponent); - itemSearchResultGridElementComponent = fixture.componentInstance; - })); - - it('should show send the object to item-type-switcher using viewMode "Card"', () => { - const itemTypeSwitcherComp = fixture.debugElement.query(By.css('ds-item-type-switcher')).componentInstance; - expect(itemTypeSwitcherComp.object).toBe(mockItemWithRelationshipType); - expect(itemTypeSwitcherComp.viewMode).toEqual(ItemViewMode.Card); - }); -}); diff --git a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.ts b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.ts deleted file mode 100644 index 7bbe41fe60..0000000000 --- a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Component } from '@angular/core'; - -import { renderElementsFor } from '../../../object-collection/shared/dso-element-decorator'; -import { SearchResultGridElementComponent } from '../search-result-grid-element.component'; -import { Item } from '../../../../core/shared/item.model'; -import { ItemSearchResult } from '../../../object-collection/shared/item-search-result.model'; -import { SetViewMode } from '../../../view-mode'; -import { focusShadow } from '../../../../shared/animations/focus'; -import { ItemViewMode } from '../../../items/item-type-decorator'; - -@Component({ - selector: 'ds-item-search-result-grid-element', - styleUrls: ['../search-result-grid-element.component.scss', 'item-search-result-grid-element.component.scss'], - templateUrl: 'item-search-result-grid-element.component.html', - animations: [focusShadow], -}) - -@renderElementsFor(ItemSearchResult, SetViewMode.Grid) -export class ItemSearchResultGridElementComponent extends SearchResultGridElementComponent { - viewMode = ItemViewMode.Card; -} diff --git a/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.html b/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.html new file mode 100644 index 0000000000..a00e30cbcd --- /dev/null +++ b/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.html @@ -0,0 +1,41 @@ + +
+ +
+ + +
+
+ +
+ + +
+
+
+ + +

+
+

+ + {{firstMetadataValue('dc.date.issued')}} + , + + + +

+

+ + + +

+
+ View +
+
+
+
diff --git a/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.scss b/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.spec.ts b/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.spec.ts new file mode 100644 index 0000000000..69e50c7300 --- /dev/null +++ b/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.spec.ts @@ -0,0 +1,125 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { TruncatePipe } from '../../../../utils/truncate.pipe'; +import { TruncatableService } from '../../../../truncatable/truncatable.service'; +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { By } from '@angular/platform-browser'; +import { of as observableOf } from 'rxjs/internal/observable/of'; +import { ItemSearchResult } from '../../../../object-collection/shared/item-search-result.model'; +import { Item } from '../../../../../core/shared/item.model'; +import { createSuccessfulRemoteDataObject$ } from '../../../../testing/utils'; +import { PaginatedList } from '../../../../../core/data/paginated-list'; +import { PageInfo } from '../../../../../core/shared/page-info.model'; +import { PublicationSearchResultGridElementComponent } from './publication-search-result-grid-element.component'; + +const mockItemWithMetadata: ItemSearchResult = new ItemSearchResult(); +mockItemWithMetadata.hitHighlights = {}; +mockItemWithMetadata.indexableObject = Object.assign(new Item(), { + bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + 'dc.contributor.author': [ + { + language: 'en_US', + value: 'Smith, Donald' + } + ], + 'dc.date.issued': [ + { + language: null, + value: '2015-06-26' + } + ], + 'dc.description.abstract': [ + { + language: 'en_US', + value: 'This is an abstract' + } + ] + } +}); + +const mockItemWithoutMetadata: ItemSearchResult = new ItemSearchResult(); +mockItemWithoutMetadata.hitHighlights = {}; +mockItemWithoutMetadata.indexableObject = Object.assign(new Item(), { + bundles: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ] + } +}); + +describe('PublicationGridElementComponent', getEntityGridElementTestComponent(PublicationSearchResultGridElementComponent, mockItemWithMetadata, mockItemWithoutMetadata, ['authors', 'date', 'abstract'])); + +/** + * Create test cases for a grid component of an entity. + * @param component The component's class + * @param searchResultWithMetadata An ItemSearchResult containing an item with metadata that should be displayed in the grid element + * @param searchResultWithoutMetadata An ItemSearchResult containing an item that's missing the metadata that should be displayed in the grid element + * @param fieldsToCheck A list of fields to check. The tests expect to find html elements with class ".item-${field}", so make sure they exist in the html template of the grid element. + * For example: If one of the fields to check is labeled "authors", the html template should contain at least one element with class ".item-authors" that's + * present when the author metadata is available. + */ +export function getEntityGridElementTestComponent(component, searchResultWithMetadata: ItemSearchResult, searchResultWithoutMetadata: ItemSearchResult, fieldsToCheck: string[]) { + return () => { + let comp; + let fixture; + + const truncatableServiceStub: any = { + isCollapsed: (id: number) => observableOf(true), + }; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [NoopAnimationsModule], + declarations: [component, TruncatePipe], + providers: [ + { provide: TruncatableService, useValue: truncatableServiceStub }, + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(component, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(component); + comp = fixture.componentInstance; + })); + + fieldsToCheck.forEach((field) => { + describe(`when the item has "${field}" metadata`, () => { + beforeEach(() => { + comp.object = searchResultWithMetadata; + fixture.detectChanges(); + }); + + it(`should show the "${field}" field`, () => { + const itemAuthorField = fixture.debugElement.query(By.css(`.item-${field}`)); + expect(itemAuthorField).not.toBeNull(); + }); + }); + + describe(`when the item has no "${field}" metadata`, () => { + beforeEach(() => { + comp.object = searchResultWithoutMetadata; + fixture.detectChanges(); + }); + + it(`should not show the "${field}" field`, () => { + const itemAuthorField = fixture.debugElement.query(By.css(`.item-${field}`)); + expect(itemAuthorField).toBeNull(); + }); + }); + }); + } +} diff --git a/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.ts b/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.ts new file mode 100644 index 0000000000..76618f18f2 --- /dev/null +++ b/src/app/shared/object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component.ts @@ -0,0 +1,20 @@ +import { Component } from '@angular/core'; +import { focusShadow } from '../../../../animations/focus'; +import { ViewMode } from '../../../../../core/shared/view-mode.model'; +import { listableObjectComponent } from '../../../../object-collection/shared/listable-object/listable-object.decorator'; +import { SearchResultGridElementComponent } from '../../search-result-grid-element.component'; +import { Item } from '../../../../../core/shared/item.model'; +import { ItemSearchResult } from '../../../../object-collection/shared/item-search-result.model'; + +@listableObjectComponent('PublicationSearchResult', ViewMode.GridElement) +@Component({ + selector: 'ds-publication-search-result-grid-element', + styleUrls: ['./publication-search-result-grid-element.component.scss'], + templateUrl: './publication-search-result-grid-element.component.html', + animations: [focusShadow] +}) +/** + * The component for displaying a grid element for an item search result of the type Publication + */ +export class PublicationSearchResultGridElementComponent extends SearchResultGridElementComponent { +} diff --git a/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.ts b/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.ts index 63b2536043..75345338e7 100644 --- a/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.ts +++ b/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.ts @@ -1,9 +1,8 @@ -import { Component, Inject } from '@angular/core'; +import { Component, Inject, OnInit } from '@angular/core'; import { SearchResult } from '../../../+search-page/search-result.model'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component'; -import { ListableObject } from '../../object-collection/shared/listable-object.model'; import { TruncatableService } from '../../truncatable/truncatable.service'; import { Observable } from 'rxjs'; import { Metadata } from '../../../core/shared/metadata.utils'; @@ -14,15 +13,30 @@ import { hasValue } from '../../empty.util'; template: `` }) -export class SearchResultGridElementComponent, K extends DSpaceObject> extends AbstractListableElementComponent { +export class SearchResultGridElementComponent, K extends DSpaceObject> extends AbstractListableElementComponent implements OnInit { + /** + * The DSpaceObject of the search result + */ dso: K; + + /** + * Whether or not the grid element is currently collapsed + */ isCollapsed$: Observable; - public constructor(@Inject('objectElementProvider') public listableObject: ListableObject, protected truncatableService: TruncatableService) { - super(listableObject); + public constructor(protected truncatableService: TruncatableService) { + super(); + if (hasValue(this.object)) { + this.isCollapsed$ = this.isCollapsed(); + } + } + + /** + * Retrieve the dso from the search result + */ + ngOnInit(): void { if (hasValue(this.object)) { this.dso = this.object.indexableObject; - this.isCollapsed$ = this.isCollapsed(); } } @@ -49,5 +63,4 @@ export class SearchResultGridElementComponent, K exten private isCollapsed(): Observable { return this.truncatableService.isCollapsed(this.dso.id); } - } diff --git a/src/app/shared/object-grid/wrapper-grid-element/wrapper-grid-element.component.html b/src/app/shared/object-grid/wrapper-grid-element/wrapper-grid-element.component.html deleted file mode 100644 index d6fd1cf9aa..0000000000 --- a/src/app/shared/object-grid/wrapper-grid-element/wrapper-grid-element.component.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/app/shared/object-grid/wrapper-grid-element/wrapper-grid-element.component.scss b/src/app/shared/object-grid/wrapper-grid-element/wrapper-grid-element.component.scss deleted file mode 100644 index 8b13789179..0000000000 --- a/src/app/shared/object-grid/wrapper-grid-element/wrapper-grid-element.component.scss +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/app/shared/object-grid/wrapper-grid-element/wrapper-grid-element.component.spec.ts b/src/app/shared/object-grid/wrapper-grid-element/wrapper-grid-element.component.spec.ts deleted file mode 100644 index 0a78c97209..0000000000 --- a/src/app/shared/object-grid/wrapper-grid-element/wrapper-grid-element.component.spec.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { WrapperGridElementComponent } from './wrapper-grid-element.component'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { of as observableOf } from 'rxjs'; -import { ActivatedRoute, Router } from '@angular/router'; -import { RouterStub } from '../../testing/router-stub'; -import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { By } from '@angular/platform-browser'; - -let wrapperGridElementComponent: WrapperGridElementComponent; -let fixture: ComponentFixture; -const queryParam = 'test query'; -const scopeParam = '7669c72a-3f2a-451f-a3b9-9210e7a4c02f'; -const activatedRouteStub = { - queryParams: observableOf({ - query: queryParam, - scope: scopeParam - }) -}; - -describe('WrapperGridElementComponent', () => { - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ WrapperGridElementComponent ], - providers: [ - { provide: ActivatedRoute, useValue: activatedRouteStub }, - { provide: Router, useClass: RouterStub }, - { provide: 'objectElementProvider', useFactory: (wrapperGridElementComponent)} - ], - - schemas: [ NO_ERRORS_SCHEMA ] - }).compileComponents(); // compile template and css - })); - - beforeEach(async(() => { - fixture = TestBed.createComponent(WrapperGridElementComponent); - wrapperGridElementComponent = fixture.componentInstance; - - })); - - it('should show the wrapper element containing the cards',() => { - expect(fixture.debugElement.query(By.css('ds-collection-grid-element'))).toBeDefined(); - }) -}) diff --git a/src/app/shared/object-grid/wrapper-grid-element/wrapper-grid-element.component.ts b/src/app/shared/object-grid/wrapper-grid-element/wrapper-grid-element.component.ts deleted file mode 100644 index 0a7312484f..0000000000 --- a/src/app/shared/object-grid/wrapper-grid-element/wrapper-grid-element.component.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Component, Injector, Input, OnInit } from '@angular/core'; -import { SetViewMode } from '../../view-mode'; -import { GenericConstructor } from '../../../core/shared/generic-constructor'; -import { rendersDSOType } from '../../object-collection/shared/dso-element-decorator'; -import { ListableObject } from '../../object-collection/shared/listable-object.model'; - -@Component({ - selector: 'ds-wrapper-grid-element', - styleUrls: ['./wrapper-grid-element.component.scss'], - templateUrl: './wrapper-grid-element.component.html' -}) -export class WrapperGridElementComponent implements OnInit { - @Input() object: ListableObject; - objectInjector: Injector; - gridElement: any; - - constructor(private injector: Injector) { - } - - ngOnInit(): void { - this.objectInjector = Injector.create({ - providers: [{ provide: 'objectElementProvider', useFactory: () => (this.object), deps:[] }], - parent: this.injector - }); - this.gridElement = this.getGridElement(); - } - - getGridElement(): string { - const f: GenericConstructor = this.object.constructor as GenericConstructor; - return rendersDSOType(f, SetViewMode.Grid); - } -} diff --git a/src/app/shared/object-list/browse-entry-list-element/browse-entry-list-element.component.html b/src/app/shared/object-list/browse-entry-list-element/browse-entry-list-element.component.html index 0fad726777..e3455bf095 100644 --- a/src/app/shared/object-list/browse-entry-list-element/browse-entry-list-element.component.html +++ b/src/app/shared/object-list/browse-entry-list-element/browse-entry-list-element.component.html @@ -1,7 +1,10 @@
- - {{object.value}} - -   - {{object.count}} + + {{object.value}} + + + {{object.value}} + +   + {{object.count}}
diff --git a/src/app/shared/object-list/browse-entry-list-element/browse-entry-list-element.component.ts b/src/app/shared/object-list/browse-entry-list-element/browse-entry-list-element.component.ts index a32cfb333e..3c1ef298a8 100644 --- a/src/app/shared/object-list/browse-entry-list-element/browse-entry-list-element.component.ts +++ b/src/app/shared/object-list/browse-entry-list-element/browse-entry-list-element.component.ts @@ -1,10 +1,10 @@ import { Component, Input, Inject } from '@angular/core'; import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component'; -import { renderElementsFor } from '../../object-collection/shared/dso-element-decorator'; import { BrowseEntry } from '../../../core/shared/browse-entry.model'; import { ViewMode } from '../../../core/shared/view-mode.model'; -import { SetViewMode } from '../../view-mode'; +import { listableObjectComponent } from '../../object-collection/shared/listable-object/listable-object.decorator'; +import { Collection } from '../../../core/shared/collection.model'; @Component({ selector: 'ds-browse-entry-list-element', @@ -15,5 +15,5 @@ import { SetViewMode } from '../../view-mode'; /** * This component is automatically used to create a list view for BrowseEntry objects when used in ObjectCollectionComponent */ -@renderElementsFor(BrowseEntry, SetViewMode.List) +@listableObjectComponent(BrowseEntry, ViewMode.ListElement) export class BrowseEntryListElementComponent extends AbstractListableElementComponent {} diff --git a/src/app/shared/object-list/collection-list-element/collection-list-element.component.html b/src/app/shared/object-list/collection-list-element/collection-list-element.component.html index dec2794dca..c61adf5dad 100644 --- a/src/app/shared/object-list/collection-list-element/collection-list-element.component.html +++ b/src/app/shared/object-list/collection-list-element/collection-list-element.component.html @@ -1,6 +1,9 @@ - + {{object.name}} + + {{object.name}} +
{{object.shortDescription}}
diff --git a/src/app/shared/object-list/collection-list-element/collection-list-element.component.ts b/src/app/shared/object-list/collection-list-element/collection-list-element.component.ts index 3fe64f5bb9..48bd6697a0 100644 --- a/src/app/shared/object-list/collection-list-element/collection-list-element.component.ts +++ b/src/app/shared/object-list/collection-list-element/collection-list-element.component.ts @@ -1,15 +1,17 @@ import { Component, Inject } from '@angular/core'; import { Collection } from '../../../core/shared/collection.model'; -import { renderElementsFor } from '../../object-collection/shared/dso-element-decorator'; -import { SetViewMode } from '../../view-mode'; import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component'; +import { ViewMode } from '../../../core/shared/view-mode.model'; +import { listableObjectComponent } from '../../object-collection/shared/listable-object/listable-object.decorator'; @Component({ selector: 'ds-collection-list-element', styleUrls: ['./collection-list-element.component.scss'], templateUrl: './collection-list-element.component.html' }) - -@renderElementsFor(Collection, SetViewMode.List) +/** + * Component representing list element for a collection + */ +@listableObjectComponent(Collection, ViewMode.ListElement) export class CollectionListElementComponent extends AbstractListableElementComponent {} diff --git a/src/app/shared/object-list/community-list-element/community-list-element.component.html b/src/app/shared/object-list/community-list-element/community-list-element.component.html index 7582680fb2..af01999ca7 100644 --- a/src/app/shared/object-list/community-list-element/community-list-element.component.html +++ b/src/app/shared/object-list/community-list-element/community-list-element.component.html @@ -1,6 +1,9 @@ - + {{object.name}} + + {{object.name}} +
{{object.shortDescription}}
diff --git a/src/app/shared/object-list/community-list-element/community-list-element.component.ts b/src/app/shared/object-list/community-list-element/community-list-element.component.ts index 5e254cb1ac..aa583378de 100644 --- a/src/app/shared/object-list/community-list-element/community-list-element.component.ts +++ b/src/app/shared/object-list/community-list-element/community-list-element.component.ts @@ -2,14 +2,16 @@ import { Component, Input, Inject } from '@angular/core'; import { Community } from '../../../core/shared/community.model'; import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component'; -import { renderElementsFor } from '../../object-collection/shared/dso-element-decorator'; -import { SetViewMode } from '../../view-mode'; +import { ViewMode } from '../../../core/shared/view-mode.model'; +import { listableObjectComponent } from '../../object-collection/shared/listable-object/listable-object.decorator'; @Component({ selector: 'ds-community-list-element', styleUrls: ['./community-list-element.component.scss'], templateUrl: './community-list-element.component.html' }) - -@renderElementsFor(Community, SetViewMode.List) +/** + * Component representing a list element for a community + */ +@listableObjectComponent(Community, ViewMode.ListElement) export class CommunityListElementComponent extends AbstractListableElementComponent {} diff --git a/src/app/shared/object-list/item-list-element/item-list-element.component.html b/src/app/shared/object-list/item-list-element/item-list-element.component.html deleted file mode 100644 index d433c7acf2..0000000000 --- a/src/app/shared/object-list/item-list-element/item-list-element.component.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/app/shared/object-list/item-list-element/item-list-element.component.spec.ts b/src/app/shared/object-list/item-list-element/item-list-element.component.spec.ts deleted file mode 100644 index 2c0c8b0aa2..0000000000 --- a/src/app/shared/object-list/item-list-element/item-list-element.component.spec.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; -import { ItemListElementComponent } from './item-list-element.component'; -import { Item } from '../../../core/shared/item.model'; -import { RemoteData } from '../../../core/data/remote-data'; -import { PaginatedList } from '../../../core/data/paginated-list'; -import { PageInfo } from '../../../core/shared/page-info.model'; -import { By } from '@angular/platform-browser'; -import { createRelationshipsObservable } from '../../../+item-page/simple/item-types/shared/item.component.spec'; -import { of as observableOf } from 'rxjs'; -import { createSuccessfulRemoteDataObject$ } from '../../testing/utils'; - -const mockItem: Item = Object.assign(new Item(), { - bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), - metadata: [], - relationships: createRelationshipsObservable() -}); - -describe('ItemListElementComponent', () => { - let comp: ItemListElementComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [], - declarations: [ItemListElementComponent], - providers: [ - { provide: 'objectElementProvider', useValue: mockItem } - ], - schemas: [NO_ERRORS_SCHEMA] - }).overrideComponent(ItemListElementComponent, { - set: {changeDetection: ChangeDetectionStrategy.Default} - }).compileComponents(); - })); - - beforeEach(async(() => { - fixture = TestBed.createComponent(ItemListElementComponent); - comp = fixture.componentInstance; - fixture.detectChanges(); - })); - - it('should call an item-type-switcher component and pass the item', () => { - const itemTypeSwitcher = fixture.debugElement.query(By.css('ds-item-type-switcher')).componentInstance; - expect(itemTypeSwitcher.object).toBe(mockItem); - }); - -}); diff --git a/src/app/shared/object-list/item-list-element/item-list-element.component.ts b/src/app/shared/object-list/item-list-element/item-list-element.component.ts deleted file mode 100644 index 67a6256d43..0000000000 --- a/src/app/shared/object-list/item-list-element/item-list-element.component.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Component } from '@angular/core'; - -import { Item } from '../../../core/shared/item.model'; -import { renderElementsFor } from '../../object-collection/shared/dso-element-decorator'; -import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component'; -import { SetViewMode } from '../../view-mode'; -import { ItemViewMode } from '../../items/item-type-decorator'; - -@Component({ - selector: 'ds-item-list-element', - styleUrls: ['./item-list-element.component.scss'], - templateUrl: './item-list-element.component.html' -}) - -/** - * The component used to list items depending on type - * Uses item-type-switcher to determine which components to use for displaying the list - */ -@renderElementsFor(Item, SetViewMode.List) -export class ItemListElementComponent extends AbstractListableElementComponent { - viewMode = ItemViewMode.Element; -} diff --git a/src/app/shared/object-list/item-list-element/item-types/publication/publication-list-element.component.html b/src/app/shared/object-list/item-list-element/item-types/publication/publication-list-element.component.html index d467edfb21..acc3ee4194 100644 --- a/src/app/shared/object-list/item-list-element/item-types/publication/publication-list-element.component.html +++ b/src/app/shared/object-list/item-list-element/item-types/publication/publication-list-element.component.html @@ -1,25 +1 @@ - - - - - (, ) - - - - ; - - - - -
- - -
-
+ \ No newline at end of file diff --git a/src/app/shared/object-list/item-list-element/item-types/publication/publication-list-element.component.spec.ts b/src/app/shared/object-list/item-list-element/item-types/publication/publication-list-element.component.spec.ts index 0913d2231c..85b964c083 100644 --- a/src/app/shared/object-list/item-list-element/item-types/publication/publication-list-element.component.spec.ts +++ b/src/app/shared/object-list/item-list-element/item-types/publication/publication-list-element.component.spec.ts @@ -1,17 +1,13 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { async, TestBed } from '@angular/core/testing'; import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; import { By } from '@angular/platform-browser'; import { PublicationListElementComponent } from './publication-list-element.component'; import { Item } from '../../../../../core/shared/item.model'; import { TruncatePipe } from '../../../../utils/truncate.pipe'; import { TruncatableService } from '../../../../truncatable/truncatable.service'; -import { ITEM } from '../../../../items/switcher/item-type-switcher.component'; import { of as observableOf } from 'rxjs'; -let publicationListElementComponent: PublicationListElementComponent; -let fixture: ComponentFixture; - -const mockItemWithMetadata: Item = Object.assign(new Item(), { +const mockItem: Item = Object.assign(new Item(), { bundles: observableOf({}), metadata: { 'dc.title': [ @@ -46,28 +42,22 @@ const mockItemWithMetadata: Item = Object.assign(new Item(), { ] } }); -const mockItemWithoutMetadata: Item = Object.assign(new Item(), { - bundles: observableOf({}), - metadata: { - 'dc.title': [ - { - language: 'en_US', - value: 'This is just another title' - } - ] - } -}); describe('PublicationListElementComponent', () => { + let comp; + let fixture; + + const truncatableServiceStub: any = { + isCollapsed: (id: number) => observableOf(true), + }; + beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ PublicationListElementComponent , TruncatePipe], + declarations: [PublicationListElementComponent, TruncatePipe], providers: [ - { provide: ITEM, useValue: mockItemWithMetadata}, - { provide: TruncatableService, useValue: {} } + { provide: TruncatableService, useValue: truncatableServiceStub }, ], - - schemas: [ NO_ERRORS_SCHEMA ] + schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(PublicationListElementComponent, { set: { changeDetection: ChangeDetectionStrategy.Default } }).compileComponents(); @@ -75,103 +65,18 @@ describe('PublicationListElementComponent', () => { beforeEach(async(() => { fixture = TestBed.createComponent(PublicationListElementComponent); - publicationListElementComponent = fixture.componentInstance; - + comp = fixture.componentInstance; })); - describe('When the item has an author', () => { + describe(`when the publication is rendered`, () => { beforeEach(() => { - publicationListElementComponent.item = mockItemWithMetadata; + comp.object = mockItem; fixture.detectChanges(); }); - it('should show the author paragraph', () => { - const itemAuthorField = fixture.debugElement.query(By.css('span.item-list-authors')); - expect(itemAuthorField).not.toBeNull(); - }); - }); - - describe('When the item has no author', () => { - beforeEach(() => { - publicationListElementComponent.item = mockItemWithoutMetadata; - fixture.detectChanges(); - }); - - it('should not show the author paragraph', () => { - const itemAuthorField = fixture.debugElement.query(By.css('span.item-list-authors')); - expect(itemAuthorField).toBeNull(); - }); - }); - - describe('When the item has a publisher', () => { - beforeEach(() => { - publicationListElementComponent.item = mockItemWithMetadata; - fixture.detectChanges(); - }); - - it('should show the publisher span', () => { - const publisherField = fixture.debugElement.query(By.css('span.item-list-publisher')); - expect(publisherField).not.toBeNull(); - }); - }); - - describe('When the item has no publisher', () => { - beforeEach(() => { - publicationListElementComponent.item = mockItemWithoutMetadata; - fixture.detectChanges(); - }); - - it('should not show the publisher span', () => { - const publisherField = fixture.debugElement.query(By.css('span.item-list-publisher')); - expect(publisherField).toBeNull(); - }); - }); - - describe('When the item has an issuedate', () => { - beforeEach(() => { - publicationListElementComponent.item = mockItemWithMetadata; - fixture.detectChanges(); - }); - - it('should show the issuedate span', () => { - const dateField = fixture.debugElement.query(By.css('span.item-list-date')); - expect(dateField).not.toBeNull(); - }); - }); - - describe('When the item has no issuedate', () => { - beforeEach(() => { - publicationListElementComponent.item = mockItemWithoutMetadata; - fixture.detectChanges(); - }); - - it('should not show the issuedate span', () => { - const dateField = fixture.debugElement.query(By.css('span.item-list-date')); - expect(dateField).toBeNull(); - }); - }); - - describe('When the item has an abstract', () => { - beforeEach(() => { - publicationListElementComponent.item = mockItemWithMetadata; - fixture.detectChanges(); - }); - - it('should show the abstract span', () => { - const abstractField = fixture.debugElement.query(By.css('div.item-list-abstract')); - expect(abstractField).not.toBeNull(); - }); - }); - - describe('When the item has no abstract', () => { - beforeEach(() => { - publicationListElementComponent.item = mockItemWithoutMetadata; - fixture.detectChanges(); - }); - - it('should not show the abstract span', () => { - const abstractField = fixture.debugElement.query(By.css('div.item-list-abstract')); - expect(abstractField).toBeNull(); + it(`should contain a PublicationListElementComponent`, () => { + const publicationListElement = fixture.debugElement.query(By.css(`ds-publication-search-result-list-element`)); + expect(publicationListElement).not.toBeNull(); }); }); }); diff --git a/src/app/shared/object-list/item-list-element/item-types/publication/publication-list-element.component.ts b/src/app/shared/object-list/item-list-element/item-types/publication/publication-list-element.component.ts index 4717ff1df2..59d0249aef 100644 --- a/src/app/shared/object-list/item-list-element/item-types/publication/publication-list-element.component.ts +++ b/src/app/shared/object-list/item-list-element/item-types/publication/publication-list-element.component.ts @@ -1,9 +1,11 @@ import { Component } from '@angular/core'; -import { DEFAULT_ITEM_TYPE, ItemViewMode, rendersItemType } from '../../../../items/item-type-decorator'; -import { TypedItemSearchResultListElementComponent } from '../typed-item-search-result-list-element.component'; +import { ViewMode } from '../../../../../core/shared/view-mode.model'; +import { listableObjectComponent } from '../../../../object-collection/shared/listable-object/listable-object.decorator'; +import { AbstractListableElementComponent } from '../../../../object-collection/shared/object-collection-element/abstract-listable-element.component'; +import { Item } from '../../../../../core/shared/item.model'; -@rendersItemType('Publication', ItemViewMode.Element) -@rendersItemType(DEFAULT_ITEM_TYPE, ItemViewMode.Element) +@listableObjectComponent('Publication', ViewMode.ListElement) +@listableObjectComponent(Item, ViewMode.ListElement) @Component({ selector: 'ds-publication-list-element', styleUrls: ['./publication-list-element.component.scss'], @@ -12,5 +14,5 @@ import { TypedItemSearchResultListElementComponent } from '../typed-item-search- /** * The component for displaying a list element for an item of the type Publication */ -export class PublicationListElementComponent extends TypedItemSearchResultListElementComponent { +export class PublicationListElementComponent extends AbstractListableElementComponent { } diff --git a/src/app/shared/object-list/item-list-element/item-types/typed-item-search-result-list-element.component.spec.ts b/src/app/shared/object-list/item-list-element/item-types/typed-item-search-result-list-element.component.spec.ts deleted file mode 100644 index 082347be0b..0000000000 --- a/src/app/shared/object-list/item-list-element/item-types/typed-item-search-result-list-element.component.spec.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { TruncatePipe } from '../../../utils/truncate.pipe'; -import { TruncatableService } from '../../../truncatable/truncatable.service'; -import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; -import { TypedItemSearchResultListElementComponent } from './typed-item-search-result-list-element.component'; -import { Item } from '../../../../core/shared/item.model'; -import { RemoteData } from '../../../../core/data/remote-data'; -import { PaginatedList } from '../../../../core/data/paginated-list'; -import { PageInfo } from '../../../../core/shared/page-info.model'; -import { ITEM } from '../../../items/switcher/item-type-switcher.component'; -import { ItemSearchResult } from '../../../object-collection/shared/item-search-result.model'; -import { createRelationshipsObservable } from '../../../../+item-page/simple/item-types/shared/item.component.spec'; -import { of as observableOf } from 'rxjs'; -import { MetadataMap } from '../../../../core/shared/metadata.models'; -import { createSuccessfulRemoteDataObject$ } from '../../../testing/utils'; - -const mockItem: Item = Object.assign(new Item(), { - bitstreams: createSuccessfulRemoteDataObject$(new PaginatedList(new PageInfo(), [])), - metadata: [], - relationships: createRelationshipsObservable() -}); -const mockSearchResult = { - indexableObject: mockItem as Item, - hitHighlights: new MetadataMap() -} as ItemSearchResult; - -describe('TypedItemSearchResultListElementComponent', () => { - let comp: TypedItemSearchResultListElementComponent; - let fixture: ComponentFixture; - - describe('when injecting an Item', () => { - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [TypedItemSearchResultListElementComponent, TruncatePipe], - providers: [ - {provide: TruncatableService, useValue: {}}, - {provide: ITEM, useValue: mockItem} - ], - - schemas: [NO_ERRORS_SCHEMA] - }).overrideComponent(TypedItemSearchResultListElementComponent, { - set: {changeDetection: ChangeDetectionStrategy.Default} - }).compileComponents(); - })); - - beforeEach(async(() => { - fixture = TestBed.createComponent(TypedItemSearchResultListElementComponent); - comp = fixture.componentInstance; - })); - - it('should initiate item, object and dso correctly', () => { - expect(comp.item).toBe(mockItem); - expect(comp.dso).toBe(mockItem); - expect(comp.object.indexableObject).toBe(mockItem); - }) - }); - - describe('when injecting an ItemSearchResult', () => { - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [TypedItemSearchResultListElementComponent, TruncatePipe], - providers: [ - {provide: TruncatableService, useValue: {}}, - {provide: ITEM, useValue: mockSearchResult} - ], - - schemas: [NO_ERRORS_SCHEMA] - }).overrideComponent(TypedItemSearchResultListElementComponent, { - set: {changeDetection: ChangeDetectionStrategy.Default} - }).compileComponents(); - })); - - beforeEach(async(() => { - fixture = TestBed.createComponent(TypedItemSearchResultListElementComponent); - comp = fixture.componentInstance; - })); - - it('should initiate item, object and dso correctly', () => { - expect(comp.item).toBe(mockItem); - expect(comp.dso).toBe(mockItem); - expect(comp.object.indexableObject).toBe(mockItem); - }) - }); -}); diff --git a/src/app/shared/object-list/item-list-element/item-types/typed-item-search-result-list-element.component.ts b/src/app/shared/object-list/item-list-element/item-types/typed-item-search-result-list-element.component.ts deleted file mode 100644 index dd1b5a7e5f..0000000000 --- a/src/app/shared/object-list/item-list-element/item-types/typed-item-search-result-list-element.component.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Component, Inject } from '@angular/core'; -import { Item } from '../../../../core/shared/item.model'; -import { hasValue } from '../../../empty.util'; -import { ITEM } from '../../../items/switcher/item-type-switcher.component'; -import { ItemSearchResult } from '../../../object-collection/shared/item-search-result.model'; -import { TruncatableService } from '../../../truncatable/truncatable.service'; -import { SearchResultListElementComponent } from '../../search-result-list-element/search-result-list-element.component'; -import { MetadataMap } from '../../../../core/shared/metadata.models'; - -/** - * A generic component for displaying item list elements - */ -@Component({ - selector: 'ds-item-search-result-list-element', - template: '' -}) -export class TypedItemSearchResultListElementComponent extends SearchResultListElementComponent { - item: Item; - - constructor( - protected truncatableService: TruncatableService, - @Inject(ITEM) public obj: Item | ItemSearchResult, - ) { - super(undefined, truncatableService); - if (hasValue((obj as any).indexableObject)) { - this.object = obj as ItemSearchResult; - this.dso = this.object.indexableObject; - } else { - this.object = { - indexableObject: obj as Item, - hitHighlights: new MetadataMap() - }; - this.dso = obj as Item; - } - this.item = this.dso; - } -} diff --git a/src/app/shared/object-list/item-type-badge/item-type-badge.component.html b/src/app/shared/object-list/item-type-badge/item-type-badge.component.html index 35d7663801..947970b7e1 100644 --- a/src/app/shared/object-list/item-type-badge/item-type-badge.component.html +++ b/src/app/shared/object-list/item-type-badge/item-type-badge.component.html @@ -1,3 +1,3 @@ -
+
{{ type.toLowerCase() + '.listelement.badge' | translate }}
diff --git a/src/app/shared/object-list/item-type-badge/item-type-badge.component.spec.ts b/src/app/shared/object-list/item-type-badge/item-type-badge.component.spec.ts index 04c40b73ff..f75a49363f 100644 --- a/src/app/shared/object-list/item-type-badge/item-type-badge.component.spec.ts +++ b/src/app/shared/object-list/item-type-badge/item-type-badge.component.spec.ts @@ -13,10 +13,8 @@ let fixture: ComponentFixture; const type = 'authorOfPublication'; -const mockItemWithRelationshipType: ItemSearchResult = new ItemSearchResult(); -mockItemWithRelationshipType.hitHighlights = {}; -mockItemWithRelationshipType.indexableObject = Object.assign(new Item(), { - bitstreams: observableOf({}), +const mockItemWithRelationshipType = Object.assign(new Item(), { + bundles: observableOf({}), metadata: { 'relationship.type': [ { @@ -27,10 +25,8 @@ mockItemWithRelationshipType.indexableObject = Object.assign(new Item(), { } }); -const mockItemWithoutRelationshipType: ItemSearchResult = new ItemSearchResult(); -mockItemWithoutRelationshipType.hitHighlights = {}; -mockItemWithoutRelationshipType.indexableObject = Object.assign(new Item(), { - bitstreams: observableOf({}), +const mockItemWithoutRelationshipType = Object.assign(new Item(), { + bundles: observableOf({}), metadata: { 'dc.title': [ { diff --git a/src/app/shared/object-list/item-type-badge/item-type-badge.component.ts b/src/app/shared/object-list/item-type-badge/item-type-badge.component.ts index 9ffba33758..5518ede202 100644 --- a/src/app/shared/object-list/item-type-badge/item-type-badge.component.ts +++ b/src/app/shared/object-list/item-type-badge/item-type-badge.component.ts @@ -7,6 +7,12 @@ import { DSpaceObject } from '../../../core/shared/dspace-object.model'; selector: 'ds-item-type-badge', templateUrl: './item-type-badge.component.html' }) +/** + * Component rendering the type of an item as a badge + */ export class ItemTypeBadgeComponent { - @Input() object: SearchResult; + /** + * The component used to retrieve the type from + */ + @Input() object: DSpaceObject; } diff --git a/src/app/shared/object-list/metadata-representation-list-element/item/item-metadata-list-element.component.html b/src/app/shared/object-list/metadata-representation-list-element/item/item-metadata-list-element.component.html index 764fdc1064..91219c7189 100644 --- a/src/app/shared/object-list/metadata-representation-list-element/item/item-metadata-list-element.component.html +++ b/src/app/shared/object-list/metadata-representation-list-element/item/item-metadata-list-element.component.html @@ -1,2 +1 @@ - - + diff --git a/src/app/shared/object-list/metadata-representation-list-element/item/item-metadata-list-element.component.spec.ts b/src/app/shared/object-list/metadata-representation-list-element/item/item-metadata-list-element.component.spec.ts index 269207bef8..c195268456 100644 --- a/src/app/shared/object-list/metadata-representation-list-element/item/item-metadata-list-element.component.spec.ts +++ b/src/app/shared/object-list/metadata-representation-list-element/item/item-metadata-list-element.component.spec.ts @@ -1,5 +1,4 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { ITEM } from '../../../items/switcher/item-type-switcher.component'; import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; import { ItemMetadataListElementComponent } from './item-metadata-list-element.component'; import { By } from '@angular/platform-browser'; @@ -15,9 +14,6 @@ describe('ItemMetadataListElementComponent', () => { TestBed.configureTestingModule({ imports: [], declarations: [ItemMetadataListElementComponent], - providers: [ - { provide: ITEM, useValue: mockItemMetadataRepresentation } - ], schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(ItemMetadataListElementComponent, { set: {changeDetection: ChangeDetectionStrategy.Default} @@ -27,12 +23,13 @@ describe('ItemMetadataListElementComponent', () => { beforeEach(async(() => { fixture = TestBed.createComponent(ItemMetadataListElementComponent); comp = fixture.componentInstance; + comp.metadataRepresentation = mockItemMetadataRepresentation; fixture.detectChanges(); })); - it('should call an item-type-switcher component and pass the item-metadata-representation', () => { - const itemTypeSwitcher = fixture.debugElement.query(By.css('ds-item-type-switcher')).nativeElement; - expect(itemTypeSwitcher.object).toBe(mockItemMetadataRepresentation); + it('should call a listable-object-component-loader component and pass the item-metadata-representation', () => { + const objectLoader = fixture.debugElement.query(By.css('ds-listable-object-component-loader')).nativeElement; + expect(objectLoader.object).toBe(mockItemMetadataRepresentation); }); }); diff --git a/src/app/shared/object-list/metadata-representation-list-element/item/item-metadata-list-element.component.ts b/src/app/shared/object-list/metadata-representation-list-element/item/item-metadata-list-element.component.ts index 084567a885..3be16bcb5e 100644 --- a/src/app/shared/object-list/metadata-representation-list-element/item/item-metadata-list-element.component.ts +++ b/src/app/shared/object-list/metadata-representation-list-element/item/item-metadata-list-element.component.ts @@ -1,9 +1,10 @@ import { MetadataRepresentationType } from '../../../../core/shared/metadata-representation/metadata-representation.model'; import { Component } from '@angular/core'; import { MetadataRepresentationListElementComponent } from '../metadata-representation-list-element.component'; -import { DEFAULT_ITEM_TYPE, ItemViewMode, rendersItemType } from '../../../items/item-type-decorator'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; +import { metadataRepresentationComponent } from '../../../metadata-representation/metadata-representation.decorator'; -@rendersItemType(DEFAULT_ITEM_TYPE, ItemViewMode.Metadata, MetadataRepresentationType.Item) +@metadataRepresentationComponent('Publication', MetadataRepresentationType.Item) @Component({ selector: 'ds-item-metadata-list-element', templateUrl: './item-metadata-list-element.component.html' @@ -16,7 +17,7 @@ import { DEFAULT_ITEM_TYPE, ItemViewMode, rendersItemType } from '../../../items export class ItemMetadataListElementComponent extends MetadataRepresentationListElementComponent { /** * The view-mode we're currently on - * @type {ElementViewMode} + * @type {ViewMode} */ - viewMode = ItemViewMode.Element; + viewMode = ViewMode.ListElement; } diff --git a/src/app/shared/object-list/metadata-representation-list-element/item/item-metadata-representation-list-element.component.ts b/src/app/shared/object-list/metadata-representation-list-element/item/item-metadata-representation-list-element.component.ts index 0fdca0d429..6c4d300e99 100644 --- a/src/app/shared/object-list/metadata-representation-list-element/item/item-metadata-representation-list-element.component.ts +++ b/src/app/shared/object-list/metadata-representation-list-element/item/item-metadata-representation-list-element.component.ts @@ -1,6 +1,5 @@ import { MetadataRepresentationListElementComponent } from '../metadata-representation-list-element.component'; -import { Component, Inject } from '@angular/core'; -import { ITEM } from '../../../items/switcher/item-type-switcher.component'; +import { Component } from '@angular/core'; import { ItemMetadataRepresentation } from '../../../../core/shared/metadata-representation/item/item-metadata-representation.model'; @Component({ @@ -11,7 +10,5 @@ import { ItemMetadataRepresentation } from '../../../../core/shared/metadata-rep * An abstract class for displaying a single ItemMetadataRepresentation */ export class ItemMetadataRepresentationListElementComponent extends MetadataRepresentationListElementComponent { - constructor(@Inject(ITEM) public metadataRepresentation: ItemMetadataRepresentation) { - super(metadataRepresentation); - } + metadataRepresentation: ItemMetadataRepresentation; } diff --git a/src/app/shared/object-list/metadata-representation-list-element/metadata-representation-list-element.component.ts b/src/app/shared/object-list/metadata-representation-list-element/metadata-representation-list-element.component.ts index 2488db50b1..2e14485fbb 100644 --- a/src/app/shared/object-list/metadata-representation-list-element/metadata-representation-list-element.component.ts +++ b/src/app/shared/object-list/metadata-representation-list-element/metadata-representation-list-element.component.ts @@ -1,6 +1,5 @@ -import { Component, Inject } from '@angular/core'; +import { Component } from '@angular/core'; import { MetadataRepresentation } from '../../../core/shared/metadata-representation/metadata-representation.model'; -import { ITEM } from '../../items/switcher/item-type-switcher.component'; @Component({ selector: 'ds-metadata-representation-list-element', @@ -10,6 +9,8 @@ import { ITEM } from '../../items/switcher/item-type-switcher.component'; * An abstract class for displaying a single MetadataRepresentation */ export class MetadataRepresentationListElementComponent { - constructor(@Inject(ITEM) public metadataRepresentation: MetadataRepresentation) { - } + /** + * The metadata representation of this component + */ + metadataRepresentation: MetadataRepresentation; } diff --git a/src/app/shared/object-list/metadata-representation-list-element/plain-text/plain-text-metadata-list-element.component.spec.ts b/src/app/shared/object-list/metadata-representation-list-element/plain-text/plain-text-metadata-list-element.component.spec.ts index 42b9abde16..9a409aa147 100644 --- a/src/app/shared/object-list/metadata-representation-list-element/plain-text/plain-text-metadata-list-element.component.spec.ts +++ b/src/app/shared/object-list/metadata-representation-list-element/plain-text/plain-text-metadata-list-element.component.spec.ts @@ -2,7 +2,6 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; import { PlainTextMetadataListElementComponent } from './plain-text-metadata-list-element.component'; import { MetadatumRepresentation } from '../../../../core/shared/metadata-representation/metadatum/metadatum-representation.model'; -import { ITEM } from '../../../items/switcher/item-type-switcher.component'; const mockMetadataRepresentation = Object.assign(new MetadatumRepresentation('type'), { key: 'dc.contributor.author', @@ -17,9 +16,6 @@ describe('PlainTextMetadataListElementComponent', () => { TestBed.configureTestingModule({ imports: [], declarations: [PlainTextMetadataListElementComponent], - providers: [ - { provide: ITEM, useValue: mockMetadataRepresentation } - ], schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(PlainTextMetadataListElementComponent, { set: {changeDetection: ChangeDetectionStrategy.Default} @@ -29,6 +25,7 @@ describe('PlainTextMetadataListElementComponent', () => { beforeEach(async(() => { fixture = TestBed.createComponent(PlainTextMetadataListElementComponent); comp = fixture.componentInstance; + comp.metadataRepresentation = mockMetadataRepresentation; fixture.detectChanges(); })); diff --git a/src/app/shared/object-list/metadata-representation-list-element/plain-text/plain-text-metadata-list-element.component.ts b/src/app/shared/object-list/metadata-representation-list-element/plain-text/plain-text-metadata-list-element.component.ts index 7c4785e37c..198c3712d9 100644 --- a/src/app/shared/object-list/metadata-representation-list-element/plain-text/plain-text-metadata-list-element.component.ts +++ b/src/app/shared/object-list/metadata-representation-list-element/plain-text/plain-text-metadata-list-element.component.ts @@ -1,11 +1,11 @@ import { MetadataRepresentationType } from '../../../../core/shared/metadata-representation/metadata-representation.model'; import { Component } from '@angular/core'; import { MetadataRepresentationListElementComponent } from '../metadata-representation-list-element.component'; -import { DEFAULT_ITEM_TYPE, ItemViewMode, rendersItemType } from '../../../items/item-type-decorator'; +import { metadataRepresentationComponent } from '../../../metadata-representation/metadata-representation.decorator'; -@rendersItemType(DEFAULT_ITEM_TYPE, ItemViewMode.Metadata, MetadataRepresentationType.PlainText) +@metadataRepresentationComponent('Publication', MetadataRepresentationType.PlainText) // For now, authority controlled fields are rendered the same way as plain text fields -@rendersItemType(DEFAULT_ITEM_TYPE, ItemViewMode.Metadata, MetadataRepresentationType.AuthorityControlled) +@metadataRepresentationComponent('Publication', MetadataRepresentationType.AuthorityControlled) @Component({ selector: 'ds-plain-text-metadata-list-element', templateUrl: './plain-text-metadata-list-element.component.html' diff --git a/src/app/shared/object-list/my-dspace-result-list-element/claimed-my-dspace-result/claimed-my-dspace-result-list-element.component.html b/src/app/shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-search-result-list-element.component.html similarity index 100% rename from src/app/shared/object-list/my-dspace-result-list-element/claimed-my-dspace-result/claimed-my-dspace-result-list-element.component.html rename to src/app/shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-search-result-list-element.component.html diff --git a/src/app/shared/object-list/my-dspace-result-list-element/claimed-my-dspace-result/claimed-my-dspace-result-list-element.component.spec.ts b/src/app/shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-search-result-list-element.component.spec.ts similarity index 70% rename from src/app/shared/object-list/my-dspace-result-list-element/claimed-my-dspace-result/claimed-my-dspace-result-list-element.component.spec.ts rename to src/app/shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-search-result-list-element.component.spec.ts index 5815cd5401..d6b8c4c8fb 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/claimed-my-dspace-result/claimed-my-dspace-result-list-element.component.spec.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-search-result-list-element.component.spec.ts @@ -5,24 +5,25 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { of as observableOf } from 'rxjs'; import { Item } from '../../../../core/shared/item.model'; -import { ClaimedMyDSpaceResultListElementComponent } from './claimed-my-dspace-result-list-element.component'; -import { ClaimedTaskMyDSpaceResult } from '../../../object-collection/shared/claimed-task-my-dspace-result.model'; +import { ClaimedSearchResultListElementComponent } from './claimed-search-result-list-element.component'; import { ClaimedTask } from '../../../../core/tasks/models/claimed-task-object.model'; -import { RemoteData } from '../../../../core/data/remote-data'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model'; import { createSuccessfulRemoteDataObject } from '../../../testing/utils'; +import { ClaimedTaskSearchResult } from '../../../object-collection/shared/claimed-task-search-result.model'; +import { TruncatableAction } from '../../../truncatable/truncatable.actions'; +import { TruncatableService } from '../../../truncatable/truncatable.service'; -let component: ClaimedMyDSpaceResultListElementComponent; -let fixture: ComponentFixture; +let component: ClaimedSearchResultListElementComponent; +let fixture: ComponentFixture; const compIndex = 1; -const mockResultObject: ClaimedTaskMyDSpaceResult = new ClaimedTaskMyDSpaceResult(); +const mockResultObject: ClaimedTaskSearchResult = new ClaimedTaskSearchResult(); mockResultObject.hitHighlights = {}; const item = Object.assign(new Item(), { - bitstreams: observableOf({}), + bundles: observableOf({}), metadata: { 'dc.title': [ { @@ -55,23 +56,22 @@ const workflowitem = Object.assign(new WorkflowItem(), { item: observableOf(rdIt const rdWorkflowitem = createSuccessfulRemoteDataObject(workflowitem); mockResultObject.indexableObject = Object.assign(new ClaimedTask(), { workflowitem: observableOf(rdWorkflowitem) }); -describe('ClaimedMyDSpaceResultListElementComponent', () => { +describe('ClaimedSearchResultListElementComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [NoopAnimationsModule], - declarations: [ClaimedMyDSpaceResultListElementComponent], + declarations: [ClaimedSearchResultListElementComponent], providers: [ - { provide: 'objectElementProvider', useValue: (mockResultObject) }, - { provide: 'indexElementProvider', useValue: (compIndex) } + { provide: TruncatableService, useValue: {} }, ], schemas: [NO_ERRORS_SCHEMA] - }).overrideComponent(ClaimedMyDSpaceResultListElementComponent, { + }).overrideComponent(ClaimedSearchResultListElementComponent, { set: { changeDetection: ChangeDetectionStrategy.Default } }).compileComponents(); })); beforeEach(async(() => { - fixture = TestBed.createComponent(ClaimedMyDSpaceResultListElementComponent); + fixture = TestBed.createComponent(ClaimedSearchResultListElementComponent); component = fixture.componentInstance; })); diff --git a/src/app/shared/object-list/my-dspace-result-list-element/claimed-my-dspace-result/claimed-my-dspace-result-list-element.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-search-result-list-element.component.ts similarity index 64% rename from src/app/shared/object-list/my-dspace-result-list-element/claimed-my-dspace-result/claimed-my-dspace-result-list-element.component.ts rename to src/app/shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-search-result-list-element.component.ts index 3423df7009..35371f40aa 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/claimed-my-dspace-result/claimed-my-dspace-result-list-element.component.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/claimed-search-result/claimed-search-result-list-element.component.ts @@ -4,30 +4,28 @@ import { Location, LocationStrategy, PathLocationStrategy } from '@angular/commo import { Observable } from 'rxjs'; import { find } from 'rxjs/operators'; -import { renderElementsFor } from '../../../object-collection/shared/dso-element-decorator'; -import { MyDSpaceResultListElementComponent, } from '../my-dspace-result-list-element.component'; import { ViewMode } from '../../../../core/shared/view-mode.model'; import { RemoteData } from '../../../../core/data/remote-data'; import { isNotUndefined } from '../../../empty.util'; import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model'; import { ClaimedTask } from '../../../../core/tasks/models/claimed-task-object.model'; -import { ClaimedTaskMyDSpaceResult } from '../../../object-collection/shared/claimed-task-my-dspace-result.model'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; -import { SetViewMode } from '../../../view-mode'; +import { listableObjectComponent } from '../../../object-collection/shared/listable-object/listable-object.decorator'; +import { ClaimedTaskSearchResult } from '../../../object-collection/shared/claimed-task-search-result.model'; +import { SearchResultListElementComponent } from '../../search-result-list-element/search-result-list-element.component'; /** - * This component renders claimed task object for the mydspace result in the list view. + * This component renders claimed task object for the search result in the list view. */ @Component({ - selector: 'ds-claimed-my-dspace-result-list-element', - styleUrls: ['../my-dspace-result-list-element.component.scss'], - templateUrl: './claimed-my-dspace-result-list-element.component.html', + selector: 'ds-claimed-search-result-list-element', + styleUrls: ['../../search-result-list-element/search-result-list-element.component.scss'], + templateUrl: './claimed-search-result-list-element.component.html', providers: [Location, { provide: LocationStrategy, useClass: PathLocationStrategy }] }) -@renderElementsFor(ClaimedTaskMyDSpaceResult, SetViewMode.List) -@renderElementsFor(ClaimedTask, SetViewMode.List) -export class ClaimedMyDSpaceResultListElementComponent extends MyDSpaceResultListElementComponent { +@listableObjectComponent(ClaimedTaskSearchResult, ViewMode.ListElement) +export class ClaimedSearchResultListElementComponent extends SearchResultListElementComponent { /** * A boolean representing if to show submitter information @@ -48,6 +46,7 @@ export class ClaimedMyDSpaceResultListElementComponent extends MyDSpaceResultLis * Initialize all instance variables */ ngOnInit() { + super.ngOnInit(); this.initWorkflowItem(this.dso.workflowitem as Observable>); } diff --git a/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.spec.ts b/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.spec.ts index 17b0279c7a..eb531d2f93 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.spec.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.spec.ts @@ -14,7 +14,7 @@ let component: ItemListPreviewComponent; let fixture: ComponentFixture; const mockItemWithAuthorAndDate: Item = Object.assign(new Item(), { - bitstreams: observableOf({}), + bundles: observableOf({}), metadata: { 'dc.contributor.author': [ { @@ -31,7 +31,7 @@ const mockItemWithAuthorAndDate: Item = Object.assign(new Item(), { } }); const mockItemWithoutAuthorAndDate: Item = Object.assign(new Item(), { - bitstreams: observableOf({}), + bundles: observableOf({}), metadata: { 'dc.title': [ { diff --git a/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.ts index 13876ab46a..0395c8c84b 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/item-list-preview/item-list-preview.component.ts @@ -3,7 +3,7 @@ import { Component, Input } from '@angular/core'; import { Item } from '../../../../core/shared/item.model'; import { fadeInOut } from '../../../animations/fade'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; -import { MyDSpaceResult } from '../../../../+my-dspace-page/my-dspace-result.model'; +import { SearchResult } from '../../../../+search-page/search-result.model'; /** * This component show metadata for the given item object in the list view. @@ -22,9 +22,9 @@ export class ItemListPreviewComponent { @Input() item: Item; /** - * The mydspace result object + * The search result object */ - @Input() object: MyDSpaceResult; + @Input() object: SearchResult; /** * Represent item's status diff --git a/src/app/shared/object-list/my-dspace-result-list-element/item-my-dspace-result/item-my-dspace-result-list-element.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/item-my-dspace-result/item-my-dspace-result-list-element.component.ts deleted file mode 100644 index 3f2a439603..0000000000 --- a/src/app/shared/object-list/my-dspace-result-list-element/item-my-dspace-result/item-my-dspace-result-list-element.component.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Component } from '@angular/core'; - -import { renderElementsFor } from '../../../object-collection/shared/dso-element-decorator'; -import { MyDSpaceResultListElementComponent, } from '../my-dspace-result-list-element.component'; -import { Item } from '../../../../core/shared/item.model'; -import { ItemMyDSpaceResult } from '../../../object-collection/shared/item-my-dspace-result.model'; -import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; -import { SetViewMode } from '../../../view-mode'; - -/** - * This component renders item object for the mydspace result in the list view. - */ -@Component({ - selector: 'ds-workspaceitem-my-dspace-result-list-element', - styleUrls: ['../my-dspace-result-list-element.component.scss', './item-my-dspace-result-list-element.component.scss'], - templateUrl: './item-my-dspace-result-list-element.component.html' -}) - -@renderElementsFor(ItemMyDSpaceResult, SetViewMode.List) -export class ItemMyDSpaceResultListElementComponent extends MyDSpaceResultListElementComponent { - - /** - * Represent item's status - */ - public status = MyDspaceItemStatusType.ARCHIVED; - -} diff --git a/src/app/shared/object-list/my-dspace-result-list-element/item-my-dspace-result/item-my-dspace-result-list-element.component.html b/src/app/shared/object-list/my-dspace-result-list-element/item-search-result/item-search-result-list-element-submission.component.html similarity index 100% rename from src/app/shared/object-list/my-dspace-result-list-element/item-my-dspace-result/item-my-dspace-result-list-element.component.html rename to src/app/shared/object-list/my-dspace-result-list-element/item-search-result/item-search-result-list-element-submission.component.html diff --git a/src/app/shared/object-list/my-dspace-result-list-element/item-my-dspace-result/item-my-dspace-result-list-element.component.scss b/src/app/shared/object-list/my-dspace-result-list-element/item-search-result/item-search-result-list-element-submission.component.scss similarity index 100% rename from src/app/shared/object-list/my-dspace-result-list-element/item-my-dspace-result/item-my-dspace-result-list-element.component.scss rename to src/app/shared/object-list/my-dspace-result-list-element/item-search-result/item-search-result-list-element-submission.component.scss diff --git a/src/app/shared/object-list/my-dspace-result-list-element/item-my-dspace-result/item-my-dspace-result-list-element.component.spec.ts b/src/app/shared/object-list/my-dspace-result-list-element/item-search-result/item-search-result-list-element-submission.component.spec.ts similarity index 66% rename from src/app/shared/object-list/my-dspace-result-list-element/item-my-dspace-result/item-my-dspace-result-list-element.component.spec.ts rename to src/app/shared/object-list/my-dspace-result-list-element/item-search-result/item-search-result-list-element-submission.component.spec.ts index ea4f2d24f3..45af23320f 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/item-my-dspace-result/item-my-dspace-result-list-element.component.spec.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/item-search-result/item-search-result-list-element-submission.component.spec.ts @@ -5,20 +5,21 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { of as observableOf } from 'rxjs'; import { Item } from '../../../../core/shared/item.model'; -import { ItemMyDSpaceResultListElementComponent } from './item-my-dspace-result-list-element.component'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; -import { ItemMyDSpaceResult } from '../../../object-collection/shared/item-my-dspace-result.model'; +import { ItemSearchResult } from '../../../object-collection/shared/item-search-result.model'; +import { ItemSearchResultListElementSubmissionComponent } from './item-search-result-list-element-submission.component'; +import { TruncatableService } from '../../../truncatable/truncatable.service'; -let component: ItemMyDSpaceResultListElementComponent; -let fixture: ComponentFixture; +let component: ItemSearchResultListElementSubmissionComponent; +let fixture: ComponentFixture; const compIndex = 1; -const mockResultObject: ItemMyDSpaceResult = new ItemMyDSpaceResult(); +const mockResultObject: ItemSearchResult = new ItemSearchResult(); mockResultObject.hitHighlights = {}; mockResultObject.indexableObject = Object.assign(new Item(), { - bitstreams: observableOf({}), + bundles: observableOf({}), metadata: { 'dc.title': [ { @@ -51,19 +52,18 @@ describe('ItemMyDSpaceResultListElementComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [NoopAnimationsModule], - declarations: [ItemMyDSpaceResultListElementComponent], + declarations: [ItemSearchResultListElementSubmissionComponent], providers: [ - { provide: 'objectElementProvider', useValue: (mockResultObject) }, - { provide: 'indexElementProvider', useValue: (compIndex) } + { provide: TruncatableService, useValue: {} }, ], schemas: [NO_ERRORS_SCHEMA] - }).overrideComponent(ItemMyDSpaceResultListElementComponent, { + }).overrideComponent(ItemSearchResultListElementSubmissionComponent, { set: { changeDetection: ChangeDetectionStrategy.Default } }).compileComponents(); })); beforeEach(async(() => { - fixture = TestBed.createComponent(ItemMyDSpaceResultListElementComponent); + fixture = TestBed.createComponent(ItemSearchResultListElementSubmissionComponent); component = fixture.componentInstance; })); diff --git a/src/app/shared/object-list/my-dspace-result-list-element/item-search-result/item-search-result-list-element-submission.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/item-search-result/item-search-result-list-element-submission.component.ts new file mode 100644 index 0000000000..3ef45d1c47 --- /dev/null +++ b/src/app/shared/object-list/my-dspace-result-list-element/item-search-result/item-search-result-list-element-submission.component.ts @@ -0,0 +1,31 @@ +import { Component, OnInit } from '@angular/core'; + +import { Item } from '../../../../core/shared/item.model'; +import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; +import { listableObjectComponent } from '../../../object-collection/shared/listable-object/listable-object.decorator'; +import { Context } from '../../../../core/shared/context.model'; +import { ItemSearchResult } from '../../../object-collection/shared/item-search-result.model'; +import { SearchResultListElementComponent } from '../../search-result-list-element/search-result-list-element.component'; + +/** + * This component renders item object for the search result in the list view for submission. + */ +@Component({ + selector: 'ds-item-search-result-list-element-submission', + styleUrls: ['../../search-result-list-element/search-result-list-element.component.scss', './item-search-result-list-element-submission.component.scss'], + templateUrl: './item-search-result-list-element-submission.component.html' +}) + +@listableObjectComponent(ItemSearchResult, ViewMode.ListElement, Context.Workspace) +@listableObjectComponent(ItemSearchResult, ViewMode.ListElement, Context.Workflow) +export class ItemSearchResultListElementSubmissionComponent extends SearchResultListElementComponent implements OnInit { + /** + * Represent item's status + */ + public status = MyDspaceItemStatusType.ARCHIVED; + + ngOnInit() { + super.ngOnInit(); + } +} diff --git a/src/app/shared/object-list/my-dspace-result-list-element/my-dspace-result-list-element.component.scss b/src/app/shared/object-list/my-dspace-result-list-element/my-dspace-result-list-element.component.scss deleted file mode 100644 index 4cd8a2b697..0000000000 --- a/src/app/shared/object-list/my-dspace-result-list-element/my-dspace-result-list-element.component.scss +++ /dev/null @@ -1 +0,0 @@ -@import '../search-result-list-element/search-result-list-element.component.scss'; diff --git a/src/app/shared/object-list/my-dspace-result-list-element/my-dspace-result-list-element.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/my-dspace-result-list-element.component.ts deleted file mode 100644 index b2a5bf14fd..0000000000 --- a/src/app/shared/object-list/my-dspace-result-list-element/my-dspace-result-list-element.component.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { Component, Inject } from '@angular/core'; - -import { MyDSpaceResult } from '../../../+my-dspace-page/my-dspace-result.model'; -import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component'; -import { ListableObject } from '../../object-collection/shared/listable-object.model'; -import { DSpaceObject } from '../../../core/shared/dspace-object.model'; -import { Metadata } from '../../../core/shared/metadata.utils'; - -@Component({ - selector: 'ds-my-dspace-result-list-element', - template: `` -}) -export class MyDSpaceResultListElementComponent, K extends DSpaceObject> extends AbstractListableElementComponent { - - /** - * The result element object - */ - dso: K; - - /** - * The array index of the result element - */ - dsoIndex: number; - - /** - * Initialize instance variables - * - * @param {ListableObject} listable - * @param {number} index - */ - public constructor(@Inject('objectElementProvider') public listable: ListableObject, - @Inject('indexElementProvider') public index: number) { - super(listable); - this.dso = this.object.indexableObject; - this.dsoIndex = this.index; - } - - /** - * Gets all matching metadata string values from hitHighlights or dso metadata, preferring hitHighlights. - * - * @param {string|string[]} keyOrKeys The metadata key(s) in scope. Wildcards are supported; see [[Metadata]]. - * @returns {string[]} the matching string values or an empty array. - */ - allMetadataValues(keyOrKeys: string | string[]): string[] { - return Metadata.allValues([this.object.hitHighlights, this.dso.metadata], keyOrKeys); - } - - /** - * Gets the first matching metadata string value from hitHighlights or dso metadata, preferring hitHighlights. - * - * @param {string|string[]} keyOrKeys The metadata key(s) in scope. Wildcards are supported; see [[Metadata]]. - * @returns {string} the first matching string value, or `undefined`. - */ - firstMetadataValue(keyOrKeys: string | string[]): string { - return Metadata.firstValue([this.object.hitHighlights, this.dso.metadata], keyOrKeys); - } - -} diff --git a/src/app/shared/object-list/my-dspace-result-list-element/pool-my-dspace-result/pool-my-dspace-result-list-element.component.html b/src/app/shared/object-list/my-dspace-result-list-element/pool-search-result/pool-search-result-list-element.component.html similarity index 100% rename from src/app/shared/object-list/my-dspace-result-list-element/pool-my-dspace-result/pool-my-dspace-result-list-element.component.html rename to src/app/shared/object-list/my-dspace-result-list-element/pool-search-result/pool-search-result-list-element.component.html diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/pool-my-dspace-result/pool-my-dspace-result-detail-element.component.spec.ts b/src/app/shared/object-list/my-dspace-result-list-element/pool-search-result/pool-search-result-list-element.component.spec.ts similarity index 70% rename from src/app/shared/object-detail/my-dspace-result-detail-element/pool-my-dspace-result/pool-my-dspace-result-detail-element.component.spec.ts rename to src/app/shared/object-list/my-dspace-result-list-element/pool-search-result/pool-search-result-list-element.component.spec.ts index a031ac3a49..119870cf9c 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/pool-my-dspace-result/pool-my-dspace-result-detail-element.component.spec.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/pool-search-result/pool-search-result-list-element.component.spec.ts @@ -5,24 +5,24 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { of as observableOf } from 'rxjs'; import { Item } from '../../../../core/shared/item.model'; -import { PoolMyDSpaceResultDetailElementComponent } from './pool-my-dspace-result-detail-lement.component'; -import { PoolTaskMyDSpaceResult } from '../../../object-collection/shared/pool-task-my-dspace-result.model'; +import { PoolSearchResultListElementComponent } from './pool-search-result-list-element.component'; import { PoolTask } from '../../../../core/tasks/models/pool-task-object.model'; -import { RemoteData } from '../../../../core/data/remote-data'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model'; import { createSuccessfulRemoteDataObject } from '../../../testing/utils'; +import { PoolTaskSearchResult } from '../../../object-collection/shared/pool-task-search-result.model'; +import { TruncatableService } from '../../../truncatable/truncatable.service'; -let component: PoolMyDSpaceResultDetailElementComponent; -let fixture: ComponentFixture; +let component: PoolSearchResultListElementComponent; +let fixture: ComponentFixture; const compIndex = 1; -const mockResultObject: PoolTaskMyDSpaceResult = new PoolTaskMyDSpaceResult(); +const mockResultObject: PoolTaskSearchResult = new PoolTaskSearchResult(); mockResultObject.hitHighlights = {}; const item = Object.assign(new Item(), { - bitstreams: observableOf({}), + bundles: observableOf({}), metadata: { 'dc.title': [ { @@ -55,23 +55,22 @@ const workflowitem = Object.assign(new WorkflowItem(), { item: observableOf(rdIt const rdWorkflowitem = createSuccessfulRemoteDataObject(workflowitem); mockResultObject.indexableObject = Object.assign(new PoolTask(), { workflowitem: observableOf(rdWorkflowitem) }); -describe('PoolMyDSpaceResultDetailElementComponent', () => { +describe('PoolSearchResultListElementComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [NoopAnimationsModule], - declarations: [PoolMyDSpaceResultDetailElementComponent], + declarations: [PoolSearchResultListElementComponent], providers: [ - { provide: 'objectElementProvider', useValue: (mockResultObject) }, - { provide: 'indexElementProvider', useValue: (compIndex) } + { provide: TruncatableService, useValue: {} }, ], schemas: [NO_ERRORS_SCHEMA] - }).overrideComponent(PoolMyDSpaceResultDetailElementComponent, { + }).overrideComponent(PoolSearchResultListElementComponent, { set: { changeDetection: ChangeDetectionStrategy.Default } }).compileComponents(); })); beforeEach(async(() => { - fixture = TestBed.createComponent(PoolMyDSpaceResultDetailElementComponent); + fixture = TestBed.createComponent(PoolSearchResultListElementComponent); component = fixture.componentInstance; })); diff --git a/src/app/shared/object-list/my-dspace-result-list-element/pool-my-dspace-result/pool-my-dspace-result-list-element.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/pool-search-result/pool-search-result-list-element.component.ts similarity index 53% rename from src/app/shared/object-list/my-dspace-result-list-element/pool-my-dspace-result/pool-my-dspace-result-list-element.component.ts rename to src/app/shared/object-list/my-dspace-result-list-element/pool-search-result/pool-search-result-list-element.component.ts index 0b60c60dc1..b34e23c3e6 100644 --- a/src/app/shared/object-list/my-dspace-result-list-element/pool-my-dspace-result/pool-my-dspace-result-list-element.component.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/pool-search-result/pool-search-result-list-element.component.ts @@ -1,32 +1,30 @@ -import { Component, Inject, OnInit } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { Observable } from 'rxjs'; import { find } from 'rxjs/operators'; -import { renderElementsFor } from '../../../object-collection/shared/dso-element-decorator'; -import { MyDSpaceResultListElementComponent, } from '../my-dspace-result-list-element.component'; import { ViewMode } from '../../../../core/shared/view-mode.model'; import { RemoteData } from '../../../../core/data/remote-data'; import { isNotUndefined } from '../../../empty.util'; -import { ListableObject } from '../../../object-collection/shared/listable-object.model'; import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model'; import { PoolTask } from '../../../../core/tasks/models/pool-task-object.model'; -import { PoolTaskMyDSpaceResult } from '../../../object-collection/shared/pool-task-my-dspace-result.model'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; -import { SetViewMode } from '../../../view-mode'; +import { listableObjectComponent } from '../../../object-collection/shared/listable-object/listable-object.decorator'; +import { PoolTaskSearchResult } from '../../../object-collection/shared/pool-task-search-result.model'; +import { SearchResultListElementComponent } from '../../search-result-list-element/search-result-list-element.component'; +import { TruncatableService } from '../../../truncatable/truncatable.service'; /** - * This component renders pool task object for the mydspace result in the list view. + * This component renders pool task object for the search result in the list view. */ @Component({ - selector: 'ds-pool-my-dspace-result-list-element', - styleUrls: ['../my-dspace-result-list-element.component.scss'], - templateUrl: './pool-my-dspace-result-list-element.component.html', + selector: 'ds-pool-search-result-list-element', + styleUrls: ['../../search-result-list-element/search-result-list-element.component.scss'], + templateUrl: './pool-search-result-list-element.component.html', }) -@renderElementsFor(PoolTaskMyDSpaceResult, SetViewMode.List) -@renderElementsFor(PoolTask, SetViewMode.List) -export class PoolMyDSpaceResultListElementComponent extends MyDSpaceResultListElementComponent implements OnInit { +@listableObjectComponent(PoolTaskSearchResult, ViewMode.ListElement) +export class PoolSearchResultListElementComponent extends SearchResultListElementComponent implements OnInit { /** * A boolean representing if to show submitter information @@ -43,15 +41,20 @@ export class PoolMyDSpaceResultListElementComponent extends MyDSpaceResultListEl */ public workflowitem: WorkflowItem; - constructor(@Inject('objectElementProvider') public listable: ListableObject, - @Inject('indexElementProvider') public index: number) { - super(listable, index); + /** + * The index of this list element + */ + public index: number; + + constructor(protected truncatableService: TruncatableService) { + super(truncatableService); } /** * Initialize all instance variables */ ngOnInit() { + super.ngOnInit(); this.initWorkflowItem(this.dso.workflowitem as Observable>); } diff --git a/src/app/shared/object-list/my-dspace-result-list-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-list-element.component.html b/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.html similarity index 100% rename from src/app/shared/object-list/my-dspace-result-list-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-list-element.component.html rename to src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.html diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-detail-element.component.spec.ts b/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.spec.ts similarity index 65% rename from src/app/shared/object-detail/my-dspace-result-detail-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-detail-element.component.spec.ts rename to src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.spec.ts index 2a4b1321e2..f5521001ff 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/workflowitem-my-dspace-result/workflowitem-my-dspace-result-detail-element.component.spec.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.spec.ts @@ -5,23 +5,23 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { of as observableOf } from 'rxjs'; import { Item } from '../../../../core/shared/item.model'; -import { WorkflowitemMyDSpaceResultDetailElementComponent } from './workflowitem-my-dspace-result-detail-element.component'; -import { WorkflowitemMyDSpaceResult } from '../../../object-collection/shared/workflowitem-my-dspace-result.model'; import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model'; -import { RemoteData } from '../../../../core/data/remote-data'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; import { createSuccessfulRemoteDataObject } from '../../../testing/utils'; +import { WorkflowItemSearchResultListElementComponent } from './workflow-item-search-result-list-element.component'; +import { WorkflowItemSearchResult } from '../../../object-collection/shared/workflow-item-search-result.model'; +import { TruncatableService } from '../../../truncatable/truncatable.service'; -let component: WorkflowitemMyDSpaceResultDetailElementComponent; -let fixture: ComponentFixture; +let component: WorkflowItemSearchResultListElementComponent; +let fixture: ComponentFixture; const compIndex = 1; -const mockResultObject: WorkflowitemMyDSpaceResult = new WorkflowitemMyDSpaceResult(); +const mockResultObject: WorkflowItemSearchResult = new WorkflowItemSearchResult(); mockResultObject.hitHighlights = {}; const item = Object.assign(new Item(), { - bitstreams: observableOf({}), + bundles: observableOf({}), metadata: { 'dc.title': [ { @@ -52,23 +52,22 @@ const item = Object.assign(new Item(), { const rd = createSuccessfulRemoteDataObject(item); mockResultObject.indexableObject = Object.assign(new WorkflowItem(), { item: observableOf(rd) }); -describe('WorkflowitemMyDSpaceResultDetailElementComponent', () => { +describe('WorkflowItemSearchResultListElementComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [NoopAnimationsModule], - declarations: [WorkflowitemMyDSpaceResultDetailElementComponent], + declarations: [WorkflowItemSearchResultListElementComponent], providers: [ - { provide: 'objectElementProvider', useValue: (mockResultObject) }, - { provide: 'indexElementProvider', useValue: (compIndex) } + { provide: TruncatableService, useValue: {} }, ], schemas: [NO_ERRORS_SCHEMA] - }).overrideComponent(WorkflowitemMyDSpaceResultDetailElementComponent, { + }).overrideComponent(WorkflowItemSearchResultListElementComponent, { set: { changeDetection: ChangeDetectionStrategy.Default } }).compileComponents(); })); beforeEach(async(() => { - fixture = TestBed.createComponent(WorkflowitemMyDSpaceResultDetailElementComponent); + fixture = TestBed.createComponent(WorkflowItemSearchResultListElementComponent); component = fixture.componentInstance; })); diff --git a/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.ts new file mode 100644 index 0000000000..faf03425f0 --- /dev/null +++ b/src/app/shared/object-list/my-dspace-result-list-element/workflow-item-search-result/workflow-item-search-result-list-element.component.ts @@ -0,0 +1,57 @@ +import { Component } from '@angular/core'; + +import { Observable } from 'rxjs'; +import { find } from 'rxjs/operators'; + +import { ViewMode } from '../../../../core/shared/view-mode.model'; +import { RemoteData } from '../../../../core/data/remote-data'; +import { isNotUndefined } from '../../../empty.util'; +import { WorkflowItem } from '../../../../core/submission/models/workflowitem.model'; +import { Item } from '../../../../core/shared/item.model'; +import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; +import { listableObjectComponent } from '../../../object-collection/shared/listable-object/listable-object.decorator'; +import { WorkflowItemSearchResult } from '../../../object-collection/shared/workflow-item-search-result.model'; +import { SearchResultListElementComponent } from '../../search-result-list-element/search-result-list-element.component'; + +/** + * This component renders workflowitem object for the search result in the list view. + */ +@Component({ + selector: 'ds-workflow-item-my-dspace-result-list-element', + styleUrls: ['../../search-result-list-element/search-result-list-element.component.scss'], + templateUrl: './workflow-item-search-result-list-element.component.html', +}) + +@listableObjectComponent(WorkflowItemSearchResult, ViewMode.ListElement) +export class WorkflowItemSearchResultListElementComponent extends SearchResultListElementComponent { + + /** + * The item object that belonging to the result object + */ + public item: Item; + + /** + * Represent item's status + */ + public status = MyDspaceItemStatusType.WORKFLOW; + + /** + * Initialize all instance variables + */ + ngOnInit() { + super.ngOnInit(); + this.initItem(this.dso.item as Observable> ); + } + + /** + * Retrieve item from result object + */ + initItem(item$: Observable>) { + item$.pipe( + find((rd: RemoteData) => rd.hasSucceeded && isNotUndefined(rd.payload)) + ).subscribe((rd: RemoteData) => { + this.item = rd.payload; + }); + } + +} diff --git a/src/app/shared/object-list/my-dspace-result-list-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component.html b/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.html similarity index 100% rename from src/app/shared/object-list/my-dspace-result-list-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component.html rename to src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.html diff --git a/src/app/shared/object-list/my-dspace-result-list-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component.scss b/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.scss similarity index 100% rename from src/app/shared/object-list/my-dspace-result-list-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-list-element.component.scss rename to src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.scss diff --git a/src/app/shared/object-detail/my-dspace-result-detail-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component.spec.ts b/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.spec.ts similarity index 65% rename from src/app/shared/object-detail/my-dspace-result-detail-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component.spec.ts rename to src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.spec.ts index 0e16b9c0f6..faf4a3b1be 100644 --- a/src/app/shared/object-detail/my-dspace-result-detail-element/workspaceitem-my-dspace-result/workspaceitem-my-dspace-result-detail-element.component.spec.ts +++ b/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.spec.ts @@ -5,23 +5,23 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { of as observableOf } from 'rxjs'; import { Item } from '../../../../core/shared/item.model'; -import { WorkspaceitemMyDSpaceResultDetailElementComponent } from './workspaceitem-my-dspace-result-detail-element.component'; -import { WorkspaceitemMyDSpaceResult } from '../../../object-collection/shared/workspaceitem-my-dspace-result.model'; +import { WorkspaceItemSearchResultListElementComponent } from './workspace-item-search-result-list-element.component'; import { WorkspaceItem } from '../../../../core/submission/models/workspaceitem.model'; -import { RemoteData } from '../../../../core/data/remote-data'; import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; import { createSuccessfulRemoteDataObject } from '../../../testing/utils'; +import { WorkflowItemSearchResult } from '../../../object-collection/shared/workflow-item-search-result.model'; +import { TruncatableService } from '../../../truncatable/truncatable.service'; -let component: WorkspaceitemMyDSpaceResultDetailElementComponent; -let fixture: ComponentFixture; +let component: WorkspaceItemSearchResultListElementComponent; +let fixture: ComponentFixture; const compIndex = 1; -const mockResultObject: WorkspaceitemMyDSpaceResult = new WorkspaceitemMyDSpaceResult(); +const mockResultObject: WorkflowItemSearchResult = new WorkflowItemSearchResult(); mockResultObject.hitHighlights = {}; const item = Object.assign(new Item(), { - bitstreams: observableOf({}), + bundles: observableOf({}), metadata: { 'dc.title': [ { @@ -52,23 +52,22 @@ const item = Object.assign(new Item(), { const rd = createSuccessfulRemoteDataObject(item); mockResultObject.indexableObject = Object.assign(new WorkspaceItem(), { item: observableOf(rd) }); -describe('WorkspaceitemMyDSpaceResultDetailElementComponent', () => { +describe('WorkspaceItemSearchResultListElementComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [NoopAnimationsModule], - declarations: [WorkspaceitemMyDSpaceResultDetailElementComponent], + declarations: [WorkspaceItemSearchResultListElementComponent], providers: [ - { provide: 'objectElementProvider', useValue: (mockResultObject) }, - { provide: 'indexElementProvider', useValue: (compIndex) } + { provide: TruncatableService, useValue: {} }, ], schemas: [NO_ERRORS_SCHEMA] - }).overrideComponent(WorkspaceitemMyDSpaceResultDetailElementComponent, { + }).overrideComponent(WorkspaceItemSearchResultListElementComponent, { set: { changeDetection: ChangeDetectionStrategy.Default } }).compileComponents(); })); beforeEach(async(() => { - fixture = TestBed.createComponent(WorkspaceitemMyDSpaceResultDetailElementComponent); + fixture = TestBed.createComponent(WorkspaceItemSearchResultListElementComponent); component = fixture.componentInstance; })); diff --git a/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.ts b/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.ts new file mode 100644 index 0000000000..830726c677 --- /dev/null +++ b/src/app/shared/object-list/my-dspace-result-list-element/workspace-item-search-result/workspace-item-search-result-list-element.component.ts @@ -0,0 +1,56 @@ +import { Component } from '@angular/core'; + +import { Observable } from 'rxjs'; +import { find } from 'rxjs/operators'; + +import { ViewMode } from '../../../../core/shared/view-mode.model'; +import { WorkspaceItem } from '../../../../core/submission/models/workspaceitem.model'; +import { RemoteData } from '../../../../core/data/remote-data'; +import { isNotUndefined } from '../../../empty.util'; +import { Item } from '../../../../core/shared/item.model'; +import { MyDspaceItemStatusType } from '../../../object-collection/shared/mydspace-item-status/my-dspace-item-status-type'; +import { listableObjectComponent } from '../../../object-collection/shared/listable-object/listable-object.decorator'; +import { WorkspaceItemSearchResult } from '../../../object-collection/shared/workspace-item-search-result.model'; +import { SearchResultListElementComponent } from '../../search-result-list-element/search-result-list-element.component'; + +/** + * This component renders workspaceitem object for the search result in the list view. + */ +@Component({ + selector: 'ds-workspace-item-search-result-list-element', + styleUrls: ['../../search-result-list-element/search-result-list-element.component.scss', './workspace-item-search-result-list-element.component.scss'], + templateUrl: './workspace-item-search-result-list-element.component.html', +}) + +@listableObjectComponent(WorkspaceItemSearchResult, ViewMode.ListElement) +export class WorkspaceItemSearchResultListElementComponent extends SearchResultListElementComponent { + + /** + * The item object that belonging to the result object + */ + item: Item; + + /** + * Represent item's status + */ + status = MyDspaceItemStatusType.WORKSPACE; + + /** + * Initialize all instance variables + */ + ngOnInit() { + super.ngOnInit(); + this.initItem(this.dso.item as Observable>); + } + + /** + * Retrieve item from result object + */ + initItem(item$: Observable>) { + item$.pipe( + find((rd: RemoteData) => rd.hasSucceeded && isNotUndefined(rd.payload)) + ).subscribe((rd: RemoteData) => { + this.item = rd.payload; + }); + } +} diff --git a/src/app/shared/object-list/object-list.component.html b/src/app/shared/object-list/object-list.component.html index 1fdc06d5bf..1d49ea09d7 100644 --- a/src/app/shared/object-list/object-list.component.html +++ b/src/app/shared/object-list/object-list.component.html @@ -12,7 +12,7 @@ (paginationChange)="onPaginationChange($event)">
  • - +
diff --git a/src/app/shared/object-list/object-list.component.ts b/src/app/shared/object-list/object-list.component.ts index afc376034f..1158085bb0 100644 --- a/src/app/shared/object-list/object-list.component.ts +++ b/src/app/shared/object-list/object-list.component.ts @@ -12,6 +12,9 @@ import { RemoteData } from '../../core/data/remote-data'; import { fadeIn } from '../animations/fade'; import { ListableObject } from '../object-collection/shared/listable-object.model'; import { PaginationComponentOptions } from '../pagination/pagination-component-options.model'; +import { ViewMode } from '../../core/shared/view-mode.model'; +import { Context } from '../../core/shared/context.model'; +import { CollectionElementLinkType } from '../object-collection/collection-element-link.type'; @Component({ changeDetection: ChangeDetectionStrategy.Default, @@ -22,17 +25,62 @@ import { PaginationComponentOptions } from '../pagination/pagination-component-o animations: [fadeIn] }) export class ObjectListComponent { + /** + * The view mode of the this component + */ + viewMode = ViewMode.ListElement; + /** + * The current pagination configuration + */ @Input() config: PaginationComponentOptions; + + /** + * The current sort configuration + */ @Input() sortConfig: SortOptions; + + /** + * Whether or not the list elements have a border + */ @Input() hasBorder = false; + + /** + * The whether or not the gear is hidden + */ @Input() hideGear = false; + + /** + * Whether or not the pager is visible when there is only a single page of results + */ @Input() hidePagerWhenSinglePage = true; + + /** + * The link type of the listable elements + */ + @Input() linkType: CollectionElementLinkType; + + /** + * The context of the listable elements + */ + @Input() context: Context; + + /** + * The current listable objects + */ private _objects: RemoteData>; + + /** + * Setter for the objects + * @param objects The new objects + */ @Input() set objects(objects: RemoteData>) { this._objects = objects; } + /** + * Getter to return the current objects + */ get objects() { return this._objects; } @@ -67,6 +115,9 @@ export class ObjectListComponent { */ @Output() sortDirectionChange: EventEmitter = new EventEmitter(); + /** + * An event fired when on of the pagination parameters changes + */ @Output() paginationChange: EventEmitter = new EventEmitter(); /** @@ -74,24 +125,42 @@ export class ObjectListComponent { * Event's payload equals to the newly selected sort field. */ @Output() sortFieldChange: EventEmitter = new EventEmitter(); - data: any = {}; + /** + * Emits the current page when it changes + * @param event The new page + */ onPageChange(event) { this.pageChange.emit(event); } + /** + * Emits the current page size when it changes + * @param event The new page size + */ onPageSizeChange(event) { this.pageSizeChange.emit(event); } - + /** + * Emits the current sort direction when it changes + * @param event The new sort direction + */ onSortDirectionChange(event) { this.sortDirectionChange.emit(event); } + /** + * Emits the current sort field when it changes + * @param event The new sort field + */ onSortFieldChange(event) { this.sortFieldChange.emit(event); } + /** + * Emits the current pagination when it changes + * @param event The new pagination + */ onPaginationChange(event) { this.paginationChange.emit(event); } diff --git a/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.html b/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.html index b4af631e83..3c787c47ce 100644 --- a/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.html +++ b/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.html @@ -1,2 +1,3 @@ - + +
diff --git a/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.spec.ts b/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.spec.ts index 7f5aaf5d9c..9de1e085b5 100644 --- a/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.spec.ts +++ b/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.spec.ts @@ -47,9 +47,7 @@ describe('CollectionSearchResultListElementComponent', () => { declarations: [ CollectionSearchResultListElementComponent, TruncatePipe ], providers: [ { provide: TruncatableService, useValue: truncatableServiceStub }, - { provide: 'objectElementProvider', useValue: (mockCollectionWithAbstract) } ], - schemas: [ NO_ERRORS_SCHEMA ] }).overrideComponent(CollectionSearchResultListElementComponent, { set: { changeDetection: ChangeDetectionStrategy.Default } @@ -59,6 +57,8 @@ describe('CollectionSearchResultListElementComponent', () => { beforeEach(async(() => { fixture = TestBed.createComponent(CollectionSearchResultListElementComponent); collectionSearchResultListElementComponent = fixture.componentInstance; + collectionSearchResultListElementComponent.object = mockCollectionWithAbstract; + fixture.detectChanges(); })); describe('When the collection has an abstract', () => { diff --git a/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.ts b/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.ts index 2205155bbd..9e09068ddf 100644 --- a/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.ts +++ b/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.ts @@ -1,17 +1,17 @@ import { Component } from '@angular/core'; - -import { renderElementsFor } from '../../../object-collection/shared/dso-element-decorator'; - import { SearchResultListElementComponent } from '../search-result-list-element.component'; import { Collection } from '../../../../core/shared/collection.model'; -import { SetViewMode } from '../../../view-mode'; import { CollectionSearchResult } from '../../../object-collection/shared/collection-search-result.model'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; +import { listableObjectComponent } from '../../../object-collection/shared/listable-object/listable-object.decorator'; @Component({ selector: 'ds-collection-search-result-list-element', styleUrls: ['../search-result-list-element.component.scss', 'collection-search-result-list-element.component.scss'], templateUrl: 'collection-search-result-list-element.component.html' }) - -@renderElementsFor(CollectionSearchResult, SetViewMode.List) +/** + * Component representing a collection search result in list view + */ +@listableObjectComponent(CollectionSearchResult, ViewMode.ListElement) export class CollectionSearchResultListElementComponent extends SearchResultListElementComponent {} diff --git a/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.html b/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.html index 9444a63771..32834fefee 100644 --- a/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.html +++ b/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.html @@ -1,2 +1,3 @@ - + +
diff --git a/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.spec.ts b/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.spec.ts index 691a69dde4..2bf61c2ab9 100644 --- a/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.spec.ts +++ b/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.spec.ts @@ -47,7 +47,6 @@ describe('CommunitySearchResultListElementComponent', () => { declarations: [ CommunitySearchResultListElementComponent, TruncatePipe ], providers: [ { provide: TruncatableService, useValue: truncatableServiceStub }, - { provide: 'objectElementProvider', useValue: (mockCommunityWithAbstract) } ], schemas: [ NO_ERRORS_SCHEMA ] @@ -59,6 +58,8 @@ describe('CommunitySearchResultListElementComponent', () => { beforeEach(async(() => { fixture = TestBed.createComponent(CommunitySearchResultListElementComponent); communitySearchResultListElementComponent = fixture.componentInstance; + communitySearchResultListElementComponent.object = mockCommunityWithAbstract; + fixture.detectChanges(); })); describe('When the community has an abstract', () => { diff --git a/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.ts b/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.ts index 3f7e08d11c..b2fd695b39 100644 --- a/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.ts +++ b/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.ts @@ -1,19 +1,19 @@ import { Component } from '@angular/core'; - -import { renderElementsFor } from '../../../object-collection/shared/dso-element-decorator'; - import { SearchResultListElementComponent } from '../search-result-list-element.component'; import { Community } from '../../../../core/shared/community.model'; -import { SetViewMode } from '../../../view-mode'; import { CommunitySearchResult } from '../../../object-collection/shared/community-search-result.model'; +import { ViewMode } from '../../../../core/shared/view-mode.model'; +import { listableObjectComponent } from '../../../object-collection/shared/listable-object/listable-object.decorator'; @Component({ selector: 'ds-community-search-result-list-element', styleUrls: ['../search-result-list-element.component.scss', 'community-search-result-list-element.component.scss'], templateUrl: 'community-search-result-list-element.component.html' }) - -@renderElementsFor(CommunitySearchResult, SetViewMode.List) +/** + * Component representing a community search result in list view + */ +@listableObjectComponent(CommunitySearchResult, ViewMode.ListElement) export class CommunitySearchResultListElementComponent extends SearchResultListElementComponent { } diff --git a/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.html b/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.html deleted file mode 100644 index 051a27bde7..0000000000 --- a/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.html +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.spec.ts b/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.spec.ts deleted file mode 100644 index 8f41018404..0000000000 --- a/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.spec.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { ItemSearchResultListElementComponent } from './item-search-result-list-element.component'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { of as observableOf } from 'rxjs'; -import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; -import { By } from '@angular/platform-browser'; -import { TruncatePipe } from '../../../utils/truncate.pipe'; -import { Item } from '../../../../core/shared/item.model'; -import { TruncatableService } from '../../../truncatable/truncatable.service'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { ItemSearchResult } from '../../../object-collection/shared/item-search-result.model'; -import { TranslateModule } from '@ngx-translate/core'; - -let itemSearchResultListElementComponent: ItemSearchResultListElementComponent; -let fixture: ComponentFixture; - -const truncatableServiceStub: any = { - isCollapsed: (id: number) => observableOf(true), -}; - -const type = 'authorOfPublication'; - -const mockItemWithRelationshipType: ItemSearchResult = new ItemSearchResult(); -mockItemWithRelationshipType.hitHighlights = {}; -mockItemWithRelationshipType.indexableObject = Object.assign(new Item(), { - bitstreams: observableOf({}), - metadata: { - 'relationship.type': [ - { - language: 'en_US', - value: type - } - ] - } -}); - -describe('ItemSearchResultListElementComponent', () => { - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [TranslateModule.forRoot(), NoopAnimationsModule], - declarations: [ItemSearchResultListElementComponent, TruncatePipe], - providers: [ - { provide: TruncatableService, useValue: truncatableServiceStub }, - { provide: 'objectElementProvider', useValue: (mockItemWithRelationshipType) } - ], - schemas: [NO_ERRORS_SCHEMA] - }).overrideComponent(ItemSearchResultListElementComponent, { - set: { changeDetection: ChangeDetectionStrategy.Default } - }).compileComponents(); - })); - - beforeEach(async(() => { - fixture = TestBed.createComponent(ItemSearchResultListElementComponent); - itemSearchResultListElementComponent = fixture.componentInstance; - })); - - it('should show a badge on top of the list element', () => { - const badge = fixture.debugElement.query(By.css('ds-item-type-badge')).componentInstance; - expect(badge.object).toBe(mockItemWithRelationshipType); - }); -}); diff --git a/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.ts b/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.ts deleted file mode 100644 index 5bd3c8ff5a..0000000000 --- a/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Component } from '@angular/core'; -import { DSpaceObject } from '../../../../core/shared/dspace-object.model'; -import { Item } from '../../../../core/shared/item.model'; -import { focusBackground } from '../../../animations/focus'; -import { hasValue } from '../../../empty.util'; - -import { renderElementsFor } from '../../../object-collection/shared/dso-element-decorator'; -import { ItemSearchResult } from '../../../object-collection/shared/item-search-result.model'; -import { SetViewMode } from '../../../view-mode'; -import { SearchResultListElementComponent } from '../search-result-list-element.component'; -import { ItemViewMode } from '../../../items/item-type-decorator'; - -@Component({ - selector: 'ds-item-search-result-list-element', - styleUrls: ['../search-result-list-element.component.scss', 'item-search-result-list-element.component.scss'], - templateUrl: 'item-search-result-list-element.component.html', - animations: [focusBackground], - -}) - -@renderElementsFor(ItemSearchResult, SetViewMode.List) -export class ItemSearchResultListElementComponent extends SearchResultListElementComponent { - viewMode = ItemViewMode.Element; - -} diff --git a/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/publication/publication-search-result-list-element.component.html b/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/publication/publication-search-result-list-element.component.html new file mode 100644 index 0000000000..3d2604585d --- /dev/null +++ b/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/publication/publication-search-result-list-element.component.html @@ -0,0 +1,29 @@ + + + + + + + + (, ) + + + + ; + + + + +
+ + +
+
diff --git a/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/publication/publication-search-result-list-element.component.scss b/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/publication/publication-search-result-list-element.component.scss new file mode 100644 index 0000000000..5e4536cf95 --- /dev/null +++ b/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/publication/publication-search-result-list-element.component.scss @@ -0,0 +1 @@ +@import '../../../../../../../styles/variables'; diff --git a/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/publication/publication-search-result-list-element.component.spec.ts b/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/publication/publication-search-result-list-element.component.spec.ts new file mode 100644 index 0000000000..9b61a133be --- /dev/null +++ b/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/publication/publication-search-result-list-element.component.spec.ts @@ -0,0 +1,182 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { By } from '@angular/platform-browser'; +import { of as observableOf } from 'rxjs'; +import { PublicationSearchResultListElementComponent } from './publication-search-result-list-element.component'; +import { Item } from '../../../../../../core/shared/item.model'; +import { TruncatePipe } from '../../../../../utils/truncate.pipe'; +import { TruncatableService } from '../../../../../truncatable/truncatable.service'; +import { ItemSearchResult } from '../../../../../object-collection/shared/item-search-result.model'; + +let publicationListElementComponent: PublicationSearchResultListElementComponent; +let fixture: ComponentFixture; + +const mockItemWithMetadata: ItemSearchResult = Object.assign(new ItemSearchResult(), { + indexableObject: + Object.assign(new Item(), { + bundles: observableOf({}), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ], + 'dc.contributor.author': [ + { + language: 'en_US', + value: 'Smith, Donald' + } + ], + 'dc.publisher': [ + { + language: 'en_US', + value: 'a publisher' + } + ], + 'dc.date.issued': [ + { + language: 'en_US', + value: '2015-06-26' + } + ], + 'dc.description.abstract': [ + { + language: 'en_US', + value: 'This is the abstract' + } + ] + } + }) +}); +const mockItemWithoutMetadata: ItemSearchResult = Object.assign(new ItemSearchResult(), { + indexableObject: + Object.assign(new Item(), { + bundles: observableOf({}), + metadata: { + 'dc.title': [ + { + language: 'en_US', + value: 'This is just another title' + } + ] + } + }) +}); + +describe('PublicationListElementComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [PublicationSearchResultListElementComponent, TruncatePipe], + providers: [ + { provide: TruncatableService, useValue: {} } + ], + + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(PublicationSearchResultListElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(PublicationSearchResultListElementComponent); + publicationListElementComponent = fixture.componentInstance; + + })); + + describe('When the item has an author', () => { + beforeEach(() => { + publicationListElementComponent.object = mockItemWithMetadata; + fixture.detectChanges(); + }); + + it('should show the author paragraph', () => { + const itemAuthorField = fixture.debugElement.query(By.css('span.item-list-authors')); + expect(itemAuthorField).not.toBeNull(); + }); + }); + + describe('When the item has no author', () => { + beforeEach(() => { + publicationListElementComponent.object = mockItemWithoutMetadata; + fixture.detectChanges(); + }); + + it('should not show the author paragraph', () => { + const itemAuthorField = fixture.debugElement.query(By.css('span.item-list-authors')); + expect(itemAuthorField).toBeNull(); + }); + }); + + describe('When the item has a publisher', () => { + beforeEach(() => { + publicationListElementComponent.object = mockItemWithMetadata; + fixture.detectChanges(); + }); + + it('should show the publisher span', () => { + const publisherField = fixture.debugElement.query(By.css('span.item-list-publisher')); + expect(publisherField).not.toBeNull(); + }); + }); + + describe('When the item has no publisher', () => { + beforeEach(() => { + publicationListElementComponent.object = mockItemWithoutMetadata; + fixture.detectChanges(); + }); + + it('should not show the publisher span', () => { + const publisherField = fixture.debugElement.query(By.css('span.item-list-publisher')); + expect(publisherField).toBeNull(); + }); + }); + + describe('When the item has an issuedate', () => { + beforeEach(() => { + publicationListElementComponent.object = mockItemWithMetadata; + fixture.detectChanges(); + }); + + it('should show the issuedate span', () => { + const dateField = fixture.debugElement.query(By.css('span.item-list-date')); + expect(dateField).not.toBeNull(); + }); + }); + + describe('When the item has no issuedate', () => { + beforeEach(() => { + publicationListElementComponent.object = mockItemWithoutMetadata; + fixture.detectChanges(); + }); + + it('should not show the issuedate span', () => { + const dateField = fixture.debugElement.query(By.css('span.item-list-date')); + expect(dateField).toBeNull(); + }); + }); + + describe('When the item has an abstract', () => { + beforeEach(() => { + publicationListElementComponent.object = mockItemWithMetadata; + fixture.detectChanges(); + }); + + it('should show the abstract span', () => { + const abstractField = fixture.debugElement.query(By.css('div.item-list-abstract')); + expect(abstractField).not.toBeNull(); + }); + }); + + describe('When the item has no abstract', () => { + beforeEach(() => { + publicationListElementComponent.object = mockItemWithoutMetadata; + fixture.detectChanges(); + }); + + it('should not show the abstract span', () => { + const abstractField = fixture.debugElement.query(By.css('div.item-list-abstract')); + expect(abstractField).toBeNull(); + }); + }); +}); diff --git a/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/publication/publication-search-result-list-element.component.ts b/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/publication/publication-search-result-list-element.component.ts new file mode 100644 index 0000000000..3e0db60b4c --- /dev/null +++ b/src/app/shared/object-list/search-result-list-element/item-search-result/item-types/publication/publication-search-result-list-element.component.ts @@ -0,0 +1,19 @@ +import { Component } from '@angular/core'; +import { listableObjectComponent } from '../../../../../object-collection/shared/listable-object/listable-object.decorator'; +import { ViewMode } from '../../../../../../core/shared/view-mode.model'; +import { ItemSearchResult } from '../../../../../object-collection/shared/item-search-result.model'; +import { SearchResultListElementComponent } from '../../../search-result-list-element.component'; +import { Item } from '../../../../../../core/shared/item.model'; + +@listableObjectComponent('PublicationSearchResult', ViewMode.ListElement) +@listableObjectComponent(ItemSearchResult, ViewMode.ListElement) +@Component({ + selector: 'ds-publication-search-result-list-element', + styleUrls: ['./publication-search-result-list-element.component.scss'], + templateUrl: './publication-search-result-list-element.component.html' +}) +/** + * The component for displaying a list element for an item search result of the type Publication + */ +export class PublicationSearchResultListElementComponent extends SearchResultListElementComponent { +} diff --git a/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts b/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts index 7017f3f48b..93fc00bc87 100644 --- a/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts +++ b/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts @@ -1,26 +1,32 @@ -import { Component, Inject } from '@angular/core'; +import { Component, Inject, OnInit } from '@angular/core'; import { Observable } from 'rxjs'; import { SearchResult } from '../../../+search-page/search-result.model'; import { DSpaceObject } from '../../../core/shared/dspace-object.model'; import { hasValue } from '../../empty.util'; -import { ListableObject } from '../../object-collection/shared/listable-object.model'; import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component'; import { TruncatableService } from '../../truncatable/truncatable.service'; import { Metadata } from '../../../core/shared/metadata.utils'; -import { MetadataMap } from '../../../core/shared/metadata.models'; @Component({ selector: 'ds-search-result-list-element', template: `` }) -export class SearchResultListElementComponent, K extends DSpaceObject> extends AbstractListableElementComponent { +export class SearchResultListElementComponent, K extends DSpaceObject> extends AbstractListableElementComponent implements OnInit { + /** + * The DSpaceObject of the search result + */ dso: K; - metadata: MetadataMap; - public constructor(@Inject('objectElementProvider') public listable: ListableObject, protected truncatableService: TruncatableService) { - super(listable); + public constructor(protected truncatableService: TruncatableService) { + super(); + } + + /** + * Retrieve the dso from the search result + */ + ngOnInit(): void { if (hasValue(this.object)) { this.dso = this.object.indexableObject; } @@ -46,7 +52,11 @@ export class SearchResultListElementComponent, K exten return Metadata.firstValue([this.object.hitHighlights, this.dso.metadata], keyOrKeys); } + /** + * Emits if the list element is currently collapsed or not + */ isCollapsed(): Observable { return this.truncatableService.isCollapsed(this.dso.id); } + } diff --git a/src/app/shared/object-list/wrapper-list-element/wrapper-list-element.component.html b/src/app/shared/object-list/wrapper-list-element/wrapper-list-element.component.html deleted file mode 100644 index db87596f31..0000000000 --- a/src/app/shared/object-list/wrapper-list-element/wrapper-list-element.component.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/app/shared/object-list/wrapper-list-element/wrapper-list-element.component.scss b/src/app/shared/object-list/wrapper-list-element/wrapper-list-element.component.scss deleted file mode 100644 index 8b13789179..0000000000 --- a/src/app/shared/object-list/wrapper-list-element/wrapper-list-element.component.scss +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/app/shared/object-list/wrapper-list-element/wrapper-list-element.component.ts b/src/app/shared/object-list/wrapper-list-element/wrapper-list-element.component.ts deleted file mode 100644 index 29b1364a75..0000000000 --- a/src/app/shared/object-list/wrapper-list-element/wrapper-list-element.component.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Component, Injector, Input, OnInit } from '@angular/core'; -import { SetViewMode } from '../../view-mode'; -import { GenericConstructor } from '../../../core/shared/generic-constructor'; -import { rendersDSOType } from '../../object-collection/shared/dso-element-decorator' -import { ListableObject } from '../../object-collection/shared/listable-object.model'; - -@Component({ - selector: 'ds-wrapper-list-element', - styleUrls: ['./wrapper-list-element.component.scss'], - templateUrl: './wrapper-list-element.component.html' -}) -export class WrapperListElementComponent implements OnInit { - @Input() object: ListableObject; - @Input() index: number; - objectInjector: Injector; - listElement: any; - - constructor(private injector: Injector) {} - - ngOnInit(): void { - this.objectInjector = Injector.create({ - providers: [ - { provide: 'objectElementProvider', useFactory: () => (this.object), deps:[] }, - { provide: 'indexElementProvider', useFactory: () => (this.index), deps:[] } - ], - parent: this.injector - }); - this.listElement = this.getListElement(); - } - - private getListElement(): string { - const f: GenericConstructor = this.object.constructor as GenericConstructor; - return rendersDSOType(f, SetViewMode.List); - } -} diff --git a/src/app/shared/object-select/item-select/item-select.component.spec.ts b/src/app/shared/object-select/item-select/item-select.component.spec.ts index 059e44064e..26dd55f010 100644 --- a/src/app/shared/object-select/item-select/item-select.component.spec.ts +++ b/src/app/shared/object-select/item-select/item-select.component.spec.ts @@ -24,7 +24,7 @@ describe('ItemSelectComponent', () => { const mockItemList = [ Object.assign(new Item(), { id: 'id1', - bitstreams: of({}), + bundles: of({}), metadata: [ { key: 'dc.title', @@ -39,7 +39,7 @@ describe('ItemSelectComponent', () => { }), Object.assign(new Item(), { id: 'id2', - bitstreams: of({}), + bundles: of({}), metadata: [ { key: 'dc.title', diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index ed9f8efa93..cce01012e5 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -9,8 +9,6 @@ import { NgbDatepickerModule, NgbModule, NgbTimepickerModule, NgbTypeaheadModule import { TranslateModule } from '@ngx-translate/core'; import { NgxPaginationModule } from 'ngx-pagination'; -import { ItemTypeSwitcherComponent } from './items/switcher/item-type-switcher.component'; -import { TypedItemSearchResultListElementComponent } from './object-list/item-list-element/item-types/typed-item-search-result-list-element.component'; import { PublicationListElementComponent } from './object-list/item-list-element/item-types/publication/publication-list-element.component'; import { FileUploadModule } from 'ng2-file-upload'; @@ -24,15 +22,11 @@ import { ConsolePipe } from './utils/console.pipe'; import { CollectionListElementComponent } from './object-list/collection-list-element/collection-list-element.component'; import { CommunityListElementComponent } from './object-list/community-list-element/community-list-element.component'; -import { ItemListElementComponent } from './object-list/item-list-element/item-list-element.component'; import { SearchResultListElementComponent } from './object-list/search-result-list-element/search-result-list-element.component'; -import { WrapperListElementComponent } from './object-list/wrapper-list-element/wrapper-list-element.component'; import { ObjectListComponent } from './object-list/object-list.component'; import { CollectionGridElementComponent } from './object-grid/collection-grid-element/collection-grid-element.component'; import { CommunityGridElementComponent } from './object-grid/community-grid-element/community-grid-element.component'; -import { ItemGridElementComponent } from './object-grid/item-grid-element/item-grid-element.component'; import { AbstractListableElementComponent } from './object-collection/shared/object-collection-element/abstract-listable-element.component'; -import { WrapperGridElementComponent } from './object-grid/wrapper-grid-element/wrapper-grid-element.component'; import { ObjectGridComponent } from './object-grid/object-grid.component'; import { ObjectCollectionComponent } from './object-collection/object-collection.component'; import { ComcolPageContentComponent } from './comcol-page-content/comcol-page-content.component'; @@ -81,12 +75,10 @@ import { DsDatePickerComponent } from './form/builder/ds-dynamic-form-ui/models/ import { DsDynamicLookupComponent } from './form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component'; import { MockAdminGuard } from './mocks/mock-admin-guard.service'; import { AlertComponent } from './alert/alert.component'; -import { MyDSpaceResultListElementComponent } from './object-list/my-dspace-result-list-element/my-dspace-result-list-element.component'; -import { MyDSpaceResultDetailElementComponent } from './object-detail/my-dspace-result-detail-element/my-dspace-result-detail-element.component'; +import { SearchResultDetailElementComponent } from './object-detail/my-dspace-result-detail-element/search-result-detail-element.component'; import { ClaimedTaskActionsComponent } from './mydspace-actions/claimed-task/claimed-task-actions.component'; import { PoolTaskActionsComponent } from './mydspace-actions/pool-task/pool-task-actions.component'; import { ObjectDetailComponent } from './object-detail/object-detail.component'; -import { WrapperDetailElementComponent } from './object-detail/wrapper-detail-element/wrapper-detail-element.component'; import { ItemDetailPreviewComponent } from './object-detail/my-dspace-result-detail-element/item-detail-preview/item-detail-preview.component'; import { MyDSpaceItemStatusComponent } from './object-collection/shared/mydspace-item-status/my-dspace-item-status.component'; import { WorkspaceitemActionsComponent } from './mydspace-actions/workspaceitem/workspaceitem-actions.component'; @@ -128,7 +120,6 @@ import { CreateItemParentSelectorComponent } from './dso-selector/modal-wrappers import { CreateCollectionParentSelectorComponent } from './dso-selector/modal-wrappers/create-collection-parent-selector/create-collection-parent-selector.component'; import { CommunitySearchResultListElementComponent } from './object-list/search-result-list-element/community-search-result/community-search-result-list-element.component'; import { CollectionSearchResultListElementComponent } from './object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component'; -import { ItemSearchResultListElementComponent } from './object-list/search-result-list-element/item-search-result/item-search-result-list-element.component'; import { EditItemSelectorComponent } from './dso-selector/modal-wrappers/edit-item-selector/edit-item-selector.component'; import { EditCommunitySelectorComponent } from './dso-selector/modal-wrappers/edit-community-selector/edit-community-selector.component'; import { EditCollectionSelectorComponent } from './dso-selector/modal-wrappers/edit-collection-selector/edit-collection-selector.component'; @@ -143,9 +134,16 @@ import { ItemSelectComponent } from './object-select/item-select/item-select.com import { CollectionSelectComponent } from './object-select/collection-select/collection-select.component'; import { FilterInputSuggestionsComponent } from './input-suggestions/filter-suggestions/filter-input-suggestions.component'; import { DsoInputSuggestionsComponent } from './input-suggestions/dso-input-suggestions/dso-input-suggestions.component'; -import { TypedItemSearchResultGridElementComponent } from './object-grid/item-grid-element/item-types/typed-item-search-result-grid-element.component'; import { PublicationGridElementComponent } from './object-grid/item-grid-element/item-types/publication/publication-grid-element.component'; import { ItemTypeBadgeComponent } from './object-list/item-type-badge/item-type-badge.component'; +import { MetadataRepresentationLoaderComponent } from './metadata-representation/metadata-representation-loader.component'; +import { MetadataRepresentationDirective } from './metadata-representation/metadata-representation.directive'; +import { ListableObjectComponentLoaderComponent } from './object-collection/shared/listable-object/listable-object-component-loader.component'; +import { PublicationSearchResultListElementComponent } from './object-list/search-result-list-element/item-search-result/item-types/publication/publication-search-result-list-element.component'; +import { PublicationSearchResultGridElementComponent } from './object-grid/search-result-grid-element/item-search-result/publication/publication-search-result-grid-element.component'; +import { ListableObjectDirective } from './object-collection/shared/listable-object/listable-object.directive'; +import { CommunitySearchResultGridElementComponent } from './object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component'; +import { CollectionSearchResultGridElementComponent } from './object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component'; import { ItemMetadataRepresentationListElementComponent } from './object-list/metadata-representation-list-element/item/item-metadata-representation-list-element.component'; const MODULES = [ @@ -227,16 +225,12 @@ const COMPONENTS = [ ObjectDetailComponent, ObjectGridComponent, AbstractListableElementComponent, - WrapperListElementComponent, - WrapperDetailElementComponent, - WrapperGridElementComponent, ObjectCollectionComponent, PaginationComponent, SearchFormComponent, ThumbnailComponent, GridThumbnailComponent, UploaderComponent, - WrapperListElementComponent, ItemListPreviewComponent, MyDSpaceItemStatusComponent, ItemSubmitterComponent, @@ -266,34 +260,38 @@ const COMPONENTS = [ EditItemSelectorComponent, CommunitySearchResultListElementComponent, CollectionSearchResultListElementComponent, - ItemSearchResultListElementComponent, - TypedItemSearchResultListElementComponent, - TypedItemSearchResultGridElementComponent, - ItemTypeSwitcherComponent, + CommunitySearchResultGridElementComponent, + CollectionSearchResultGridElementComponent, + ListableObjectComponentLoaderComponent, + CollectionListElementComponent, + CommunityListElementComponent, + CollectionGridElementComponent, + CommunityGridElementComponent, BrowseByComponent, ItemTypeBadgeComponent, ItemSelectComponent, - CollectionSelectComponent + CollectionSelectComponent, + MetadataRepresentationLoaderComponent ]; const ENTRY_COMPONENTS = [ // put shared entry components (components that are created dynamically) here - ItemListElementComponent, CollectionListElementComponent, CommunityListElementComponent, - MyDSpaceResultListElementComponent, SearchResultListElementComponent, CommunitySearchResultListElementComponent, CollectionSearchResultListElementComponent, - ItemSearchResultListElementComponent, - ItemGridElementComponent, CollectionGridElementComponent, CommunityGridElementComponent, + CommunitySearchResultGridElementComponent, + CollectionSearchResultGridElementComponent, SearchResultGridElementComponent, PublicationListElementComponent, PublicationGridElementComponent, + PublicationSearchResultListElementComponent, + PublicationSearchResultGridElementComponent, BrowseEntryListElementComponent, - MyDSpaceResultDetailElementComponent, + SearchResultDetailElementComponent, SearchResultGridElementComponent, DsDynamicListComponent, DsDynamicLookupComponent, @@ -343,7 +341,9 @@ const DIRECTIVES = [ AuthorityConfidenceStateDirective, InListValidator, AutoFocusDirective, - RoleDirective + RoleDirective, + MetadataRepresentationDirective, + ListableObjectDirective ]; @NgModule({ @@ -356,7 +356,8 @@ const DIRECTIVES = [ ...COMPONENTS, ...DIRECTIVES, ...ENTRY_COMPONENTS, - ...SHARED_ITEM_PAGE_COMPONENTS + ...SHARED_ITEM_PAGE_COMPONENTS, + PublicationSearchResultListElementComponent ], providers: [ ...PROVIDERS diff --git a/src/app/shared/testing/search-service-stub.ts b/src/app/shared/testing/search-service-stub.ts index d886604ef2..b64fdd1330 100644 --- a/src/app/shared/testing/search-service-stub.ts +++ b/src/app/shared/testing/search-service-stub.ts @@ -1,22 +1,22 @@ import {of as observableOf, Observable , BehaviorSubject } from 'rxjs'; -import { SetViewMode } from '../view-mode'; +import { ViewMode } from '../../core/shared/view-mode.model'; export class SearchServiceStub { - private _viewMode: SetViewMode; + private _viewMode: ViewMode; private subject?: BehaviorSubject = new BehaviorSubject(this.testViewMode); viewMode = this.subject.asObservable(); constructor(private searchLink: string = '/search') { - this.setViewMode(SetViewMode.List); + this.setViewMode(ViewMode.ListElement); } - getViewMode(): Observable { + getViewMode(): Observable { return this.viewMode; } - setViewMode(viewMode: SetViewMode) { + setViewMode(viewMode: ViewMode) { this.testViewMode = viewMode; } @@ -24,11 +24,11 @@ export class SearchServiceStub { return null; } - get testViewMode(): SetViewMode { + get testViewMode(): ViewMode { return this._viewMode; } - set testViewMode(viewMode: SetViewMode) { + set testViewMode(viewMode: ViewMode) { this._viewMode = viewMode; this.subject.next(viewMode); } diff --git a/src/app/shared/testing/utils.ts b/src/app/shared/testing/utils.ts index 7033f79472..d68d18e51e 100644 --- a/src/app/shared/testing/utils.ts +++ b/src/app/shared/testing/utils.ts @@ -131,3 +131,14 @@ export function createPendingRemoteDataObject$(object?: T): Observable(objects?: T[]): PaginatedList { return new PaginatedList(new PageInfo(), objects); } + +/** + * Creates a jasmine spy for an exported function + * @param target The object to spy on + * @param prop The property/function to spy on + */ +export function spyOnExported(target: T, prop: keyof T): jasmine.Spy { + const spy = jasmine.createSpy(`${prop}Spy`); + spyOnProperty(target, prop).and.returnValue(spy); + return spy; +} diff --git a/src/app/shared/view-mode-switch/view-mode-switch.component.html b/src/app/shared/view-mode-switch/view-mode-switch.component.html index 905cf29bac..b4c1c18d4f 100644 --- a/src/app/shared/view-mode-switch/view-mode-switch.component.html +++ b/src/app/shared/view-mode-switch/view-mode-switch.component.html @@ -1,31 +1,31 @@
- - - diff --git a/src/app/shared/view-mode-switch/view-mode-switch.component.spec.ts b/src/app/shared/view-mode-switch/view-mode-switch.component.spec.ts index 2fe405de3f..cc0175231e 100644 --- a/src/app/shared/view-mode-switch/view-mode-switch.component.spec.ts +++ b/src/app/shared/view-mode-switch/view-mode-switch.component.spec.ts @@ -8,8 +8,8 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; import { SearchService } from '../../+search-page/search-service/search.service'; import { ViewModeSwitchComponent } from './view-mode-switch.component'; -import { SetViewMode } from '../view-mode'; import { SearchServiceStub } from '../testing/search-service-stub'; +import { ViewMode } from '../../core/shared/view-mode.model'; @Component({ template: '' }) class DummyComponent { } @@ -55,19 +55,19 @@ describe('ViewModeSwitchComponent', () => { }); it('should set list button as active when on list mode', fakeAsync(() => { - searchService.setViewMode(SetViewMode.List); + searchService.setViewMode(ViewMode.ListElement); tick(); fixture.detectChanges(); - expect(comp.currentMode).toBe(SetViewMode.List); + expect(comp.currentMode).toBe(ViewMode.ListElement); expect(listButton.classList).toContain('active'); expect(gridButton.classList).not.toContain('active'); })); it('should set grid button as active when on grid mode', fakeAsync(() => { - searchService.setViewMode(SetViewMode.Grid); + searchService.setViewMode(ViewMode.GridElement); tick(); fixture.detectChanges(); - expect(comp.currentMode).toBe(SetViewMode.Grid); + expect(comp.currentMode).toBe(ViewMode.GridElement); expect(listButton.classList).not.toContain('active'); expect(gridButton.classList).toContain('active'); })); diff --git a/src/app/shared/view-mode-switch/view-mode-switch.component.ts b/src/app/shared/view-mode-switch/view-mode-switch.component.ts index dc355c6409..d406573646 100644 --- a/src/app/shared/view-mode-switch/view-mode-switch.component.ts +++ b/src/app/shared/view-mode-switch/view-mode-switch.component.ts @@ -22,16 +22,26 @@ export class ViewModeSwitchComponent implements OnInit, OnDestroy { */ @Input() inPlaceSearch; - currentMode: ViewMode = ViewMode.List; + /** + * The current view mode + */ + currentMode: ViewMode = ViewMode.ListElement; + + /** + * All available view modes + */ viewModeEnum = ViewMode; private sub: Subscription; constructor(private searchService: SearchService) { } + /** + * Initialize the instance variables + */ ngOnInit(): void { if (isEmpty(this.viewModeList)) { - this.viewModeList = [ViewMode.List, ViewMode.Grid]; + this.viewModeList = [ViewMode.ListElement, ViewMode.GridElement]; } this.sub = this.searchService.getViewMode().subscribe((viewMode: ViewMode) => { @@ -39,6 +49,10 @@ export class ViewModeSwitchComponent implements OnInit, OnDestroy { }); } + /** + * Switch view modes + * @param viewMode The new view mode + */ switchViewTo(viewMode: ViewMode) { this.searchService.setViewMode(viewMode, this.getSearchLinkParts()); } @@ -49,6 +63,10 @@ export class ViewModeSwitchComponent implements OnInit, OnDestroy { } } + /** + * Whether or not to show a certain view mode + * @param viewMode The view mode to check for + */ isToShow(viewMode: ViewMode) { return this.viewModeList && this.viewModeList.includes(viewMode); } diff --git a/src/app/shared/view-mode.ts b/src/app/shared/view-mode.ts deleted file mode 100644 index 826d467d6f..0000000000 --- a/src/app/shared/view-mode.ts +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Enum used for defining the view-mode of a set of elements - * List Display the elements in a (vertical) list - * Grid Display the elements in a grid - */ -export enum SetViewMode { - List = 'list', - Grid = 'grid', - Detail = 'detail' -} - -/** - * ViewMode refers to either a SetViewMode or ElementViewMode - */ -export type ViewMode = SetViewMode; diff --git a/src/app/submission/submission.service.spec.ts b/src/app/submission/submission.service.spec.ts index 5cb6efd8b7..d67fb3679a 100644 --- a/src/app/submission/submission.service.spec.ts +++ b/src/app/submission/submission.service.spec.ts @@ -45,6 +45,10 @@ import { createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ } from '../shared/testing/utils'; +import { getMockSearchService } from '../shared/mocks/mock-search-service'; +import { getMockRequestService } from '../shared/mocks/mock-request.service'; +import { SearchService } from '../+search-page/search-service/search.service'; +import { RequestService } from '../core/data/request.service'; describe('SubmissionService test suite', () => { const config = MOCK_SUBMISSION_CONFIG; @@ -349,7 +353,12 @@ describe('SubmissionService test suite', () => { let scheduler: TestScheduler; let service: SubmissionService; + const searchService = getMockSearchService(); + + const requestServce = getMockRequestService(); + beforeEach(async(() => { + TestBed.configureTestingModule({ imports: [ StoreModule.forRoot({ submissionReducers } as any), @@ -365,6 +374,8 @@ describe('SubmissionService test suite', () => { { provide: Router, useValue: router }, { provide: SubmissionRestService, useValue: restService }, { provide: ActivatedRoute, useValue: new MockActivatedRoute() }, + { provide: SearchService, useValue: searchService }, + { provide: RequestService, useValue: requestServce }, NotificationsService, RouteService, SubmissionService, diff --git a/src/app/submission/submission.service.ts b/src/app/submission/submission.service.ts index 7605f1c73a..c9be658b31 100644 --- a/src/app/submission/submission.service.ts +++ b/src/app/submission/submission.service.ts @@ -4,13 +4,12 @@ import { Router } from '@angular/router'; import { Observable, of as observableOf, Subscription, timer as observableTimer } from 'rxjs'; import { - catchError, + catchError, concatMap, distinctUntilChanged, filter, find, - first, map, - startWith + startWith, take, tap } from 'rxjs/operators'; import { Store } from '@ngrx/store'; import { TranslateService } from '@ngx-translate/core'; @@ -56,6 +55,8 @@ import { createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ } from '../shared/testing/utils'; +import { SearchService } from '../+search-page/search-service/search.service'; +import { RequestService } from '../core/data/request.service'; /** * A service that provides methods used in submission process. @@ -82,6 +83,8 @@ export class SubmissionService { * @param {RouteService} routeService * @param {Store} store * @param {TranslateService} translate + * @param {SearchService} searchService + * @param {RequestService} requestService */ constructor(@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig, protected notificationsService: NotificationsService, @@ -89,7 +92,9 @@ export class SubmissionService { protected router: Router, protected routeService: RouteService, protected store: Store, - protected translate: TranslateService) { + protected translate: TranslateService, + protected searchService: SearchService, + protected requestService: RequestService) { } /** @@ -460,16 +465,23 @@ export class SubmissionService { * Redirect to MyDspace page */ redirectToMyDSpace() { - this.routeService.getPreviousUrl().pipe( - first() - ).subscribe((previousUrl: string) => { - if (isEmpty(previousUrl) || !previousUrl.startsWith('/mydspace')) { - this.router.navigate(['/mydspace']); - } else { - this.router.navigateByUrl(previousUrl); - } - }); - + // This assures that the cache is empty before redirecting to mydspace. + // See https://github.com/DSpace/dspace-angular/pull/468 + this.searchService.getEndpoint().pipe( + take(1), + tap((url) => this.requestService.removeByHrefSubstring(url)), + // Now, do redirect. + concatMap( + () => this.routeService.getPreviousUrl().pipe( + take(1), + tap((previousUrl) => { + if (isEmpty(previousUrl) || !previousUrl.startsWith('/mydspace')) { + this.router.navigate(['/mydspace']); + } else { + this.router.navigateByUrl(previousUrl); + } + }))) + ).subscribe(); } /** diff --git a/themes/mantis/app/+item-page/simple/item-page.component.html b/themes/mantis/app/+item-page/simple/item-page.component.html index 472df7c78e..83f910e0cd 100644 --- a/themes/mantis/app/+item-page/simple/item-page.component.html +++ b/themes/mantis/app/+item-page/simple/item-page.component.html @@ -1,7 +1,7 @@
- +
diff --git a/themes/mantis/app/+item-page/simple/item-types/publication/publication.component.html b/themes/mantis/app/+item-page/simple/item-types/publication/publication.component.html index 6b6f484183..35dc903432 100644 --- a/themes/mantis/app/+item-page/simple/item-types/publication/publication.component.html +++ b/themes/mantis/app/+item-page/simple/item-types/publication/publication.component.html @@ -1,83 +1,84 @@ -
+a
- +
+ [parentItem]="object" + [itemType]="'Person'" + [metadataField]="'dc.contributor.author'" + [label]="'relationships.isAuthorOf' | translate"> - - - - + + + - -
- - + - - - + +
-
+
-
- - -
-
- - -
-
- - -
+ + + + + +
diff --git a/themes/mantis/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.html b/themes/mantis/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.html index a25a474eb0..9fa80d9c3c 100644 --- a/themes/mantis/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.html +++ b/themes/mantis/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.html @@ -4,11 +4,11 @@
- + @@ -17,34 +17,38 @@

{{'journalissue.page.titleprefix' | translate}} + [mdValues]="object?.allMetadata(['dc.title'])">

- - + + -
- - -
@@ -53,21 +57,21 @@
-
+
-
- - -
-
- - -
+ + + +
diff --git a/themes/mantis/app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.html b/themes/mantis/app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.html index c20e9a775a..99d92d2af8 100644 --- a/themes/mantis/app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.html +++ b/themes/mantis/app/entity-groups/journal-entities/item-pages/journal-volume/journal-volume.component.html @@ -4,11 +4,11 @@
- + @@ -17,23 +17,23 @@

{{'journalvolume.page.titleprefix' | translate}} + [mdValues]="object?.allMetadata(['dc.title'])">

- -
-
@@ -42,21 +42,21 @@
-
+
-
- - -
-
- - -
+ + + +
diff --git a/themes/mantis/app/entity-groups/journal-entities/item-pages/journal/journal.component.html b/themes/mantis/app/entity-groups/journal-entities/item-pages/journal/journal.component.html index ef827af590..1b8a283da9 100644 --- a/themes/mantis/app/entity-groups/journal-entities/item-pages/journal/journal.component.html +++ b/themes/mantis/app/entity-groups/journal-entities/item-pages/journal/journal.component.html @@ -3,11 +3,11 @@
- + @@ -16,27 +16,27 @@

{{'journal.page.titleprefix' | translate}} + [mdValues]="object?.allMetadata(['dc.title'])">

- - -
-
@@ -45,15 +45,15 @@
-
+
-
- - -
+ +
@@ -61,7 +61,7 @@

{{"item.page.journal.search.title" | translate}}

-
diff --git a/themes/mantis/app/entity-groups/research-entities/item-pages/orgunit/orgunit.component.html b/themes/mantis/app/entity-groups/research-entities/item-pages/orgunit/orgunit.component.html index 6bb925c93f..15529a1bd5 100644 --- a/themes/mantis/app/entity-groups/research-entities/item-pages/orgunit/orgunit.component.html +++ b/themes/mantis/app/entity-groups/research-entities/item-pages/orgunit/orgunit.component.html @@ -4,12 +4,12 @@
- @@ -18,30 +18,30 @@

{{'orgunit.page.titleprefix' | translate}} + [mdValues]="object?.allMetadata(['organization.legalName'])">

- - -
- -
@@ -50,27 +50,27 @@
-
+
-
- - -
-
- - -
-
- - -
+ + + + + +
diff --git a/themes/mantis/app/entity-groups/research-entities/item-pages/person/person.component.html b/themes/mantis/app/entity-groups/research-entities/item-pages/person/person.component.html index 54d7962b97..bb5cb1b787 100644 --- a/themes/mantis/app/entity-groups/research-entities/item-pages/person/person.component.html +++ b/themes/mantis/app/entity-groups/research-entities/item-pages/person/person.component.html @@ -4,12 +4,12 @@
- @@ -17,38 +17,38 @@

{{'person.page.titleprefix' | translate}} + [mdValues]="[object?.firstMetadata('person.familyName'), object?.firstMetadata('person.givenName')]" [separator]="', '">

- - - - + + + + - - + + + +
- - -
@@ -57,21 +57,21 @@
-
+
-
- - -
-
- - -
+ + + +
@@ -79,7 +79,7 @@

{{"item.page.person.search.title" | translate}}

-
diff --git a/themes/mantis/app/entity-groups/research-entities/item-pages/project/project.component.html b/themes/mantis/app/entity-groups/research-entities/item-pages/project/project.component.html index aa4a107247..31ba79a158 100644 --- a/themes/mantis/app/entity-groups/research-entities/item-pages/project/project.component.html +++ b/themes/mantis/app/entity-groups/research-entities/item-pages/project/project.component.html @@ -4,52 +4,51 @@

- {{'project.page.titleprefix' | translate}} - + {{'project.page.titleprefix' | translate}}

- + - - - - - + + + + + + + +
- - -
@@ -58,27 +57,27 @@
-
+
-
- - -
-
- - -
-
- - -
+ + + + + +
diff --git a/yarn.lock b/yarn.lock index 854c6add88..69f4a072ae 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2053,6 +2053,14 @@ cli-cursor@^2.1.0: dependencies: restore-cursor "^2.0.0" +cli-progress@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/cli-progress/-/cli-progress-3.3.1.tgz#e08fb6853e269c3bc7e0ad8ad0ede59035f5fbce" + integrity sha512-cfvv/uuWblzSI6fvpmCNREWxwzI/luelp+P7zoPlguswswWVCfsq334/U6tmh+vusJ7yzbQ3xFni9JNqiF4fAA== + dependencies: + colors "^1.1.2" + string-width "^2.1.1" + cli-width@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" @@ -2224,6 +2232,11 @@ colors@^1.1.0: resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.2.tgz#2df8ff573dfbf255af562f8ce7181d6b971a359b" integrity sha512-rhP0JSBGYvpcNQj4s5AdShMeE5ahMop96cTeDl/v9qQQm2fYClE2QXZRi8wLzc+GmXSxdIqqbOIAhyObEXDbfQ== +colors@^1.1.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" + integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== + combine-lists@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/combine-lists/-/combine-lists-1.0.1.tgz#458c07e09e0d900fc28b70a3fec2dacd1d2cb7f6" @@ -2253,6 +2266,11 @@ commander@^2.12.1, commander@^2.18.0, commander@~2.20.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== +commander@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/commander/-/commander-3.0.2.tgz#6837c3fb677ad9933d1cfba42dd14d5117d6b39e" + integrity sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow== + commander@~2.13.0: version "2.13.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c"