From a4f8ca65e27f78fb727fef1b95923fbd3f6968d5 Mon Sep 17 00:00:00 2001 From: Volker Hartmann Date: Sat, 11 Feb 2023 17:30:51 +0100 Subject: [PATCH 01/40] Dockerize repo. --- Dockerfile | 3 +++ js/metastore.settings.js | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..31c8363 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,3 @@ +FROM httpd:2.4 +COPY ./ /usr/local/apache2/htdocs/ + diff --git a/js/metastore.settings.js b/js/metastore.settings.js index ddfc5ab..458873f 100644 --- a/js/metastore.settings.js +++ b/js/metastore.settings.js @@ -1,4 +1,4 @@ -export let ajaxBaseUrl = "https://demo.datamanager.kit.edu:8443/metastore/api/v1/"; +export let ajaxBaseUrl = "http://metastore.docker:8040/metastore/api/v1/"; //export let ajaxBaseUrl = "http://localhost:8041/api/v1/"; export const keycloak = Keycloak({ url: 'https://gateway.datamanager.kit.edu:8443/', From 6b9720f969c0be0805f30913b284b21e7964e84f Mon Sep 17 00:00:00 2001 From: Volker Hartmann Date: Sat, 11 Feb 2023 17:51:46 +0100 Subject: [PATCH 02/40] Fix typo --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 31c8363..0c8b821 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,3 @@ FROM httpd:2.4 -COPY ./ /usr/local/apache2/htdocs/ +COPY . /usr/local/apache2/htdocs/ From 2940d825748d27eef40f7a41f46c125eaa3d5d45 Mon Sep 17 00:00:00 2001 From: Volker Hartmann Date: Sat, 11 Feb 2023 18:04:07 +0100 Subject: [PATCH 03/40] Fix baseUrl. --- js/metastore.settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/metastore.settings.js b/js/metastore.settings.js index 458873f..e29a51a 100644 --- a/js/metastore.settings.js +++ b/js/metastore.settings.js @@ -1,4 +1,4 @@ -export let ajaxBaseUrl = "http://metastore.docker:8040/metastore/api/v1/"; +export let ajaxBaseUrl = "http://metastore.docker:8040/api/v1/"; //export let ajaxBaseUrl = "http://localhost:8041/api/v1/"; export const keycloak = Keycloak({ url: 'https://gateway.datamanager.kit.edu:8443/', From 65cca342efb9c3281b06dbe1627da4e8395cb05b Mon Sep 17 00:00:00 2001 From: Volker Hartmann Date: Mon, 13 Feb 2023 14:26:48 +0100 Subject: [PATCH 04/40] Skip dashboard and forward directly to schema management. --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index 2f4b3a5..91eedca 100644 --- a/index.html +++ b/index.html @@ -2,7 +2,7 @@ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> - + From b78b08a1ffb8ba69a0cb8b988516a28bce2d2eeb Mon Sep 17 00:00:00 2001 From: Volker Hartmann Date: Mon, 13 Feb 2023 14:30:44 +0100 Subject: [PATCH 05/40] Disable authentication for MetaStore. --- js/metastore.settings.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/js/metastore.settings.js b/js/metastore.settings.js index e29a51a..4d85fe0 100644 --- a/js/metastore.settings.js +++ b/js/metastore.settings.js @@ -1,16 +1,12 @@ export let ajaxBaseUrl = "http://metastore.docker:8040/api/v1/"; -//export let ajaxBaseUrl = "http://localhost:8041/api/v1/"; -export const keycloak = Keycloak({ - url: 'https://gateway.datamanager.kit.edu:8443/', - realm: 'dem_testing', - clientId: 'kitdm-services' -}); + +export const keycloak = undefined; export const showServiceUrl = false; export const appDescription = { "app-logo":"./images/metadata.jpg", - "app-title":"MetaStore Frontend", + "app-title":"MetaStore Frontend 4 Docker", "app-subtitle":"Schema and Metadata Management" }; From d5dc10313c782a4354a6ff227ff43f3ab78d955c Mon Sep 17 00:00:00 2001 From: Volker Hartmann Date: Tue, 13 Jun 2023 16:05:04 +0200 Subject: [PATCH 06/40] Remove trailing '/' from URLs for MetaStore --- js/metastore-utils.js | 2 +- metadata-management.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/js/metastore-utils.js b/js/metastore-utils.js index 539eab7..85c37b5 100644 --- a/js/metastore-utils.js +++ b/js/metastore-utils.js @@ -288,7 +288,7 @@ export function createSchemaRecord(valueSchemaRecord, schemaDocumentFile) { return new Promise(function (resolve, reject) { $.ajax({ type: "POST", - url: config.ajaxBaseUrl + "schemas/", + url: config.ajaxBaseUrl + "schemas", contentType: false, processData: false, data: formData, diff --git a/metadata-management.html b/metadata-management.html index ce46362..19bf1a6 100644 --- a/metadata-management.html +++ b/metadata-management.html @@ -355,7 +355,7 @@

let selectedMetadataId = null; currentAjaxBaseUrl = ajaxBaseUrl; - ajaxURL = currentAjaxBaseUrl + "ui/metadata/"; + ajaxURL = currentAjaxBaseUrl + "ui/metadata"; config.ajaxBaseUrl = currentAjaxBaseUrl; $('#metastore-base-url').val(currentAjaxBaseUrl); tableDefinitionMetadata.ajaxURL = ajaxURL; From e5c7f3a345c58198b3176d2f5c2e160433bbae53 Mon Sep 17 00:00:00 2001 From: Volker Hartmann Date: Wed, 14 Jun 2023 08:46:50 +0200 Subject: [PATCH 07/40] Remove more trailing '/' from URLs for MetaStore --- js/metastore-utils.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/metastore-utils.js b/js/metastore-utils.js index 85c37b5..4aa2316 100644 --- a/js/metastore-utils.js +++ b/js/metastore-utils.js @@ -72,7 +72,7 @@ export function readSchemaIds(){ let result = undefined; $.ajax({ type: "GET", - url: config.ajaxBaseUrl + "schemas/?size=100", + url: config.ajaxBaseUrl + "schemas?size=100", contentType: "application/json", dataType: 'json', async: false, @@ -248,7 +248,7 @@ export function createMetadataRecord(valueMetadataRecord, metadataDocumentFile) return new Promise(function (resolve, reject) { $.ajax({ type: "POST", - url: config.ajaxBaseUrl + "metadata/", + url: config.ajaxBaseUrl + "metadata", contentType: false, processData: false, data: formData, From d56b8bfa6ff082fa0c04fd3a662683bc2579b120 Mon Sep 17 00:00:00 2001 From: Volker Hartmann Date: Wed, 14 Jun 2023 11:39:35 +0200 Subject: [PATCH 08/40] Remove trailing '/' from output message for MetaStore --- js/metastore-utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/metastore-utils.js b/js/metastore-utils.js index 4aa2316..2ee10c3 100644 --- a/js/metastore-utils.js +++ b/js/metastore-utils.js @@ -85,7 +85,7 @@ export function readSchemaIds(){ result = output; }, error: function (result) { - let message = "Failed to read schema ids from URL " + config.ajaxBaseUrl + "/schemas/" + ". (HTTP " + result.status + ")"; + let message = "Failed to read schema ids from URL " + config.ajaxBaseUrl + "/schemas" + ". (HTTP " + result.status + ")"; result = message; } }); From c755157f06e15a29a152e63a97e502e73669f060 Mon Sep 17 00:00:00 2001 From: Volker Hartmann Date: Fri, 16 Jun 2023 11:39:56 +0200 Subject: [PATCH 09/40] Add search tab to MetaStore. --- js/metastore.settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/metastore.settings.js b/js/metastore.settings.js index ae49de2..616ee0b 100644 --- a/js/metastore.settings.js +++ b/js/metastore.settings.js @@ -3,7 +3,7 @@ export let ajaxBaseUrl = "http://metastore.docker:8040/api/v1/"; export const keycloak = undefined; export const showServiceUrl = false; -export const searchEnabled = false; +export const searchEnabled = true; export const appDescription = { "app-logo":"./images/metadata.jpg", From 33ddcf5805aae2fa9c8ad37f3ac714db1bc2508b Mon Sep 17 00:00:00 2001 From: Volker Hartmann Date: Fri, 16 Jun 2023 11:41:08 +0200 Subject: [PATCH 10/40] Adapt search settings for MetaStore for docker. --- js/elastic-search-metastore.settings.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/js/elastic-search-metastore.settings.js b/js/elastic-search-metastore.settings.js index 98ab8b0..5269d1f 100644 --- a/js/elastic-search-metastore.settings.js +++ b/js/elastic-search-metastore.settings.js @@ -1,11 +1,5 @@ -//export let ajaxBaseUrl = "https://demo.datamanager.kit.edu:8443/metastore/api/v1/"; -export let ajaxBaseUrl = "http://localhost:8041/api/v1/"; +export let ajaxBaseUrl = "http://localhost:8040/api/v1/"; export const keycloak = undefined; -/*Keycloak({ - url: 'https://gateway.datamanager.kit.edu:8443/', - realm: 'dem_testing', - clientId: 'kitdm-services' -});*/ export const showServiceUrl = false; export const page_size = 5; From d1af49a8479d2cec2254606cafe247f87df982c4 Mon Sep 17 00:00:00 2001 From: Volker Hartmann Date: Fri, 16 Jun 2023 11:42:03 +0200 Subject: [PATCH 11/40] Remove trailing '/' for search (MetaStore). --- elastic-search-metastore.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/elastic-search-metastore.html b/elastic-search-metastore.html index 41b5a27..81de0f8 100644 --- a/elastic-search-metastore.html +++ b/elastic-search-metastore.html @@ -416,7 +416,7 @@

//initialize dropdown fields $('.ui.dropdown').dropdown(); - ajaxURL = ajaxBaseUrl + "search/"; + ajaxURL = ajaxBaseUrl + "search"; $('#search-base-url').val(ajaxBaseUrl); config.ajaxBaseUrl = ajaxBaseUrl; From 8a309a3f199d920e661e3862e113876473e886fb Mon Sep 17 00:00:00 2001 From: Volker Hartmann Date: Wed, 5 Jul 2023 14:47:18 +0200 Subject: [PATCH 12/40] Add context path to base URL of metastore. --- js/elastic-search-metastore.settings.js | 2 +- js/metastore.settings.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/js/elastic-search-metastore.settings.js b/js/elastic-search-metastore.settings.js index 5269d1f..33ed6be 100644 --- a/js/elastic-search-metastore.settings.js +++ b/js/elastic-search-metastore.settings.js @@ -1,4 +1,4 @@ -export let ajaxBaseUrl = "http://localhost:8040/api/v1/"; +export let ajaxBaseUrl = "http://metastore.docker:8040/metastore/api/v1/"; export const keycloak = undefined; export const showServiceUrl = false; diff --git a/js/metastore.settings.js b/js/metastore.settings.js index 616ee0b..b33e9c5 100644 --- a/js/metastore.settings.js +++ b/js/metastore.settings.js @@ -1,4 +1,4 @@ -export let ajaxBaseUrl = "http://metastore.docker:8040/api/v1/"; +export let ajaxBaseUrl = "http://metastore.docker:8040/metastore/api/v1/"; export const keycloak = undefined; From 0f57ea58764a1ea37f96df6d70773f4f7acb878b Mon Sep 17 00:00:00 2001 From: Thomas Jejkal Date: Thu, 21 Sep 2023 13:21:41 +0200 Subject: [PATCH 13/40] Reorganization of settings, added customization for dashboard, cleanup, bugfixing, update of README --- README.md | 63 ++-- dashboard.html | 68 ++-- elastic-search-base-repo.html | 3 +- elastic-search-fdo.html | 8 +- elastic-search-metastore.html | 3 +- fdo-creator-ui.html | 6 +- js/apply-config.js | 5 +- js/base-repo.settings.js | 29 -- js/elastic-search-base-repo.settings.js | 21 -- js/elastic-search-fdo.settings.js | 21 -- js/elastic-search-metastore.settings.js | 21 -- js/fdo-maker.settings.js | 17 - js/mapping-service.settings.js | 16 - js/metastore.settings.js | 19 - js/typed-pid-maker.settings.js | 17 - mapping-service-ui.html | 37 +- metadata-management.html | 5 +- miserables.json | 337 ------------------ repo-management.html | 4 +- schema-management.html | 3 +- settings/base-repo.settings.js | 32 ++ settings/dashboard.settings.js | 34 ++ settings/elastic-search-base-repo.settings.js | 16 + settings/elastic-search-fdo.settings.js | 12 + settings/elastic-search-metastore.settings.js | 15 + settings/fdo-maker.settings.js | 10 + settings/general.settings.js | 15 + settings/mapping-service.settings.js | 9 + settings/metastore.settings.js | 18 + settings/typed-pid-maker.settings.js | 10 + test.html | 152 -------- typed-pid-maker-ui.html | 19 +- 32 files changed, 280 insertions(+), 765 deletions(-) delete mode 100644 js/base-repo.settings.js delete mode 100644 js/elastic-search-base-repo.settings.js delete mode 100644 js/elastic-search-fdo.settings.js delete mode 100644 js/elastic-search-metastore.settings.js delete mode 100644 js/fdo-maker.settings.js delete mode 100644 js/mapping-service.settings.js delete mode 100644 js/metastore.settings.js delete mode 100644 js/typed-pid-maker.settings.js delete mode 100644 miserables.json create mode 100644 settings/base-repo.settings.js create mode 100644 settings/dashboard.settings.js create mode 100644 settings/elastic-search-base-repo.settings.js create mode 100644 settings/elastic-search-fdo.settings.js create mode 100644 settings/elastic-search-metastore.settings.js create mode 100644 settings/fdo-maker.settings.js create mode 100644 settings/general.settings.js create mode 100644 settings/mapping-service.settings.js create mode 100644 settings/metastore.settings.js create mode 100644 settings/typed-pid-maker.settings.js delete mode 100644 test.html diff --git a/README.md b/README.md index ab7c0f6..97b9c5d 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ This repository contains a collection of generic web frontends for accessing RESTful services from the KIT Data Manager service portfolio. The idea is to have graphical user interfaces available such that certain base services can be directly used for performing basic tasks without the need of integrating them in your own frontends before being able to use them the first time. -However, for some application cases, these generic web frontends might even be sufficient for direct interaction with our services and they might be offered to the end-user. To allow that, all frontends of this collection offer a certain degree of customization to slightly adapt their presentation to specific needs. +However, for some application cases, these generic web frontends might even be sufficient for direct interaction with our services, and they might be offered to the end-user. To allow that, all frontends of this collection offer a certain degree of customization to slightly adapt their presentation to specific needs. ## Installation @@ -10,7 +10,7 @@ Installing the frontend collection is relatively easy, as it is based only on HT If you don't have Python installed, this would be the first step for you. You may either install Python 2.x or 3.x, depending on your preferences. -Afterwards, you have to clone this repository to a directory of your choice, e.g., /home/user/, and change into the 'frontend-collection' subfolder: +Afterwards, you have to clone this repository to a directory of your choice, e.g., /home/user/, and change into the 'frontend-collection' sub folder: ```bash user@hostname:~ git clone https://github.com/kit-data-manager/frontend-collection @@ -34,29 +34,28 @@ user@hostname:~/frontent-collection python -m http.server Serving HTTP on :: port 8000 (http://[::]:8000/) ... ``` -After this, the output should tell you that the content is served at [http://localhost:8000/](http://localhost:8000/). Hostname and/or port might be different depending on your local configuration. +After this, the output should tell you that the content is served at [http://localhost:8000/](http://localhost:8000/). +Hostname and/or port might be different depending on your local configuration. You can now access the HTML pages of the single frontends directly, which are: -| Service | Frontend Location| -|---------------|------------------| -| [base-repo](https://github.com/kit-data-manager/base-repo) | http://localhost:8000/repo-management.html -| [metastore](https://github.com/kit-data-manager/metastore2) | http://localhost:8000/metadata-management.html or http://localhost:8000/schema-management.html +| Service | Frontend Location| +|------------------------------------------------------------------------|------------------| +| [base-repo](https://github.com/kit-data-manager/base-repo) | http://localhost:8000/repo-management.html +| [metastore](https://github.com/kit-data-manager/metastore2) | http://localhost:8000/metadata-management.html or http://localhost:8000/schema-management.html +| [typed-pid-maker](https://github.com/kit-data-manager/pit-service) | http://localhost:8000/typed-pid-maker-ui.html +| [mapping-service](https://github.com/kit-data-manager/mapping-service) | http://localhost:8000/mapping-service-ui.html +| fdo-creator | http://localhost:8000/fdo-creator-ui.html ## Basic Customization -For basic customization please check the .settings.js files in the js subfolder of this repository. For each frontend, you'll find one settings file, e.g., `base-repo.settings.js` for repo-management.html or `metastore.settings.js` for metadata-management.html and schema-management.html. +For basic customization please check the .settings.js files in the `settings` sub folder of this repository. +Settings for the dashboard page can be found in ´dashboard.settings.js`. +Settings applied for different frontends the same way can be found in `general.settings.js`. +In addition, for each frontend you'll find a specific settings file, e.g., `base-repo.settings.js` for repo-management.html or +`metastore.settings.js` for metadata-management.html and schema-management.html. -Depending on the service, there might be different settings available depending on the service's capabilities. There are some commons property variables listed in the following table: - -| Variable | Description | -|---------------|------------------| -| ajaxBaseUrl | The base URL for requests to this service, e.g., http://localhost:8080/api/v1/ Be aware, that providing a wrong base URL will result in loading errors in the frontend. -| keycloak | If you want to enable authentication via Keycloak, you have to assign a proper value according to the example to this variable. Otherwise, no user login will be provided. -| showServiceUrl | Setting this variable `true` will allow to change ajaxBaseUrl in the frontend. This setting is meant for developers only. In production environments, only `ajaxBaseUrl` should be used. -| appDescription | Here you can customize the header of your frontend, e.g., by providing a custom logo, title, or subtitle. - -For the base-repo frontend, there is another variable named `tags`. This variable allows to provide a list of tags and their color, which are then presented to the user to tag content elements in the frontend. Please note, that tag colors re only used in the frontend and are not stored at the base-repo service. Browsing a base-repo instance with another instance of the frontend having a different tag coloring scheme will render the tags according to the configuration in the currently used frontend instance. +For more information please refer to the documentation inside the setting files. ## Issues @@ -64,27 +63,29 @@ For the base-repo frontend, there is another variable named `tags`. This variabl **The table showing service entries shows an error and no data is loaded.** :grey_exclamation: -Typically, this is an issue with the ajaxBaseURL, which was either provided in the settings.js file or via the input of the frontend page. At first, you should check the format. The URL should look similar to http://localhost:8080/api/v1/ , i.e., it should contain protocol, hostname and port depending on the addressed service instance followed by api/v1/, which is the base path of the API itself and **must** end with / +Typically, this is an issue with the ajaxBaseURL, which was either provided in the service's settings.js file or via the input of the frontend page. +At first, you should check the format. The URL should look similar to http://localhost:8080/api/v1/ or http://localhost:8090/, i.e., +it should contain protocol, hostname and port depending on the addressed service instance optionally followed by an API base path, e.g., api/v1/, +which is the base path of the API itself. The ajaxBaseURL **must** end with / -If everything looks fine, ensure that no authentication is used by the service you want to address. If Keycloak-based authentication is used, please adapt the settings.js accordingly to gain access. +If everything looks fine, ensure that no authentication is used by the service you want to address. If Keycloak-based +authentication is used by the service, please also adapt the `general.settings.js` accordingly to gain access. -If both checks succeed, please also check by which protocol the server providing your frontend is accessible. If it is `https` you are only allowed to load information from `https` resources. Accessing a service via `http` from a frontend running with `https` is not possible for security reasons. +If both checks succeed, please also check by which protocol the server providing your frontend is accessible. +If it is `https` you are only allowed to load information from `https` resources. Accessing a service via `http` +from a frontend running with `https` is not possible for security reasons. +Finally, if everything looks fine so far there might also be an issue with the service itself. Try to access the service without frontend to ensure +it is up and running. --- :grey_question: -**Applying filters to the tables in `metadata-management.html` and `schema-management.html` results in incomplete pages.** - -:grey_exclamation: -The reason here is, that pagination for the MetaStore frontend is build remotely, whereas filering happens on the client-side. In future this will change in a way, that both is done on the client side. - ---- - -:grey_question: **The tables in `repo-management.html` seem not to contain all resources I have in my system.** +**After applying a filter to the MetaStore and base-repo frontends, no results are shown even when I'm sure that there should be one.** :grey_exclamation: -For the base-repo frontent, pagination is done locally instead of remotely. However, for proper local pagination, the Tabulator library we are using for handling tables requires a certain response format which is not yet provided by base-repo. Therefore, Tabulator-wise only one page with 20 elements is loaded. This will change in future. - +The reason here is, that the tables are loaded page-wise with max. 20 entries at once. New data is only loaded on scrolling. As filtering +happens on the client-side, only the data already loaded is filtered. This may result in an empty table if elements known to match +the filter criteria are not loaded yet. The only solution for this for now is scrolling the table to the end before applying filters. ## License diff --git a/dashboard.html b/dashboard.html index 13dd504..7c8ac3a 100644 --- a/dashboard.html +++ b/dashboard.html @@ -10,8 +10,9 @@ + + href="https://cdn.jsdelivr.net/npm/@kit-data-manager/metadata-editor@0.9.3/deps/opt/fontawesome/css/all.min.css"> - - -
-
-

Simulation activity

-
-
-
-

Shifts the view, so the graph is centered at this location.

- - -
- -
-

Attracts (+) or repels (-) nodes to/from each other.

- - - -
- -
-

Prevents nodes from overlapping

- - - -
- -
-

Acts like gravity. Pulls all points towards an X location.

- - -
- -
-

Acts like gravity. Pulls all points towards a Y location.

- - -
- -
-

Sets link length

- - -
-
- - - - - diff --git a/typed-pid-maker-ui.html b/typed-pid-maker-ui.html index ca361fe..83ccd41 100644 --- a/typed-pid-maker-ui.html +++ b/typed-pid-maker-ui.html @@ -14,6 +14,7 @@ +

@@ -55,18 +56,20 @@

+

+ Use this field to connect to an instance of the Typed PID Maker. +

-

- Use this field to connect to an instance of the Typed PID Maker. -

- - + + - \ No newline at end of file + From 9f18807ecba98abbd8b26b83f1f9325aff508c25 Mon Sep 17 00:00:00 2001 From: Thomas Jejkal Date: Thu, 21 Sep 2023 22:10:10 +0200 Subject: [PATCH 14/40] Improved progressive loading in MetaStore and base-repo frontends, increased table size for improved screen usage in MetaStore and base-repo frontends, added download for metdata schemas and documents, fix #39 --- .../base-repo/tableDefinitionResource.js | 5 +- .../metastore/tableDefinitionMetadata.js | 7 +- .../metastore/tableDefinitionSchema.js | 5 +- js/apply-config.js | 47 +++++--- metadata-management.html | 110 ++++++------------ repo-management.html | 33 ++++-- schema-management.html | 100 ++++++---------- settings/general.settings.js | 13 ++- settings/metastore.settings.js | 2 +- 9 files changed, 147 insertions(+), 175 deletions(-) diff --git a/definitions/base-repo/tableDefinitionResource.js b/definitions/base-repo/tableDefinitionResource.js index 36756ff..b3490b6 100644 --- a/definitions/base-repo/tableDefinitionResource.js +++ b/definitions/base-repo/tableDefinitionResource.js @@ -2,14 +2,15 @@ let tableDefinitionResource = { layout: "fitDataFill", responsiveLayout: "collapse", ajaxURL: undefined, - ajaxProgressiveLoad:"scroll", + //ajaxProgressiveLoad:"scroll", + ajaxProgressiveLoad:"load", ajaxProgressiveLoadDelay:50, groupBy: function(data){ //let identifier = data.schema.identifier //let version = identifier.substring(identifier.lastIndexOf('?') + 1) return [data.publisher, data.publicationYear] ; }, - height: 400, + height: "90%", paginationSize: 10, paginationSizeSelector: [3, 6, 8, 10, 15, 20], dataLoading: function(data) { diff --git a/definitions/metastore/tableDefinitionMetadata.js b/definitions/metastore/tableDefinitionMetadata.js index 0a905ca..e46ab49 100644 --- a/definitions/metastore/tableDefinitionMetadata.js +++ b/definitions/metastore/tableDefinitionMetadata.js @@ -2,15 +2,16 @@ let tableDefinitionMetadata = { layout: "fitDataFill", responsiveLayout: "collapse", ajaxURL: undefined, - ajaxProgressiveLoad:"scroll", - ajaxProgressiveLoadDelay:50, + //ajaxProgressiveLoad:"scroll", + ajaxProgressiveLoad:"load", + ajaxProgressiveLoadDelay:100, groupBy: function(data){ let identifier = data.schema.identifier let version = identifier.substring(identifier.lastIndexOf('?') + 1) return identifier.substring(identifier.lastIndexOf('/') + 1, identifier.lastIndexOf('?')) + " (" + version + ")" ; }, - height: 400, + height: "90%", paginationSize: 10, paginationSizeSelector: [3, 6, 8, 10, 15, 20] /* for modifying data while loading, diff --git a/definitions/metastore/tableDefinitionSchema.js b/definitions/metastore/tableDefinitionSchema.js index c2ef7bb..a2466a5 100644 --- a/definitions/metastore/tableDefinitionSchema.js +++ b/definitions/metastore/tableDefinitionSchema.js @@ -2,7 +2,8 @@ let tableDefinitionMetadata = { layout: "fitDataFill", responsiveLayout: "collapse", ajaxURL: undefined, - ajaxProgressiveLoad:"scroll", + //ajaxProgressiveLoad:"scroll", + ajaxProgressiveLoad:"load", ajaxProgressiveLoadDelay:50, groupBy: function(data){ let identifier = data.schemaId @@ -10,7 +11,7 @@ let tableDefinitionMetadata = { return identifier + " (" + version + ")" ; }, - height: 400, + height: "90%", paginationSize: 10, paginationSizeSelector: [3, 6, 8, 10, 15, 20] /* for modifying data while loading, diff --git a/js/apply-config.js b/js/apply-config.js index 2c9da72..99b3543 100644 --- a/js/apply-config.js +++ b/js/apply-config.js @@ -1,47 +1,65 @@ // requires jQuery in HTML, like this: // +let keycloak = undefined; +let config = undefined; -function userLoggedIn(login) { - if (login) { +function userLoggedIn(_login, _messageCallback, _loginCallback) { + let username = undefined; + if (_login) { $("#login_icon").attr("class", "sign-out icon") $("#login_button_text").text("Logout"); - addMessage(0, 'User ' + keycloak.idTokenParsed.preferred_username + ' logged in.'); + _messageCallback(0, 'User ' + keycloak.idTokenParsed.preferred_username + ' logged in.'); config.token = keycloak.token; + localStorage.setItem("userLoggedIn", true); + localStorage.setItem("token", config.token); + username = keycloak.idTokenParsed.preferred_username; } else { $("#login_icon").attr("class", "sign-in icon") $("#login_button_text").text("Login"); config.token = null; + localStorage.removeItem("userLoggedIn", true); + localStorage.removeItem("token", true); } - reloadTable(); + _loginCallback(_login, username); } -function applyConfig(keycloak, showServiceUrl, appDescription) { - if (!showServiceUrl) { +function applyConfig(_keycloak, + _showServiceUrl, + _appDescription, + _config, + _messageCallback = (status, message) => console.log((status == 0)?"INFO: ":"ERROR:" + ": " + message), + _loginCallback= (loggedIn, username) => console.log("Logged in: " + loggedIn + "as User: " + username)) { + keycloak = _keycloak; + config = _config; + if (!_showServiceUrl) { $('#service-url-input').empty(); } // set header - $('#app-logo').attr("src", appDescription["app-logo"]); - let header = appDescription["app-title"] + - '
' + appDescription["app-subtitle"] + '
'; + $('#app-logo').attr("src", _appDescription["app-logo"]); + let header = _appDescription["app-title"] + + '
' + _appDescription["app-subtitle"] + '
'; $('#app-title').html(header); if (typeof keycloak != typeof undefined) { keycloak.onAuthSuccess = function () { - userLoggedIn(true); + userLoggedIn(true, _messageCallback, _loginCallback); }; keycloak.onAuthLogout = function () { - userLoggedIn(false); + userLoggedIn(false, _messageCallback, _loginCallback); }; keycloak.onTokenExpired = () => { addMessage(0, 'Keycloak token expired. Trying to refresh.'); keycloak.updateToken(30).success(() => { - addMessage(0, 'Successfully got a new token.'); + _messageCallback(0, 'Successfully got a new token.'); config.token = keycloak.token; + if(loginCallback) loginCallback(true, keycloak.idTokenParsed.preferred_username); }).catch(() => { - addMessage(1, "Failed to refresh keycloak token."); + _messageCallback(1, "Failed to refresh keycloak token."); + userLoggedIn(false, _messageCallback, _loginCallback) config.token = null; + if(loginCallback) loginCallback(false, undefined); }); }; @@ -58,5 +76,8 @@ function applyConfig(keycloak, showServiceUrl, appDescription) { }); } else { $("#login_button").attr("style", "display:none"); + if($("#logged_in_as")) { + $("#logged_in_as").attr("style", "display:none"); + } } } diff --git a/metadata-management.html b/metadata-management.html index 0603131..baf750b 100644 --- a/metadata-management.html +++ b/metadata-management.html @@ -20,6 +20,7 @@ + @@ -42,6 +43,8 @@ + + @@ -119,7 +122,7 @@

-
+
@@ -189,9 +192,8 @@

-
+ @@ -246,6 +248,12 @@

+
+ +
+ +
+
@@ -259,8 +267,6 @@

- - @@ -278,78 +284,19 @@

import {keycloak, showServiceUrl} from './settings/general.settings.js'; import {ajaxBaseUrl, appDescription, searchEnabled} from './settings/metastore.settings.js'; - if (!showServiceUrl) { - $('#service-url-input').empty(); - } - - if (!searchEnabled) { - $('#search-tab').empty(); - } - - $('#app-logo').attr("src", appDescription["app-logo"]); - let header = appDescription["app-title"] + - '
' + appDescription["app-subtitle"] + '
'; - - $('#app-title').html(header); - - if (typeof keycloak != typeof undefined) { - keycloak.onAuthSuccess = function () { - userLoggedIn(true); - }; - keycloak.onAuthLogout = function () { - userLoggedIn(false); - }; - - keycloak.onTokenExpired = () => { - addMessage(0, 'Keycloak token expired. Trying to refresh.'); - keycloak.updateToken(30).success(() => { - addMessage(0, 'Successfully got a new token.'); - config.token = keycloak.token; - reloadTable(); - }).catch(() => { - addMessage(1, "Failed to refresh keycloak token."); - config.token = null; - userLoggedIn(false); - reloadTable(); - }); - }; - - keycloak.init({ - responseMode: 'fragment' - }); - - $("#login_button").click(() => { - if ($("#login_button_text").text() === "Login") { - keycloak.login(); - } else { - keycloak.logout(); - } - }); - } else { - $("#login_button").attr("style", "display:none"); - $("#logged_in_as").attr("style", "display:none"); - } - - function userLoggedIn(login) { - if (login) { - $("#login_icon").attr("class", "sign-out icon") - $("#login_button_text").text("Logout"); - addMessage(0, 'User ' + keycloak.idTokenParsed.preferred_username + ' logged in.'); - localStorage.setItem("userLoggedIn", true); - $("#logged_in_as").text("Logged in as " + keycloak.idTokenParsed.preferred_username); + applyConfig(keycloak, showServiceUrl,appDescription, config, addMessage, (login, username) => { + if(login){ + $("#logged_in_as").text("Logged in as " + username); $("#editor-create-button").removeAttr("disabled"); - config.token = keycloak.token; - localStorage.setItem("token", config.token); - } else { - $("#login_icon").attr("class", "sign-in icon") - $("#login_button_text").text("Login"); - localStorage.removeItem("userLoggedIn", true); + }else{ $("#logged_in_as").text("Not logged in."); $("#editor-create-button").attr("disabled", "disabled"); - config.token = null; - localStorage.removeItem("token", true); } reloadTable(); + }); + + if (!searchEnabled) { + $('#search-tab').empty(); } JSONForm.elementTypes.typeahead = typeahead; @@ -518,6 +465,18 @@

return result; } + /** Download the current document from the monaco editor. + */ + function downloadDocumentFromMonaco() { + if (rightModel != null) { + if (rightModel._languageId === "json") { + download(rightModel.getValue(), "metadata.json", "application/json"); + } else { + download(rightModel.getValue(), "metadata.xml", "application/xml"); + } + } + } + function doUpdateMetadata() { documentFile = getDocumentFromMonaco(false); @@ -824,7 +783,7 @@

reloadTable(); }); - //schema version selection handler + //document version selection handler $("#document-version-button").click(() => { let url = currentAjaxBaseUrl + "metadata/" + selectedMetadataId + "?version=" + $("#document-version").val(); //Obtain schema for record @@ -837,6 +796,11 @@

}); + //document download handler + $("#document-download-button").click(() => { + downloadDocumentFromMonaco(); + }); + if (localStorage.getItem("userLoggedIn")) { localStorage.removeItem("userLoggedIn") $("#login_button").click(); diff --git a/repo-management.html b/repo-management.html index c72e2d4..5ab711d 100644 --- a/repo-management.html +++ b/repo-management.html @@ -39,6 +39,8 @@ + + @@ -110,7 +112,7 @@

-
+
@@ -178,7 +180,7 @@

-
+ @@ -273,9 +275,24 @@

import {keycloak, showServiceUrl} from './settings/general.settings.js'; import {ajaxBaseUrl, tags, searchEnabled, appDescription} from './settings/base-repo.settings.js'; + applyConfig(keycloak, showServiceUrl,appDescription, config, addMessage, (login, username) => { + if(login){ + $("#logged_in_as").text("Logged in as " + username); + $("#editor-create-button").removeAttr("disabled"); + }else{ + $("#logged_in_as").text("Not logged in."); + $("#editor-create-button").attr("disabled", "disabled"); + } + reloadTable(); + }); + + if (!searchEnabled) { + $('#search-tab').empty(); + } + fillTags(tags); - if (!showServiceUrl) { + /*if (!showServiceUrl) { $('#service-url-input').empty(); } @@ -288,7 +305,7 @@

'
' + appDescription["app-subtitle"] + '
'; $('#app-title').html(header); - +*/ /* Fill options with model definitions for metadata record. */ let options = { dataModel: model, @@ -305,7 +322,7 @@

* and sets the token which is used for authenticated remote operations. * @param {boolean} login TRUE in case of a login, FALSE for logout operation. */ - function userLoggedIn(login) { + /* function userLoggedIn(login) { if (login) { $("#login_icon").attr("class", "sign-out icon") $("#login_button_text").text("Logout"); @@ -323,9 +340,9 @@

config.token = null; } reloadTable(); - } + }*/ - if (typeof keycloak != typeof undefined) { + /* if (typeof keycloak != typeof undefined) { keycloak.onAuthSuccess = function () { userLoggedIn(true); }; @@ -362,7 +379,7 @@

$("#logged_in_as").attr("style", "display:none"); $("#login_button").attr("style", "display:none"); } - +*/ /**Apply the provided tag via PATCH operation to the content information entry/entries selected in the table. * @param {String} tag The tag to add. */ diff --git a/schema-management.html b/schema-management.html index 153f2e6..a27a3b6 100644 --- a/schema-management.html +++ b/schema-management.html @@ -15,6 +15,7 @@ integrity="sha512-qTXRIMyZIFb8iQcfjXWCO8+M5Tbc38Qi5WzdPOYZHIlZpzBHG3L3by84BBBOiRGiEb7KKtAOAs5qYdUiZiQNNQ==" crossorigin="anonymous" referrerpolicy="no-referrer"> + @@ -23,7 +24,6 @@ - + + @@ -111,7 +113,7 @@

-
+
@@ -181,7 +183,7 @@

-
+ @@ -238,6 +240,12 @@

+
+ +
+ +
+
@@ -265,80 +273,21 @@

import {keycloak, showServiceUrl} from './settings/general.settings.js'; import {ajaxBaseUrl, searchEnabled, appDescription} from './settings/metastore.settings.js'; - function userLoggedIn(login) { - if (login) { - $("#login_icon").attr("class", "sign-out icon") - $("#login_button_text").text("Logout"); - addMessage(0, 'User ' + keycloak.idTokenParsed.preferred_username + ' logged in.'); - localStorage.setItem("userLoggedIn", true); - $("#logged_in_as").text("Logged in as " + keycloak.idTokenParsed.preferred_username); + applyConfig(keycloak, showServiceUrl,appDescription, config, addMessage, (login, username) => { + if(login){ + $("#logged_in_as").text("Logged in as " + username); $("#editor-create-button").removeAttr("disabled"); - config.token = keycloak.token; - } else { - $("#login_icon").attr("class", "sign-in icon") - $("#login_button_text").text("Login"); - localStorage.removeItem("userLoggedIn", true); + }else{ $("#logged_in_as").text("Not logged in."); $("#editor-create-button").attr("disabled", "disabled"); - config.token = null; } reloadTable(); - } - - if (!showServiceUrl) { - $('#service-url-input').empty(); - } + }); if (!searchEnabled) { $('#search-tab').empty(); } - $('#app-logo').attr("src", appDescription["app-logo"]); - let header = appDescription["app-title"] + - '
' + appDescription["app-subtitle"] + '
'; - - $('#app-title').html(header); - - - //enable keycloak if defined - if (typeof keycloak != typeof undefined) { - keycloak.onAuthSuccess = function () { - userLoggedIn(true); - }; - keycloak.onAuthLogout = function () { - userLoggedIn(false); - }; - - keycloak.onTokenExpired = () => { - addMessage(0, 'Keycloak token expired. Trying to refresh.'); - keycloak.updateToken(30).success(() => { - addMessage(0, 'Successfully got a new token.'); - config.token = keycloak.token; - reloadTable(); - }).catch(() => { - addMessage(1, "Failed to refresh keycloak token."); - config.token = null; - userLoggedIn(false); - reloadTable(); - }); - }; - - - keycloak.init({ - responseMode: 'fragment', - }); - - $("#login_button").click(() => { - if ($("#login_button_text").text() === "Login") { - keycloak.login(); - } else { - keycloak.logout(); - } - }); - } else { - $("#logged_in_as").attr("style", "display:none"); - $("#login_button").attr("style", "display:none"); - } let table = null; let ajaxURL = null; let currentAjaxBaseUrl = null; @@ -497,6 +446,18 @@

return result; } + /** Download the current schema from the monaco editor. + */ + function downloadDocumentFromMonaco() { + if (rightModel != null) { + if (rightModel._languageId === "json") { + download(rightModel.getValue(), "schema.json", "application/json"); + } else { + download(rightModel.getValue(), "schema.xsd", "application/xml"); + } + } + } + function doUpdateSchema() { let schema = getDocumentFromMonaco(); if (!validatedRecord) { @@ -812,6 +773,11 @@

}) }); + //document download handler + $("#schema-download-button").click(() => { + downloadDocumentFromMonaco(); + }); + if (localStorage.getItem("userLoggedIn")) { localStorage.removeItem("userLoggedIn") $("#login_button").click(); diff --git a/settings/general.settings.js b/settings/general.settings.js index 4e1142f..7cb9ca4 100644 --- a/settings/general.settings.js +++ b/settings/general.settings.js @@ -1,10 +1,11 @@ //Keycloak configuration to use Keycloak as identity provider for single sign-on. -export const keycloak = undefined; -/*Keycloak({ - url: 'https://gateway.datamanager.kit.edu:8443/', - realm: 'dem_testing', - clientId: 'kitdm-services' -});*/ +export const keycloak //= undefined; += Keycloak({ + // url: 'https://gateway.datamanager.kit.edu:8443/', + url: 'http://localhost:8080/auth/', + realm: 'myrealm', + clientId: 'keycloak-angular' +}); //Show the input for the backend service URL. This property should only be enabled for debugging. export const showServiceUrl = false; diff --git a/settings/metastore.settings.js b/settings/metastore.settings.js index 000b6b6..b0f4f2b 100644 --- a/settings/metastore.settings.js +++ b/settings/metastore.settings.js @@ -1,5 +1,5 @@ //The backend service URL for the MetaStore instance used by the frontend. -export const ajaxBaseUrl = "http://localhost:8041/api/v1/"; +export const ajaxBaseUrl = "http://localhost:8040/api/v1/"; //export const ajaxBaseUrl = "https://demo.datamanager.kit.edu:8443/metastore/api/v1/"; //The app description used to customize the frontend, e.g., for a specific project with a custom title and subtitle. From 94a2544beec1470578197eaeef0b92bd79816e68 Mon Sep 17 00:00:00 2001 From: Thomas Jejkal Date: Fri, 22 Sep 2023 10:47:23 +0200 Subject: [PATCH 15/40] Fixed issue that actions are hidden if table acts responsively, added login on reload for repo-management --- .../base-repo/tableDefinitionResource.js | 16 ++-- js/editor/lib/js/metadataeditor.js | 8 +- metadata-management.html | 2 +- repo-management.html | 83 ++----------------- settings/general.settings.js | 7 +- settings/metastore.settings.js | 2 +- 6 files changed, 25 insertions(+), 93 deletions(-) diff --git a/definitions/base-repo/tableDefinitionResource.js b/definitions/base-repo/tableDefinitionResource.js index b3490b6..9e4b23c 100644 --- a/definitions/base-repo/tableDefinitionResource.js +++ b/definitions/base-repo/tableDefinitionResource.js @@ -4,7 +4,7 @@ let tableDefinitionResource = { ajaxURL: undefined, //ajaxProgressiveLoad:"scroll", ajaxProgressiveLoad:"load", - ajaxProgressiveLoadDelay:50, + ajaxProgressiveLoadDelay:100, groupBy: function(data){ //let identifier = data.schema.identifier //let version = identifier.substring(identifier.lastIndexOf('?') + 1) @@ -14,12 +14,12 @@ let tableDefinitionResource = { paginationSize: 10, paginationSizeSelector: [3, 6, 8, 10, 15, 20], dataLoading: function(data) { - for(let i=0;i "Accept": 'application/tabulator+json; charset=utf-8', } }; - table.setData(ajaxURL); + table.setData(ajaxURL, {}, ajaxConfig); } } } diff --git a/repo-management.html b/repo-management.html index 5ab711d..0e72f3d 100644 --- a/repo-management.html +++ b/repo-management.html @@ -292,20 +292,6 @@

fillTags(tags); - /*if (!showServiceUrl) { - $('#service-url-input').empty(); - } - - if (!searchEnabled) { - $('#search-tab').empty(); - } - - $('#app-logo').attr("src", appDescription["app-logo"]); - let header = appDescription["app-title"] + - '
' + appDescription["app-subtitle"] + '
'; - - $('#app-title').html(header); -*/ /* Fill options with model definitions for metadata record. */ let options = { dataModel: model, @@ -322,64 +308,7 @@

* and sets the token which is used for authenticated remote operations. * @param {boolean} login TRUE in case of a login, FALSE for logout operation. */ - /* function userLoggedIn(login) { - if (login) { - $("#login_icon").attr("class", "sign-out icon") - $("#login_button_text").text("Logout"); - addMessage(0, 'User ' + keycloak.idTokenParsed.preferred_username + ' logged in.'); - localStorage.setItem("userLoggedIn", true); - $("#logged_in_as").text("Logged in as " + keycloak.idTokenParsed.preferred_username); - $("#editor-create-button").removeAttr("disabled"); - config.token = keycloak.token; - } else { - $("#login_icon").attr("class", "sign-in icon") - $("#login_button_text").text("Login"); - localStorage.removeItem("userLoggedIn", true); - $("#logged_in_as").text("Not logged in."); - $("#editor-create-button").attr("disabled", "disabled"); - config.token = null; - } - reloadTable(); - }*/ - /* if (typeof keycloak != typeof undefined) { - keycloak.onAuthSuccess = function () { - userLoggedIn(true); - }; - keycloak.onAuthLogout = function () { - userLoggedIn(false); - }; - - keycloak.onTokenExpired = () => { - addMessage(0, 'Keycloak token expired. Trying to refresh.'); - keycloak.updateToken(30).success(() => { - addMessage(0, 'Successfully got a new token.'); - config.token = keycloak.token; - reloadTable(); - }).catch(() => { - addMessage(1, "Failed to refresh keycloak token."); - config.token = null; - userLoggedIn(false); - reloadTable(); - }); - }; - - keycloak.init({ - responseMode: 'fragment', - }); - - $("#login_button").click(() => { - if ($("#login_button_text").text() === "Login") { - keycloak.login(); - } else { - keycloak.logout(); - } - }); - } else { - $("#logged_in_as").attr("style", "display:none"); - $("#login_button").attr("style", "display:none"); - } -*/ /**Apply the provided tag via PATCH operation to the content information entry/entries selected in the table. * @param {String} tag The tag to add. */ @@ -395,7 +324,6 @@

addMessage(1, error); }); } - } /**Fill in the list of tags. @@ -428,7 +356,7 @@

tableDefinitionResource.ajaxError = function (cell, value) { addMessage(1, "Failed to access backend service at " + ajaxURL); }; - tableDefinitionContent.ajaxURL = ajaxURL + "?page=0&size=100"; + tableDefinitionContent.ajaxURL = ajaxURL ; tableDefinitionContent.ajaxError = function (cell, value) { addMessage(1, "Failed to access backend service at " + ajaxURL); }; @@ -750,6 +678,11 @@

reloadTable(); }); + if (localStorage.getItem("userLoggedIn")) { + localStorage.removeItem("userLoggedIn") + $("#login_button").click(); + } + if (typeof keycloak != typeof undefined && config.token == null) { $("#editor-create-button").attr("disabled", "disabled"); } @@ -769,7 +702,7 @@

"Authorization": "Bearer " + config.token } }; - table.setData(ajaxURL + "?page=0&size=50", {}, ajaxConfig); + table.setData(ajaxURL, {}, ajaxConfig); } else { let ajaxConfig = { method: "GET", @@ -777,7 +710,7 @@

"Accept": 'application/tabulator+json; charset=utf-8', } }; - table.setData(ajaxURL + "?page=0&size=50", {}, ajaxConfig); + table.setData(ajaxURL, {}, ajaxConfig); } } } diff --git a/settings/general.settings.js b/settings/general.settings.js index 7cb9ca4..90fa6cb 100644 --- a/settings/general.settings.js +++ b/settings/general.settings.js @@ -1,10 +1,9 @@ //Keycloak configuration to use Keycloak as identity provider for single sign-on. export const keycloak //= undefined; = Keycloak({ - // url: 'https://gateway.datamanager.kit.edu:8443/', - url: 'http://localhost:8080/auth/', - realm: 'myrealm', - clientId: 'keycloak-angular' + url: 'https://gateway.datamanager.kit.edu:8443/', + realm: 'dem_testing', + clientId: 'kitdm-services' }); //Show the input for the backend service URL. This property should only be enabled for debugging. diff --git a/settings/metastore.settings.js b/settings/metastore.settings.js index b0f4f2b..000b6b6 100644 --- a/settings/metastore.settings.js +++ b/settings/metastore.settings.js @@ -1,5 +1,5 @@ //The backend service URL for the MetaStore instance used by the frontend. -export const ajaxBaseUrl = "http://localhost:8040/api/v1/"; +export const ajaxBaseUrl = "http://localhost:8041/api/v1/"; //export const ajaxBaseUrl = "https://demo.datamanager.kit.edu:8443/metastore/api/v1/"; //The app description used to customize the frontend, e.g., for a specific project with a custom title and subtitle. From aeee948e0bb1585c882449bd912beb7d210cd67f Mon Sep 17 00:00:00 2001 From: Thomas Jejkal Date: Sat, 23 Sep 2023 15:49:48 +0200 Subject: [PATCH 16/40] Added landing page for public repo resources --- compile.sh | 11 + definitions/base-repo/landingpage.handlebars | 161 ++++++++++++ .../base-repo/landingpage.handlebars.js | 156 ++++++++++++ definitions/search/compile.sh | 6 - elastic-search-base-repo.html | 76 ++---- repo-landing-page.html | 232 ++++++++++++++++++ settings/base-repo.settings.js | 2 +- settings/general.settings.js | 8 +- 8 files changed, 579 insertions(+), 73 deletions(-) create mode 100644 compile.sh create mode 100644 definitions/base-repo/landingpage.handlebars create mode 100644 definitions/base-repo/landingpage.handlebars.js delete mode 100644 definitions/search/compile.sh create mode 100644 repo-landing-page.html diff --git a/compile.sh b/compile.sh new file mode 100644 index 0000000..aa2e367 --- /dev/null +++ b/compile.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +for FILE in ./definitions/search/*.handlebars; +do +handlebars $FILE -f "${FILE}.js" +done + +for FILE in ./definitions/base-repo/*.handlebars; +do +handlebars $FILE -f "${FILE}.js" +done diff --git a/definitions/base-repo/landingpage.handlebars b/definitions/base-repo/landingpage.handlebars new file mode 100644 index 0000000..9871b5d --- /dev/null +++ b/definitions/base-repo/landingpage.handlebars @@ -0,0 +1,161 @@ + +
+
+ +
+
+ +
+
+

{{titles.0.value}}

+
+
+ + {{resourceType.typeGeneral}}
+
{{resourceType.value}}
+
+
+
+ +
+
+ + {{#creatorsList creators}}{{/creatorsList}} + +
+
+ +
+
+ {{#if descriptions.0.description}} + {{descriptions.0.description}} + {{else}} + No description available + {{/if}} +
+
+ +
+
+
+ + + + {{#if content.0.relativePath}} + {{#each content}} +
+
+
+ +
{{hash}}
+
+
+
+ {{/each}} + {{else}} + No content uploaded, yet. + {{/if}} +
+
+
+
+
+ +
+
+
+

Metadata

+ Publisher:
+ {{publisher}}
+ Publication Year:
+ {{publicationYear}}
+ Created at:
+ {{formatDate created}}
+ Last Modified:
+ {{formatDate lastUpdate}}
+ License:
+
+ {{#if rights.0.schemeId}} + {{#each rights}} +
+ +
+ {{/each}} + {{else}} +
+
+
No license assigned
+
+
+ {{/if}} +
+
+ Related Identifiers:
+
+ {{#if relatedIdentifiers.0.value}} + {{#each relatedIdentifiers}} +
+
+ {{splitUrl value}} +
({{relationType}})
+
+
+ {{/each}} + {{else}} +
+
+
No related identifiers assigned
+
+
+ {{/if}} +
+ Alternate Identifiers:
+
+ {{#if alternateIdentifiers.0.value}} + {{#each alternateIdentifiers}} +
+
+ {{splitUrl value}} +
({{identifierType}})
+
+
+ {{/each}} + {{else}} +
+
+
No alternate identifiers assigned
+
+
+ {{/if}} +
+
+
+ +
+
+

Downloads

+
+ JSON +
+
+ ZIP +
+
+
+
+
+
+ diff --git a/definitions/base-repo/landingpage.handlebars.js b/definitions/base-repo/landingpage.handlebars.js new file mode 100644 index 0000000..86407fe --- /dev/null +++ b/definitions/base-repo/landingpage.handlebars.js @@ -0,0 +1,156 @@ +(function() { + var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {}; +templates['landingpage'] = template({"1":function(container,depth0,helpers,partials,data) { + return ""; +},"3":function(container,depth0,helpers,partials,data) { + var stack1, lookupProperty = container.lookupProperty || function(parent, propertyName) { + if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { + return parent[propertyName]; + } + return undefined + }; + + return " " + + container.escapeExpression(container.lambda(((stack1 = ((stack1 = (depth0 != null ? lookupProperty(depth0,"descriptions") : depth0)) != null ? lookupProperty(stack1,"0") : stack1)) != null ? lookupProperty(stack1,"description") : stack1), depth0)) + + "\n"; +},"5":function(container,depth0,helpers,partials,data) { + return " No description available\n"; +},"7":function(container,depth0,helpers,partials,data) { + var stack1, lookupProperty = container.lookupProperty || function(parent, propertyName) { + if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { + return parent[propertyName]; + } + return undefined + }; + + return ((stack1 = lookupProperty(helpers,"each").call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? lookupProperty(depth0,"content") : depth0),{"name":"each","hash":{},"fn":container.program(8, data, 0),"inverse":container.noop,"data":data,"loc":{"start":{"line":54,"column":32},"end":{"line":64,"column":41}}})) != null ? stack1 : ""); +},"8":function(container,depth0,helpers,partials,data) { + var helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=container.hooks.helperMissing, alias3=container.escapeExpression, alias4="function", lookupProperty = container.lookupProperty || function(parent, propertyName) { + if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { + return parent[propertyName]; + } + return undefined + }; + + return "
\n
\n
\n \n
" + + alias3(((helper = (helper = lookupProperty(helpers,"hash") || (depth0 != null ? lookupProperty(depth0,"hash") : depth0)) != null ? helper : alias2),(typeof helper === alias4 ? helper.call(alias1,{"name":"hash","hash":{},"data":data,"loc":{"start":{"line":60,"column":73},"end":{"line":60,"column":81}}}) : helper))) + + "
\n
\n
\n
\n"; +},"10":function(container,depth0,helpers,partials,data) { + return " No content uploaded, yet.\n"; +},"12":function(container,depth0,helpers,partials,data) { + var stack1, lookupProperty = container.lookupProperty || function(parent, propertyName) { + if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { + return parent[propertyName]; + } + return undefined + }; + + return ((stack1 = lookupProperty(helpers,"each").call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? lookupProperty(depth0,"rights") : depth0),{"name":"each","hash":{},"fn":container.program(13, data, 0),"inverse":container.noop,"data":data,"loc":{"start":{"line":89,"column":24},"end":{"line":95,"column":33}}})) != null ? stack1 : ""); +},"13":function(container,depth0,helpers,partials,data) { + var helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=container.hooks.helperMissing, alias3="function", alias4=container.escapeExpression, lookupProperty = container.lookupProperty || function(parent, propertyName) { + if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { + return parent[propertyName]; + } + return undefined + }; + + return " \n"; +},"15":function(container,depth0,helpers,partials,data) { + return "
\n
\n
No license assigned
\n
\n
\n"; +},"17":function(container,depth0,helpers,partials,data) { + var stack1, lookupProperty = container.lookupProperty || function(parent, propertyName) { + if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { + return parent[propertyName]; + } + return undefined + }; + + return ((stack1 = lookupProperty(helpers,"each").call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? lookupProperty(depth0,"relatedIdentifiers") : depth0),{"name":"each","hash":{},"fn":container.program(18, data, 0),"inverse":container.noop,"data":data,"loc":{"start":{"line":108,"column":28},"end":{"line":115,"column":37}}})) != null ? stack1 : ""); +},"18":function(container,depth0,helpers,partials,data) { + var helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=container.hooks.helperMissing, alias3="function", alias4=container.escapeExpression, lookupProperty = container.lookupProperty || function(parent, propertyName) { + if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { + return parent[propertyName]; + } + return undefined + }; + + return "
\n
\n " + + alias4((lookupProperty(helpers,"splitUrl")||(depth0 && lookupProperty(depth0,"splitUrl"))||alias2).call(alias1,(depth0 != null ? lookupProperty(depth0,"value") : depth0),{"name":"splitUrl","hash":{},"data":data,"loc":{"start":{"line":111,"column":91},"end":{"line":111,"column":109}}})) + + "\n
(" + + alias4(((helper = (helper = lookupProperty(helpers,"relationType") || (depth0 != null ? lookupProperty(depth0,"relationType") : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"relationType","hash":{},"data":data,"loc":{"start":{"line":112,"column":66},"end":{"line":112,"column":82}}}) : helper))) + + ")
\n
\n
\n"; +},"20":function(container,depth0,helpers,partials,data) { + return "
\n
\n
No related identifiers assigned
\n
\n
\n"; +},"22":function(container,depth0,helpers,partials,data) { + var stack1, lookupProperty = container.lookupProperty || function(parent, propertyName) { + if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { + return parent[propertyName]; + } + return undefined + }; + + return ((stack1 = lookupProperty(helpers,"each").call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? lookupProperty(depth0,"alternateIdentifiers") : depth0),{"name":"each","hash":{},"fn":container.program(23, data, 0),"inverse":container.noop,"data":data,"loc":{"start":{"line":127,"column":28},"end":{"line":134,"column":37}}})) != null ? stack1 : ""); +},"23":function(container,depth0,helpers,partials,data) { + var helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=container.hooks.helperMissing, alias3="function", alias4=container.escapeExpression, lookupProperty = container.lookupProperty || function(parent, propertyName) { + if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { + return parent[propertyName]; + } + return undefined + }; + + return "
\n
\n " + + alias4((lookupProperty(helpers,"splitUrl")||(depth0 && lookupProperty(depth0,"splitUrl"))||alias2).call(alias1,(depth0 != null ? lookupProperty(depth0,"value") : depth0),{"name":"splitUrl","hash":{},"data":data,"loc":{"start":{"line":130,"column":91},"end":{"line":130,"column":109}}})) + + "\n
(" + + alias4(((helper = (helper = lookupProperty(helpers,"identifierType") || (depth0 != null ? lookupProperty(depth0,"identifierType") : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"identifierType","hash":{},"data":data,"loc":{"start":{"line":131,"column":66},"end":{"line":131,"column":84}}}) : helper))) + + ")
\n
\n
\n"; +},"25":function(container,depth0,helpers,partials,data) { + return "
\n
\n
No alternate identifiers assigned
\n
\n
\n"; +},"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) { + var stack1, helper, alias1=container.lambda, alias2=container.escapeExpression, alias3=depth0 != null ? depth0 : (container.nullContext || {}), alias4=container.hooks.helperMissing, alias5="function", lookupProperty = container.lookupProperty || function(parent, propertyName) { + if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { + return parent[propertyName]; + } + return undefined + }; + + return "\n
\n
\n \n
\n
\n \n
\n
\n

" + + alias2(alias1(((stack1 = ((stack1 = (depth0 != null ? lookupProperty(depth0,"titles") : depth0)) != null ? lookupProperty(stack1,"0") : stack1)) != null ? lookupProperty(stack1,"value") : stack1), depth0)) + + "

\n
\n
\n \n " + + alias2(alias1(((stack1 = (depth0 != null ? lookupProperty(depth0,"resourceType") : depth0)) != null ? lookupProperty(stack1,"typeGeneral") : stack1), depth0)) + + "
\n
" + + alias2(alias1(((stack1 = (depth0 != null ? lookupProperty(depth0,"resourceType") : depth0)) != null ? lookupProperty(stack1,"value") : stack1), depth0)) + + "
\n
\n
\n
\n \n
\n
\n \n " + + ((stack1 = (lookupProperty(helpers,"creatorsList")||(depth0 && lookupProperty(depth0,"creatorsList"))||alias4).call(alias3,(depth0 != null ? lookupProperty(depth0,"creators") : depth0),{"name":"creatorsList","hash":{},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data,"loc":{"start":{"line":32,"column":28},"end":{"line":32,"column":71}}})) != null ? stack1 : "") + + "\n \n
\n
\n \n
\n
\n" + + ((stack1 = lookupProperty(helpers,"if").call(alias3,((stack1 = ((stack1 = (depth0 != null ? lookupProperty(depth0,"descriptions") : depth0)) != null ? lookupProperty(stack1,"0") : stack1)) != null ? lookupProperty(stack1,"description") : stack1),{"name":"if","hash":{},"fn":container.program(3, data, 0),"inverse":container.program(5, data, 0),"data":data,"loc":{"start":{"line":39,"column":24},"end":{"line":43,"column":31}}})) != null ? stack1 : "") + + "
\n
\n \n
\n
\n
\n \n \n \n" + + ((stack1 = lookupProperty(helpers,"if").call(alias3,((stack1 = ((stack1 = (depth0 != null ? lookupProperty(depth0,"content") : depth0)) != null ? lookupProperty(stack1,"0") : stack1)) != null ? lookupProperty(stack1,"relativePath") : stack1),{"name":"if","hash":{},"fn":container.program(7, data, 0),"inverse":container.program(10, data, 0),"data":data,"loc":{"start":{"line":53,"column":28},"end":{"line":67,"column":35}}})) != null ? stack1 : "") + + "
\n
\n
\n
\n
\n \n
\n
\n
\n

Metadata

\n Publisher:
\n " + + alias2(((helper = (helper = lookupProperty(helpers,"publisher") || (depth0 != null ? lookupProperty(depth0,"publisher") : depth0)) != null ? helper : alias4),(typeof helper === alias5 ? helper.call(alias3,{"name":"publisher","hash":{},"data":data,"loc":{"start":{"line":79,"column":41},"end":{"line":79,"column":54}}}) : helper))) + + "
\n Publication Year:
\n " + + alias2(((helper = (helper = lookupProperty(helpers,"publicationYear") || (depth0 != null ? lookupProperty(depth0,"publicationYear") : depth0)) != null ? helper : alias4),(typeof helper === alias5 ? helper.call(alias3,{"name":"publicationYear","hash":{},"data":data,"loc":{"start":{"line":81,"column":41},"end":{"line":81,"column":60}}}) : helper))) + + "
\n Created at:
\n " + + alias2((lookupProperty(helpers,"formatDate")||(depth0 && lookupProperty(depth0,"formatDate"))||alias4).call(alias3,(depth0 != null ? lookupProperty(depth0,"created") : depth0),{"name":"formatDate","hash":{},"data":data,"loc":{"start":{"line":83,"column":41},"end":{"line":83,"column":63}}})) + + "
\n Last Modified:
\n " + + alias2((lookupProperty(helpers,"formatDate")||(depth0 && lookupProperty(depth0,"formatDate"))||alias4).call(alias3,(depth0 != null ? lookupProperty(depth0,"lastUpdate") : depth0),{"name":"formatDate","hash":{},"data":data,"loc":{"start":{"line":85,"column":41},"end":{"line":85,"column":66}}})) + + "
\n License:
\n
\n" + + ((stack1 = lookupProperty(helpers,"if").call(alias3,((stack1 = ((stack1 = (depth0 != null ? lookupProperty(depth0,"rights") : depth0)) != null ? lookupProperty(stack1,"0") : stack1)) != null ? lookupProperty(stack1,"schemeId") : stack1),{"name":"if","hash":{},"fn":container.program(12, data, 0),"inverse":container.program(15, data, 0),"data":data,"loc":{"start":{"line":88,"column":20},"end":{"line":102,"column":27}}})) != null ? stack1 : "") + + "
\n
\n Related Identifiers:
\n
\n" + + ((stack1 = lookupProperty(helpers,"if").call(alias3,((stack1 = ((stack1 = (depth0 != null ? lookupProperty(depth0,"relatedIdentifiers") : depth0)) != null ? lookupProperty(stack1,"0") : stack1)) != null ? lookupProperty(stack1,"value") : stack1),{"name":"if","hash":{},"fn":container.program(17, data, 0),"inverse":container.program(20, data, 0),"data":data,"loc":{"start":{"line":107,"column":24},"end":{"line":122,"column":31}}})) != null ? stack1 : "") + + "
\n Alternate Identifiers:
\n
\n" + + ((stack1 = lookupProperty(helpers,"if").call(alias3,((stack1 = ((stack1 = (depth0 != null ? lookupProperty(depth0,"alternateIdentifiers") : depth0)) != null ? lookupProperty(stack1,"0") : stack1)) != null ? lookupProperty(stack1,"value") : stack1),{"name":"if","hash":{},"fn":container.program(22, data, 0),"inverse":container.program(25, data, 0),"data":data,"loc":{"start":{"line":126,"column":24},"end":{"line":141,"column":31}}})) != null ? stack1 : "") + + "
\n
\n
\n \n
\n
\n

Downloads

\n
\n JSON\n
\n
\n ZIP\n
\n
\n
\n
\n
\n
\n\n"; +},"useData":true}); +})(); \ No newline at end of file diff --git a/definitions/search/compile.sh b/definitions/search/compile.sh deleted file mode 100644 index 89d41b1..0000000 --- a/definitions/search/compile.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -for FILE in ./*.handlebars; -do -handlebars $FILE -f "${FILE}.js" -done diff --git a/elastic-search-base-repo.html b/elastic-search-base-repo.html index 4134382..9ba1392 100644 --- a/elastic-search-base-repo.html +++ b/elastic-search-base-repo.html @@ -21,6 +21,7 @@ + @@ -332,69 +333,16 @@

return ret; }); - if (!showServiceUrl) { - $('#service-url-input').empty(); - } - - $('#app-logo').attr("src", appDescription["app-logo"]); - let header = appDescription["app-title"] + - '
' + appDescription["app-subtitle"] + '
'; - - $('#app-title').html(header); - - function userLoggedIn(login) { - if (login) { - $("#login_icon").attr("class", "sign-out icon") - $("#login_button_text").text("Logout"); - addMessage(0, 'User ' + keycloak.idTokenParsed.preferred_username + ' logged in.'); - localStorage.setItem("userLoggedIn", true); - $("#logged_in_as").text("Logged in as " + keycloak.idTokenParsed.preferred_username); - config.token = keycloak.token; - } else { - $("#login_icon").attr("class", "sign-in icon") - $("#login_button_text").text("Login"); - localStorage.removeItem("userLoggedIn", true); + applyConfig(keycloak, showServiceUrl,appDescription, config, addMessage, (login, username) => { + if(login){ + $("#logged_in_as").text("Logged in as " + username); + $("#editor-create-button").removeAttr("disabled"); + }else{ $("#logged_in_as").text("Not logged in."); - config.token = null; + $("#editor-create-button").attr("disabled", "disabled"); } - } - - if (typeof keycloak != typeof undefined) { - keycloak.onAuthSuccess = function () { - userLoggedIn(true); - }; - keycloak.onAuthLogout = function () { - userLoggedIn(false); - }; - - keycloak.onTokenExpired = () => { - addMessage(0, 'Keycloak token expired. Trying to refresh.'); - keycloak.updateToken(30).success(() => { - addMessage(0, 'Successfully got a new token.'); - config.token = keycloak.token; - }).catch(() => { - addMessage(1, "Failed to refresh keycloak token."); - config.token = null; - userLoggedIn(false); - }); - }; - - - keycloak.init({ - responseMode: 'fragment', - }); - - $("#login_button").click(() => { - if ($("#login_button_text").text() === "Login") { - keycloak.login(); - } else { - keycloak.logout(); - } - }); - } else { - $("#logged_in_as").attr("style", "display:none"); - $("#login_button").attr("style", "display:none"); - } + reloadTable(); + }); //initialize dropdown fields $('.ui.dropdown').dropdown(); @@ -424,6 +372,12 @@

from = from + size; doSearch(true); }); + + if (localStorage.getItem("userLoggedIn")) { + localStorage.removeItem("userLoggedIn") + $("#login_button").click(); + } + addMessage(0, "Search successfully initialized."); diff --git a/repo-landing-page.html b/repo-landing-page.html new file mode 100644 index 0000000..f755fff --- /dev/null +++ b/repo-landing-page.html @@ -0,0 +1,232 @@ + + + + + + BaseRepo UI + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ +
+ {app-title} +
{app-subtitle}
+
+

+ +
+
+
+
+
+ + + + + diff --git a/settings/base-repo.settings.js b/settings/base-repo.settings.js index 430cb77..7e8cfdc 100644 --- a/settings/base-repo.settings.js +++ b/settings/base-repo.settings.js @@ -23,7 +23,7 @@ export const appDescription = { //Enable/disable the Elastic search functionality. The availability of the search depends on the configuration of //the configured base-repo instance. If Elastic search is not configured for the underlying base-repo, it should //also be disabled here. -export const searchEnabled = false; +export const searchEnabled = true; diff --git a/settings/general.settings.js b/settings/general.settings.js index 90fa6cb..b4d4fdb 100644 --- a/settings/general.settings.js +++ b/settings/general.settings.js @@ -1,15 +1,13 @@ //Keycloak configuration to use Keycloak as identity provider for single sign-on. -export const keycloak //= undefined; -= Keycloak({ +export const keycloak = undefined; +/*= Keycloak({ url: 'https://gateway.datamanager.kit.edu:8443/', realm: 'dem_testing', clientId: 'kitdm-services' -}); +});*/ //Show the input for the backend service URL. This property should only be enabled for debugging. export const showServiceUrl = false; //The max. number of elements obtained in a single search request. export const page_size = 5; - -export const test=false; From c27083bef4a40386f9703423f680da662d95d36a Mon Sep 17 00:00:00 2001 From: Thomas Jejkal Date: Sat, 23 Sep 2023 15:53:55 +0200 Subject: [PATCH 17/40] Added error page if no identifier is provided --- repo-landing-page.html | 103 ++++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 48 deletions(-) diff --git a/repo-landing-page.html b/repo-landing-page.html index f755fff..febf105 100644 --- a/repo-landing-page.html +++ b/repo-landing-page.html @@ -105,62 +105,69 @@

function mainMethod() { const urlParams = new URLSearchParams(window.location.search); const pid = urlParams.get('pid'); - if(!pid){ - //no pid...empty result - return; - } - let ajaxURL = ajaxBaseUrl + "dataresources/"; - config.ajaxBaseUrl = ajaxBaseUrl; + let res = document.createElement("div"); + res.setAttribute("style", "background: #FAFAFA;padding-left:5px;"); - /* if (localStorage.getItem("userLoggedIn")) { + if(!pid){ + //no pid...empty result + res.innerHTML = '
\n' + + '
\n' + + ' Unable to load resource without identifier.\n' + + '
\n' + + '

You must provide an identifier as query parameter (e.g., ?pid=1234-5678) to show a landing page.

\n' + + '
'; + }else { + let ajaxURL = ajaxBaseUrl + "dataresources/"; + config.ajaxBaseUrl = ajaxBaseUrl; + + /* if (localStorage.getItem("userLoggedIn")) { localStorage.removeItem("userLoggedIn") $("#login_button").click(); }*/ - let data = {"read": ["anonymousUser"], "creators":[], "created":"2023-12-12T12:12:12"}; - let headers = { - Accept: "application/json" - }; - let res = document.createElement("div"); - res.setAttribute("style", "background: #FAFAFA;padding-left:5px;"); + let data = {"read": ["anonymousUser"], "creators": [], "created": "2023-12-12T12:12:12"}; + let headers = { + Accept: "application/json" + }; - $.ajax({ - type: "GET", - url: ajaxURL + pid, - headers: headers, - cache: false, - success: function (result) { - let headers = { - Accept: "application/vnd.datamanager.content-information+json" - }; - $.ajax({ - type: "GET", - url: ajaxURL + pid + "/data/", - headers: headers, - cache: false, - success: function (content_result) { - result.content = content_result; - let template = Handlebars.templates.landingpage; - res.innerHTML = template(result); - - $("#download_json").click(function (e) { - downloadJson(result.id); - }); - $("#download_zip").click(function (e) { - downloadZip(result.id); - }); - }, - error: function (result) { - res.innerHTML = renderError(pid, result); - } - }) - }, - error: function (result) { - res.innerHTML = renderError(pid, result); - } - }); + $.ajax({ + type: "GET", + url: ajaxURL + pid, + headers: headers, + cache: false, + success: function (result) { + let headers = { + Accept: "application/vnd.datamanager.content-information+json" + }; + $.ajax({ + type: "GET", + url: ajaxURL + pid + "/data/", + headers: headers, + cache: false, + success: function (content_result) { + result.content = content_result; + let template = Handlebars.templates.landingpage; + res.innerHTML = template(result); + + $("#download_json").click(function (e) { + downloadJson(result.id); + }); + $("#download_zip").click(function (e) { + downloadZip(result.id); + }); + }, + error: function (result) { + res.innerHTML = renderError(pid, result); + } + }) + }, + error: function (result) { + res.innerHTML = renderError(pid, result); + } + }); + } $('#result').append(res); } From 5fde3da2249b5d869d13abe9960c9c3b2552d0b2 Mon Sep 17 00:00:00 2001 From: Thomas Jejkal Date: Sun, 24 Sep 2023 22:37:10 +0200 Subject: [PATCH 18/40] Started adding MetaStore landing page --- compile.sh | 5 + .../metastore/landingpage_schema.handlebars | 86 +++++++ .../landingpage_schema.handlebars.js | 61 +++++ metastore-landing-page.html | 225 ++++++++++++++++++ 4 files changed, 377 insertions(+) create mode 100644 definitions/metastore/landingpage_schema.handlebars create mode 100644 definitions/metastore/landingpage_schema.handlebars.js create mode 100644 metastore-landing-page.html diff --git a/compile.sh b/compile.sh index aa2e367..57af21c 100644 --- a/compile.sh +++ b/compile.sh @@ -9,3 +9,8 @@ for FILE in ./definitions/base-repo/*.handlebars; do handlebars $FILE -f "${FILE}.js" done + +for FILE in ./definitions/metastore/*.handlebars; +do +handlebars $FILE -f "${FILE}.js" +done diff --git a/definitions/metastore/landingpage_schema.handlebars b/definitions/metastore/landingpage_schema.handlebars new file mode 100644 index 0000000..7051be7 --- /dev/null +++ b/definitions/metastore/landingpage_schema.handlebars @@ -0,0 +1,86 @@ + +
+
+ +
+
+ +
+
+

{{schema.label}}

+
+
+ + {{schema.schemaId}}
+
{{schema.schemaVersion}}
+
+
+
+ +
+
+ {{#if schema.definition}} + {{schema.definition}} + {{else}} + No definition available + {{/if}} +
+
+ +
+
+ {{#if schema.comment}} + {{schema.comment}} + {{else}} + No comment available + {{/if}} +
+
+ + +
+
+ +
+
+
+

Metadata

+ Type:
+ {{schema.type}}
+ MimeType:
+ {{schema.mimeType}}
+ Created at:
+ {{formatDate createdAt}}
+ Last Modified:
+ {{formatDate lastUpdate}}
+
+
+ +
+
+

Downloads

+
+ JSON +
+
+ ZIP +
+
+
+
+
+
+ diff --git a/definitions/metastore/landingpage_schema.handlebars.js b/definitions/metastore/landingpage_schema.handlebars.js new file mode 100644 index 0000000..771158a --- /dev/null +++ b/definitions/metastore/landingpage_schema.handlebars.js @@ -0,0 +1,61 @@ +(function() { + var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {}; +templates['landingpage_schema'] = template({"1":function(container,depth0,helpers,partials,data) { + var stack1, lookupProperty = container.lookupProperty || function(parent, propertyName) { + if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { + return parent[propertyName]; + } + return undefined + }; + + return " " + + container.escapeExpression(container.lambda(((stack1 = (depth0 != null ? lookupProperty(depth0,"schema") : depth0)) != null ? lookupProperty(stack1,"definition") : stack1), depth0)) + + "\n"; +},"3":function(container,depth0,helpers,partials,data) { + return " No definition available\n"; +},"5":function(container,depth0,helpers,partials,data) { + var stack1, lookupProperty = container.lookupProperty || function(parent, propertyName) { + if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { + return parent[propertyName]; + } + return undefined + }; + + return " " + + container.escapeExpression(container.lambda(((stack1 = (depth0 != null ? lookupProperty(depth0,"schema") : depth0)) != null ? lookupProperty(stack1,"comment") : stack1), depth0)) + + "\n"; +},"7":function(container,depth0,helpers,partials,data) { + return " No comment available\n"; +},"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) { + var stack1, alias1=container.lambda, alias2=container.escapeExpression, alias3=depth0 != null ? depth0 : (container.nullContext || {}), alias4=container.hooks.helperMissing, lookupProperty = container.lookupProperty || function(parent, propertyName) { + if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { + return parent[propertyName]; + } + return undefined + }; + + return "\n
\n
\n \n
\n
\n \n
\n
\n

" + + alias2(alias1(((stack1 = (depth0 != null ? lookupProperty(depth0,"schema") : depth0)) != null ? lookupProperty(stack1,"label") : stack1), depth0)) + + "

\n
\n
\n \n " + + alias2(alias1(((stack1 = (depth0 != null ? lookupProperty(depth0,"schema") : depth0)) != null ? lookupProperty(stack1,"schemaId") : stack1), depth0)) + + "
\n
" + + alias2(alias1(((stack1 = (depth0 != null ? lookupProperty(depth0,"schema") : depth0)) != null ? lookupProperty(stack1,"schemaVersion") : stack1), depth0)) + + "
\n
\n
\n
\n \n
\n
\n" + + ((stack1 = lookupProperty(helpers,"if").call(alias3,((stack1 = (depth0 != null ? lookupProperty(depth0,"schema") : depth0)) != null ? lookupProperty(stack1,"definition") : stack1),{"name":"if","hash":{},"fn":container.program(1, data, 0),"inverse":container.program(3, data, 0),"data":data,"loc":{"start":{"line":31,"column":24},"end":{"line":35,"column":31}}})) != null ? stack1 : "") + + "
\n
\n \n
\n
\n" + + ((stack1 = lookupProperty(helpers,"if").call(alias3,((stack1 = (depth0 != null ? lookupProperty(depth0,"schema") : depth0)) != null ? lookupProperty(stack1,"comment") : stack1),{"name":"if","hash":{},"fn":container.program(5, data, 0),"inverse":container.program(7, data, 0),"data":data,"loc":{"start":{"line":41,"column":24},"end":{"line":45,"column":31}}})) != null ? stack1 : "") + + "
\n
\n \n \n
\n
\n \n
\n
\n
\n

Metadata

\n Type:
\n " + + alias2(alias1(((stack1 = (depth0 != null ? lookupProperty(depth0,"schema") : depth0)) != null ? lookupProperty(stack1,"type") : stack1), depth0)) + + "
\n MimeType:
\n " + + alias2(alias1(((stack1 = (depth0 != null ? lookupProperty(depth0,"schema") : depth0)) != null ? lookupProperty(stack1,"mimeType") : stack1), depth0)) + + "
\n Created at:
\n " + + alias2((lookupProperty(helpers,"formatDate")||(depth0 && lookupProperty(depth0,"formatDate"))||alias4).call(alias3,(depth0 != null ? lookupProperty(depth0,"createdAt") : depth0),{"name":"formatDate","hash":{},"data":data,"loc":{"start":{"line":65,"column":41},"end":{"line":65,"column":65}}})) + + "
\n Last Modified:
\n " + + alias2((lookupProperty(helpers,"formatDate")||(depth0 && lookupProperty(depth0,"formatDate"))||alias4).call(alias3,(depth0 != null ? lookupProperty(depth0,"lastUpdate") : depth0),{"name":"formatDate","hash":{},"data":data,"loc":{"start":{"line":67,"column":41},"end":{"line":67,"column":66}}})) + + "
\n
\n
\n \n
\n
\n

Downloads

\n
\n JSON\n
\n
\n ZIP\n
\n
\n
\n
\n
\n
\n\n"; +},"useData":true}); +})(); \ No newline at end of file diff --git a/metastore-landing-page.html b/metastore-landing-page.html new file mode 100644 index 0000000..5d57dd3 --- /dev/null +++ b/metastore-landing-page.html @@ -0,0 +1,225 @@ + + + + + + MetaStore2 UI + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ +
+ {app-title} +
{app-subtitle}
+
+

+ +
+
+
+
+
+ + + + + From ed524d369dce9c297deacc740afb7dc4017a50d8 Mon Sep 17 00:00:00 2001 From: Thomas Jejkal Date: Fri, 29 Sep 2023 11:12:09 +0200 Subject: [PATCH 19/40] Renamed FDO Maker to FDO Builder, enabled Typed PID Maker backend access --- .../{fdo-maker => fdo-builder}/hkip.js | 0 .../{fdo-maker => fdo-builder}/known-types.js | 0 .../recordUIDefinitionCreate.js | 0 fdo-creator-ui.html => fdo-builder-ui.html | 22 ++-- metastore-landing-page.html | 102 +++++++++++++----- ...er.settings.js => fdo-builder.settings.js} | 2 +- 6 files changed, 90 insertions(+), 36 deletions(-) rename definitions/{fdo-maker => fdo-builder}/hkip.js (100%) rename definitions/{fdo-maker => fdo-builder}/known-types.js (100%) rename definitions/{fdo-maker => fdo-builder}/recordUIDefinitionCreate.js (100%) rename fdo-creator-ui.html => fdo-builder-ui.html (98%) rename settings/{fdo-maker.settings.js => fdo-builder.settings.js} (92%) diff --git a/definitions/fdo-maker/hkip.js b/definitions/fdo-builder/hkip.js similarity index 100% rename from definitions/fdo-maker/hkip.js rename to definitions/fdo-builder/hkip.js diff --git a/definitions/fdo-maker/known-types.js b/definitions/fdo-builder/known-types.js similarity index 100% rename from definitions/fdo-maker/known-types.js rename to definitions/fdo-builder/known-types.js diff --git a/definitions/fdo-maker/recordUIDefinitionCreate.js b/definitions/fdo-builder/recordUIDefinitionCreate.js similarity index 100% rename from definitions/fdo-maker/recordUIDefinitionCreate.js rename to definitions/fdo-builder/recordUIDefinitionCreate.js diff --git a/fdo-creator-ui.html b/fdo-builder-ui.html similarity index 98% rename from fdo-creator-ui.html rename to fdo-builder-ui.html index af41562..fc4e244 100644 --- a/fdo-creator-ui.html +++ b/fdo-builder-ui.html @@ -25,10 +25,10 @@ - + - + + + + + + + +
+ +
+ +
+ + +
+ + + + + + From 8d3b7dc7c1020092e8c70858a0d85118a283043c Mon Sep 17 00:00:00 2001 From: Volker Hartmann Date: Wed, 22 Nov 2023 07:52:08 +0100 Subject: [PATCH 24/40] Test new frontend-collection for MetaStore --- index.html | 2 +- settings/elastic-search-metastore.settings.js | 2 +- settings/metastore.settings.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index 2f4b3a5..91eedca 100644 --- a/index.html +++ b/index.html @@ -2,7 +2,7 @@ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> - + diff --git a/settings/elastic-search-metastore.settings.js b/settings/elastic-search-metastore.settings.js index acc179b..43b0ba5 100644 --- a/settings/elastic-search-metastore.settings.js +++ b/settings/elastic-search-metastore.settings.js @@ -1,5 +1,5 @@ //The backend service URL for the MetaStore instance used by the frontend. -export const ajaxBaseUrl = "http://localhost:8041/api/v1/"; +export const ajaxBaseUrl = "http://metastore.docker:8040/metastore/api/v1/"; //export const ajaxBaseUrl = "https://demo.datamanager.kit.edu:8443/metastore/api/v1/"; //The app description used to customize the frontend, e.g., for a specific project with a custom title and subtitle. diff --git a/settings/metastore.settings.js b/settings/metastore.settings.js index 000b6b6..9269c16 100644 --- a/settings/metastore.settings.js +++ b/settings/metastore.settings.js @@ -1,5 +1,5 @@ //The backend service URL for the MetaStore instance used by the frontend. -export const ajaxBaseUrl = "http://localhost:8041/api/v1/"; +export const ajaxBaseUrl = "http://metastore.docker:8040/metastore/api/v1/"; //export const ajaxBaseUrl = "https://demo.datamanager.kit.edu:8443/metastore/api/v1/"; //The app description used to customize the frontend, e.g., for a specific project with a custom title and subtitle. From b55d5dce8231c0dc7b6ca472edba89fd963fce42 Mon Sep 17 00:00:00 2001 From: Volker Hartmann Date: Wed, 22 Nov 2023 08:48:30 +0100 Subject: [PATCH 25/40] Add dockerfile. --- Dockerfile | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..0c8b821 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,3 @@ +FROM httpd:2.4 +COPY . /usr/local/apache2/htdocs/ + From 2a6246adcd7e602376a364209e72595e4971cd37 Mon Sep 17 00:00:00 2001 From: Volker Hartmann Date: Sat, 11 Feb 2023 17:30:51 +0100 Subject: [PATCH 26/40] Dockerize repo. --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 0c8b821..31c8363 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,3 @@ FROM httpd:2.4 -COPY . /usr/local/apache2/htdocs/ +COPY ./ /usr/local/apache2/htdocs/ From f540cd505b808da14e7cf8c1958b83cfe67d1052 Mon Sep 17 00:00:00 2001 From: Volker Hartmann Date: Sat, 11 Feb 2023 17:51:46 +0100 Subject: [PATCH 27/40] Fix typo --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 31c8363..0c8b821 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,3 @@ FROM httpd:2.4 -COPY ./ /usr/local/apache2/htdocs/ +COPY . /usr/local/apache2/htdocs/ From 7d5bcd464acf9c83f51f405bc34044b7cc19d924 Mon Sep 17 00:00:00 2001 From: Volker Hartmann Date: Wed, 14 Jun 2023 08:46:50 +0200 Subject: [PATCH 28/40] Remove more trailing '/' from URLs for MetaStore --- js/metastore-utils.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/js/metastore-utils.js b/js/metastore-utils.js index 5d8dd50..cf011c0 100644 --- a/js/metastore-utils.js +++ b/js/metastore-utils.js @@ -56,10 +56,9 @@ export function readSchema(schemaUrl) { let message = "Failed to read schema from URL " + schemaUrl + ". (HTTP " + result.status + ")"; reject(message); } - }); + }) }); -} - +}; export function readSchemaIds() { let headers = { From 2ab130e1cabc2e5a565726ef1208f9767afdcf42 Mon Sep 17 00:00:00 2001 From: Volker Hartmann Date: Wed, 22 Nov 2023 14:24:32 +0100 Subject: [PATCH 29/40] Enable search --- settings/metastore.settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings/metastore.settings.js b/settings/metastore.settings.js index 9269c16..b3fffcb 100644 --- a/settings/metastore.settings.js +++ b/settings/metastore.settings.js @@ -12,7 +12,7 @@ export const appDescription = { //Enable/disable the Elastic search functionality. The availability of the search depends on the configuration of //the configured MetaStore instance. If Elastic search is not configured for the underlying MetaStore, it should //also be disabled here. -export const searchEnabled = false; +export const searchEnabled = true; From 05530011ef45f3c3dbb5efca79a90755e8c1c918 Mon Sep 17 00:00:00 2001 From: Thomas Jejkal Date: Sun, 10 Dec 2023 22:25:30 +0100 Subject: [PATCH 30/40] Continued on adaptation of new json editor for base-repo UI --- definitions/base-repo/models/acl_entry.json | 16 +- definitions/base-repo/models/agent.json | 23 +- .../models/alternate_identifier.json | 60 + definitions/base-repo/models/contributor.json | 42 + definitions/base-repo/models/date.json | 30 + definitions/base-repo/models/description.json | 12 +- .../base-repo/models/funding_reference.json | 81 +- definitions/base-repo/models/identifier.json | 52 + .../base-repo/models/related_identifier.json | 78 + definitions/base-repo/models/resourceModel.js | 369 ++-- .../base-repo/models/resource_type.json | 20 +- definitions/base-repo/models/scheme.json | 20 +- definitions/base-repo/models/subject.json | 45 + definitions/base-repo/models/title.json | 26 +- definitions/base-repo/sample_schema.js | 1523 +++++++++++++++++ repo-management_new.html | 6 +- search.html | 131 ++ 17 files changed, 2238 insertions(+), 296 deletions(-) create mode 100644 definitions/base-repo/models/alternate_identifier.json create mode 100644 definitions/base-repo/models/contributor.json create mode 100644 definitions/base-repo/models/date.json create mode 100644 definitions/base-repo/models/identifier.json create mode 100644 definitions/base-repo/models/related_identifier.json create mode 100644 definitions/base-repo/models/subject.json create mode 100644 definitions/base-repo/sample_schema.js create mode 100644 search.html diff --git a/definitions/base-repo/models/acl_entry.json b/definitions/base-repo/models/acl_entry.json index 53f7aa6..4dcfe8b 100644 --- a/definitions/base-repo/models/acl_entry.json +++ b/definitions/base-repo/models/acl_entry.json @@ -1,15 +1,23 @@ { "type": "object", "headerTemplate": "{{self.sid}}", + "format": "grid-strict", "properties": { "id": { "type": "integer", - "readOnly":true + "readOnly": true, + "options": { + "hidden": true + } }, "permission": { "type": "string", "propertyOrder":2, - "enum": ["NONE", "READ", "WRITE", "ADMINISTRATE"] + "enum": ["NONE", "READ", "WRITE", "ADMINISTRATE"], + "options": { + "grid_columns": 6, + "infoText": "The access control permission." + } }, "sid": { "type": "string", @@ -20,7 +28,9 @@ "search": "search_keycloak", "getResultValue": "getResultValue_keycloak", "renderResult": "renderResult_keycloak" - } + }, + "grid_columns": 6, + "infoText": "The subject identifier, e.g., a user id or email." } } }, diff --git a/definitions/base-repo/models/agent.json b/definitions/base-repo/models/agent.json index 5840627..23cee71 100644 --- a/definitions/base-repo/models/agent.json +++ b/definitions/base-repo/models/agent.json @@ -10,21 +10,26 @@ "properties": { "id": { "type": "integer", - "title": "Id", - "propertyOrder": 1 + "options": { + "hidden": true + } }, "givenName": { "type": "string", - "propertyOrder": 2, + "title": "First Name", + "propertyOrder": 3, "options": { - "grid_columns": 6 + "grid_columns": 6, + "infoText": "The given name of the person." } }, "familyName": { "type": "string", - "propertyOrder": 3, + "title": "Family Name", + "propertyOrder": 2, "options": { - "grid_columns": 6 + "grid_columns": 6, + "infoText": "The family name of the person." } }, "affiliations": { @@ -32,10 +37,12 @@ "title": "Affiliations", "propertyOrder": 4, "options": { - "grid_columns": 12 + "collapsed": true, + "grid_columns": 12, + "infoText": "One or more affiliations of the person." }, "items": { - "headerTemplate": "Affiliation #{{ i1 }}", + "headerTemplate": "Affiliation #{{ i1 }} {{#if self }} ({{ self }}) {{else}} (None) {{/if}}", "type": "string" } } diff --git a/definitions/base-repo/models/alternate_identifier.json b/definitions/base-repo/models/alternate_identifier.json new file mode 100644 index 0000000..3cf936f --- /dev/null +++ b/definitions/base-repo/models/alternate_identifier.json @@ -0,0 +1,60 @@ +{ + "type": "object", + "headerTemplate": "{{self.identifierType}}", + "format": "grid-strict", + "properties": { + "id": { + "type": "integer", + "readOnly": true, + "options": { + "hidden": true + } + }, + "identifierType": { + "propertyOrder": 2, + "type": "string", + "title": "Identifier Type", + "enum": [ + "ARK", + "AR_XIV", + "BIBCODE", + "DOI", + "EAN_13", + "EISSN", + "HANDLE", + "IGSN", + "ISBN", + "ISSN", + "ISTC", + "LISSN", + "LSID", + "PMID", + "PURL", + "UPC", + "URL", + "URN", + "W_3_ID", + "INTERNAL", + "OTHER" + ], + "default": "DOI", + "options": { + "grid_columns": 4, + "infoText": "The type of the alternate identifier." + } + }, + "value": { + "type": "string", + "propertyOrder": 3, + "title": "Identifier", + "options": { + "grid_columns": 8, + "infoText": "The alternate identifier value." + } + } + }, + "required": [ + "identifierType", + "value" + ] +} diff --git a/definitions/base-repo/models/contributor.json b/definitions/base-repo/models/contributor.json new file mode 100644 index 0000000..883ec37 --- /dev/null +++ b/definitions/base-repo/models/contributor.json @@ -0,0 +1,42 @@ +{ + "type": "object", + "format": "grid-strict", + "properties": { + "id": { + "type": "integer", + "propertyOrder": 1, + "readOnly": true, + "options": { + "hidden": true + } + }, + "contributionType": { + "type": "string", + "title":"Contribution Type", + "propertyOrder": 2, + "enum": ["CONTACT_PERSON", "DATA_COLLECTOR", "DATA_CURATOR", "DATA_MANAGER", "DISTRIBUTOR", "EDITOR", "HOSTING_INSTITUTION", "OTHER", "PRODUCER", "PROJECT_LEADER", "PROJECT_MANAGER", "PROJECT_MEMBER", "REGISTRATION_AGENCY", "REGISTRATION_AUTHORITY", "RELATED_PERSON", "RESEARCH_GROUP", "RIGHTS_HOLDER", "RESEARCHER", "SPONSOR", "SUPERVISOR", "WORK_PACKAGE_LEADER"], + "options": { + "grid_columns": 12, + "disable_collapse": false, + "disable_edit_json": true, + "disable_properties": true, + "compact": false, + "infoText": "The type of the contribution." + } + }, + "user": { + "title": "Contributor", + "propertyOrder": 3, + "$ref": "agent.json", + "required": ["givenName", "familyName"], + "options": { + "grid_columns": 12, + "disable_collapse": true, + "disable_edit_json": true, + "disable_properties": true, + "compact": true + } + } + }, + "required": ["contributionType", "user"] +} diff --git a/definitions/base-repo/models/date.json b/definitions/base-repo/models/date.json new file mode 100644 index 0000000..4a435eb --- /dev/null +++ b/definitions/base-repo/models/date.json @@ -0,0 +1,30 @@ +{ + "type": "object", + "format": "grid-strict", + "properties": { + "id": { + "type": "integer", + "readOnly": true, + "options": { + "hidden": true + } + }, + "type": { + "type": "string", + "enum": ["ACCEPTED", "AVAILABLE", "COLLECTED", "COPYRIGHTED", "CREATED", "ISSUED", "SUBMITTED", "UPDATED", "VALID", "REVOKED"], + "options": { + "grid_columns": 6, + "infoText": "The date type." + + } + }, + "value": { + "type": "string", + "pattern": "\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\d([+-][0-2]\\d:[0-5]\\d|Z)", + "options": { + "grid_columns": 6, + "infoText": "The date value." + } + } + } +} diff --git a/definitions/base-repo/models/description.json b/definitions/base-repo/models/description.json index 04157ea..42795b6 100644 --- a/definitions/base-repo/models/description.json +++ b/definitions/base-repo/models/description.json @@ -6,32 +6,36 @@ "type": "integer", "propertyOrder": 1, "options":{ - "grid_columns":2, "hidden": true } }, "description": { "type": "string", + "title": "Description", "propertyOrder": 4, "maxLength": 10240, "options":{ "grid_columns":12, - "infoText": "Your full name" + "infoText": "The description text." } }, "lang": { "$ref": "language.json", + "title": "Language", "propertyOrder": 3, "options":{ - "grid_columns":5 + "grid_columns": 6, + "infoText": "The description language." } }, "type": { "type": "string", + "title": "Description Type", "propertyOrder": 2, "enum": ["ABSTRACT", "METHODS", "SERIES_INFORMATION", "TABLE_OF_CONTENTS", "TECHNICAL_INFO", "OTHER"], "options":{ - "grid_columns":5 + "grid_columns": 6, + "infoText": "The type of the description." } } }, diff --git a/definitions/base-repo/models/funding_reference.json b/definitions/base-repo/models/funding_reference.json index d1fd872..7657ab8 100644 --- a/definitions/base-repo/models/funding_reference.json +++ b/definitions/base-repo/models/funding_reference.json @@ -1,38 +1,89 @@ { "type": "object", + "format": "grid-strict", "properties": { - "awardNumber": { - "$ref": "scheme.json" - }, - "awardTitle": { - "type": "string" + "id": { + "type": "integer", + "options": { + "hidden": true + } }, - "awardUri": { - "type": "string" + "funderName": { + "title": "Funder Name", + "propertyOrder": 1, + "type": "string", + "options": { + "grid_columns": 12, + "infoText": "The funder name." + } }, "funderIdentifier": { "type": "object", + "format": "grid-strict", + "propertyOrder": 2, + "title": "Funder Identifier", "properties": { "id": { - "type": "integer" + "type": "integer", + "options": { + "hidden": true + } }, "identifierType": { - "$ref": "#/$defs/IDENTIFIER_TYPE" + "type": "string", + "title": "Identifier Type", + "enum": ["ARK", "AR_XIV", "BIBCODE", "DOI", "EAN_13", "EISSN", "HANDLE", "IGSN", "ISBN", "ISSN", "ISTC", "LISSN", "LSID", "PMID", "PURL", "UPC", "URL", "URN", "W_3_ID", "INTERNAL", "OTHER"], + "default": "DOI", + "options": { + "grid_columns": 6, + "infoText": "The funder identifier type." + } }, "type": { "type": "string", - "enum": ["ISNI", "GRID", "CROSSREF_FUNDER_ID", "OTHER"] + "title": "Identifier Issuer", + "enum": ["ISNI", "GRID", "CROSSREF_FUNDER_ID", "OTHER"], + "options": { + "grid_columns": 6, + "infoText": "The funder identifier issuer." + } }, "value": { - "type": "string" + "type": "string", + "title": "Value", + "options": { + "grid_columns": 12, + "infoText": "The funder identifier value." + } } + }, + "options": { + "collapsed": true } }, - "funderName": { - "type": "string" + "awardTitle": { + "type": "string", + "propertyOrder": 3, + "title": "Award Title", + "options": { + "grid_columns": 6 + } }, - "id": { - "type": "integer" + "awardUri": { + "type": "string", + "propertyOrder": 4, + "title": "Award URI", + "options": { + "grid_columns": 6 + } + }, + "awardNumber": { + "propertyOrder": 5, + "title": "Award Number", + "$ref": "scheme.json", + "options": { + "collapsed": true + } } } } diff --git a/definitions/base-repo/models/identifier.json b/definitions/base-repo/models/identifier.json new file mode 100644 index 0000000..901cd0c --- /dev/null +++ b/definitions/base-repo/models/identifier.json @@ -0,0 +1,52 @@ +{ + "type": "object", + "format": "grid-strict", + "properties": { + "id": { + "type": "integer", + "options": { + "hidden": true + } + }, + "identifierType": { + "type": "string", + "title": "Identifier Type", + "enum": [ + "ARK", + "AR_XIV", + "BIBCODE", + "DOI", + "EAN_13", + "EISSN", + "HANDLE", + "IGSN", + "ISBN", + "ISSN", + "ISTC", + "LISSN", + "LSID", + "PMID", + "PURL", + "UPC", + "URL", + "URN", + "W_3_ID", + "INTERNAL", + "OTHER" + ], + "default": "DOI", + "options": { + "grid_columns": 4, + "infoText": "The type of the identifier." + } + }, + "value": { + "type": "string", + "title": "Value", + "options": { + "grid_columns": 8, + "infoText": "The identifier value." + } + } + } +} diff --git a/definitions/base-repo/models/related_identifier.json b/definitions/base-repo/models/related_identifier.json new file mode 100644 index 0000000..ef709e4 --- /dev/null +++ b/definitions/base-repo/models/related_identifier.json @@ -0,0 +1,78 @@ +{ + "type": "object", + "format": "grid-strict", + "headerTemplate": "{{self.relationType}}", + "properties": { + "id": { + "type": "integer", + "options": { + "hidden": true + } + }, + "relationType": { + "type": "string", + "propertyOrder": 1, + "title": "Relation Type", + "enum": ["IS_CITED_BY", "CITES", "IS_SUPPLEMENT_TO", "IS_SUPPLEMENTED_BY", "IS_CONTINUED_BY", "CONTINUES", "IS_NEW_VERSION_OF", "IS_PREVIOUS_VERSION_OF", "IS_PART_OF", "HAS_PART", "IS_REFERENCED_BY", "REFERENCES", "IS_DOCUMENTED_BY", "DOCUMENTS", "IS_COMPILED_BY", "COMPILES", "IS_VARIANT_FORM_OF", "IS_ORIGINAL_FORM_OF", "IS_IDENTICAL_TO", "HAS_METADATA", "IS_METADATA_FOR", "REVIEWS", "IS_REVIEWED_BY", "IS_DERIVED_FROM", "IS_SOURCE_OF"], + "options": { + "grid_columns": 12, + "infoText": "The type of the relation." + } + }, + "identifierType": { + "type": "string", + "propertyOrder": 2, + "title": "Identifier Type", + "enum": [ + "ARK", + "AR_XIV", + "BIBCODE", + "DOI", + "EAN_13", + "EISSN", + "HANDLE", + "IGSN", + "ISBN", + "ISSN", + "ISTC", + "LISSN", + "LSID", + "PMID", + "PURL", + "UPC", + "URL", + "URN", + "W_3_ID", + "INTERNAL", + "OTHER" + ], + "default": "DOI", + "options": { + "grid_columns": 4, + "infoText": "The type of the related identifier." + } + }, + "value": { + "type": "string", + "propertyOrder": 3, + "title": "Value", + "options": { + "grid_columns": 8, + "infoText": "The related identifier value." + } + }, + "relatedMetadataScheme": { + "type": "string", + "options": { + "grid_columns": 4, + "hidden": "true" + } + }, + "scheme": { + "$ref": "scheme.json", + "options": { + "hidden": true + } + } + } +} diff --git a/definitions/base-repo/models/resourceModel.js b/definitions/base-repo/models/resourceModel.js index b8fb61e..92d33be 100644 --- a/definitions/base-repo/models/resourceModel.js +++ b/definitions/base-repo/models/resourceModel.js @@ -1,35 +1,91 @@ let model = { "$schema": "https://json-schema.org/draft/2019-09/schema", - "$defs": { - "IDENTIFIER_TYPE": { - "type": "string", - "enum": ["ARK", "AR_XIV", "BIBCODE", "DOI", "EAN_13", "EISSN", "HANDLE", "IGSN", "ISBN", "ISSN", "ISTC", "LISSN", "LSID", "PMID", "PURL", "UPC", "URL", "URN", "W_3_ID", "INTERNAL", "OTHER"], - "default": "DOI" - } - }, "type": "object", + "headerTemplate": "Data Resource {{#if self.id}} #{{ self.id }} {{else}} (New) {{/if}}", "required": [ "titles", "publisher", "publicationYear", "resourceType", "alternateIdentifiers" ], "format": "categories", "properties": { + "id": { + "type": "string", + "propertyOrder": 1, + "readOnly": true, + "title": "Internal Identifier", + "options":{ + "infoText": "The internal identifier of the resource." + } + }, + "publisher": { + "type": "string", + "propertyOrder": 2, + "title": "Publisher", + "options":{ + "infoText": "The publisher of the resource." + } + }, + "publicationYear": { + "type": "string", + "propertyOrder": 3, + "title": "Publication Year", + "options": { + "inputAttributes": { + "placeholder": "YYYY" + }, + "cleave": { + "date": true, + "datePattern": ['Y'] + }, + "infoText": "The year when the resource has been published." + } + //"pattern":"^(19|20)\\d{2}$" + }, + "embargoDate": { + "type": "string", + "title": "Under Embargo Until", + "propertyOrder": 4, + "pattern": "\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\d([+-][0-2]\\d:[0-5]\\d|Z)", + "options":{ + "infoText": "The date until which the resource or its contents are under embargo." + } + }, + "language": { + "title": "Language", + "propertyOrder": 5, + "$ref": "definitions/base-repo/models/language.json", + "options":{ + "infoText": "The language of the resource." + } + }, + "lastUpdate": { + "type": "string", + "propertyOrder": 6, + "title": "Last Update", + "options":{ + "infoText": "The date of the last update to the resource." + } + }, + "state": { + "type": "string", + "propertyOrder": 7, + "title": "Resource State", + "enum": ["VOLATILE", "FIXED", "REVOKED", "GONE"], + "options":{ + "infoText": "The state of the resource." + } + }, + "titles": { "type": "array", "title": "Titles", - "description": "A list of titles.", + "description": "One or more titles of the resource.", "minItems": 1, "propertyOrder": 1, - "options": { - "disable_collapse": false, - "disable_edit_json": true, - "disable_properties": false, - "compact": false - }, "items": { "headerTemplate": " {{#if self.titleType}}\n" + " {{self.titleType}}\n" + " {{else}}\n" + - " None\n" + + " Other\n" + " {{/if}}", "$ref": "definitions/base-repo/models/title.json", "watch": { @@ -40,6 +96,7 @@ let model = { "descriptions": { "type": "array", "title": "Descriptions", + "description": "One or more descriptions of the resource.", "format": "grid-strict", "propertyOrder": 2, "items": { @@ -55,29 +112,13 @@ let model = { } }, "resourceType": { + "description": "Type information for the resource.", "$ref": "definitions/base-repo/models/resource_type.json" }, - "publisher": { - "type": "string", - "title": "Publisher", - }, - "publicationYear": { - "type": "string", - "title": "Publication Year", - "options": { - "inputAttributes": { - "placeholder": "YYYY" - }, - "cleave": { - "date": true, - "datePattern": ['Y'] - } - } - //"pattern":"^(19|20)\\d{2}$" - }, "acls": { "type": "array", "title": "Access Control Information", + "description": "Access control information for the resource.", "required": true, "items": { "headerTemplate": " {{#if self.sid}}\n" + @@ -94,177 +135,76 @@ let model = { "alternateIdentifiers": { "type": "array", "title": "Alternate Identifiers", + "description": "One or more alternate identifiers of the resource.", "items": { - "type": "object", - "headerTemplate": "{{ self.identifierType }}", - "format":"grid-strict", - "properties": { - "id": { - "type": "integer", - "title":"Id", - "propertyOrder": 1, - "readOnly":true, - "options": { - "grid_columns": 2, - } - }, - "identifierType": { - "propertyOrder": 2, - "$ref": "#/$defs/IDENTIFIER_TYPE", - "default": "DOI", - "options": { - "grid_columns": 4, - } - }, - "value": { - "type": "string", - "propertyOrder": 3, - "title": "Identifier", - "options": { - "grid_columns": 6 - } - } - }, - "required": ["identifierType", "value"] + "headerTemplate": " {{#if self.identifierType}}\n" + + " {{self.identifierType}}\n" + + " {{else}}\n" + + " None\n" + + " {{/if}}", + "$ref": "definitions/base-repo/models/alternate_identifier.json", + "watch": { + "titleType": "self.identifierType" + } } }, "contributors": { "type": "array", "title":"Contributors", - "options": { - "grid_columns": 6, - "disable_collapse": false, - "disable_edit_json": true, - "disable_properties": true, - "compact": false - }, + "description": "One or more contributors to the resource.", "items": { - "type": "object", - "headerTemplate": "{{ self.contributionType }}", - "options": { - "grid_columns": 12, - "disable_collapse": false, - "disable_edit_json": true, - "disable_properties": true, - "compact": false - }, - "properties": { - "id": { - "type": "integer", - "propertyOrder": 1, - "readOnly": true - }, - "contributionType": { - "type": "string", - "title":"Contribution Type", - "propertyOrder": 2, - "enum": ["CONTACT_PERSON", "DATA_COLLECTOR", "DATA_CURATOR", "DATA_MANAGER", "DISTRIBUTOR", "EDITOR", "HOSTING_INSTITUTION", "OTHER", "PRODUCER", "PROJECT_LEADER", "PROJECT_MANAGER", "PROJECT_MEMBER", "REGISTRATION_AGENCY", "REGISTRATION_AUTHORITY", "RELATED_PERSON", "RESEARCH_GROUP", "RIGHTS_HOLDER", "RESEARCHER", "SPONSOR", "SUPERVISOR", "WORK_PACKAGE_LEADER"], - "options": { - "grid_columns": 12, - "disable_collapse": false, - "disable_edit_json": true, - "disable_properties": true, - "compact": false - } - }, - "user": { - "propertyOrder": 3, - "headerTemplate":" {{#if self.givenName}}\n" + - " {{#if self.familyName}}\n" + - " {{self.familyName}}, {{self.givenName}}\n" + - " {{else}}\n" + - " No Contributor\n" + - " {{/if}}"+ - " {{else}}\n" + - " No Contributor\n" + - " {{/if}}", - "$ref": "definitions/base-repo/models/agent.json", - "required": ["givenName", "familyName"], - "options": { - "grid_columns": 12, - "disable_collapse": false, - "disable_edit_json": true, - "disable_properties": false, - "compact": false - }, - "watch": { - "givenName": "self.givenName", - "familyName": "self.familyName" - } - } - }, - "required": ["contributionType", "user"] + "headerTemplate": "{{ self.contributionType }} ( {{ self.user.familyName }}, {{ self.user.givenName }})", + "$ref": "definitions/base-repo/models/contributor.json" } }, "creators": { "type": "array", "title":"Creators", - "format": "grid-strict", - "options": { - "grid_columns": 6, - "disable_collapse": false, - "disable_edit_json": true, - "disable_properties": true, - "compact": false - }, + "description": "One or more creators of the resource.", "items": { - "headerTemplate":" {{#if self.givenName}}\n" + - " {{#if self.familyName}}\n" + - " {{self.familyName}}, {{self.givenName}}\n" + - " {{else}}\n" + - " No Creator\n" + - " {{/if}}"+ + "headerTemplate": " {{#if self.familyName }}\n" + + " {{#if self.givenName }}\n" + + " {{ self.familyName }}, {{ self.givenName }}\n" + + " {{else}}\n" + + " None\n" + + " {{/if}}" + " {{else}}\n" + - " No Creator\n" + + " None\n" + " {{/if}}", "$ref": "definitions/base-repo/models/agent.json", - "required": ["givenName", "familyName"], "watch": { - "givenName": "self.givenName", - "familyName": "self.familyName" - } + "familyName": "self.familyName", + "givenName": "self.givenName" + } } }, "dates": { "type": "array", + "title": "Dates", + "description": "One or more dates where certain events happened to the resource.", "items": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "type": { - "type": "string", - "enum": ["ACCEPTED", "AVAILABLE", "COLLECTED", "COPYRIGHTED", "CREATED", "ISSUED", "SUBMITTED", "UPDATED", "VALID", "REVOKED"] - }, - "value": { - "type": "string", - "pattern": "\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\d([+-][0-2]\\d:[0-5]\\d|Z)" - } - } + "headerTemplate": "{{ self.type }}", + "$ref": "definitions/base-repo/models/date.json" } }, - - "embargoDate": { - "type": "string", - "pattern": "\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\d([+-][0-2]\\d:[0-5]\\d|Z)" - }, "formats": { "type": "array", + "title": "Format Information", + "description": "One or more format information entries.", "items": { + "headerTemplate": "Format #{{ i1 }} {{#if self}} ({{ self }}) {{else}} (None) {{/if}}", "type": "string" } }, "fundingReferences": { "type": "array", + "title":"Funding Information", + "description": "Funding information for the resource.", "items": { "$ref": "definitions/base-repo/models/funding_reference.json" } }, - "geoLocationsAsString": { - "type": "string" - }, "geoLocations": { "type": "array", "items": { @@ -319,98 +259,53 @@ let model = { } } }, - "id": { - "type": "string" - }, "identifier": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "identifierType": { - "type": "string" - }, - "value": { - "type": "string" - } - } - }, - "language": { - "$ref": "definitions/base-repo/models/language.json" - }, - "lastUpdate": { - "type": "string" + "title": "Persistent Identifier", + "description": "The persistent identifier of the resource.", + "$ref": "definitions/base-repo/models/identifier.json" }, - - "relatedIdentifiers": { "type": "array", + "title":"Related Identifiers", + "description": "One or more related identifiers for the resource.", "items": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "identifierType": { - "$ref": "#/$defs/IDENTIFIER_TYPE" - }, - "relatedMetadataScheme": { - "type": "string" - }, - "relationType": { - "type": "string", - "enum": ["IS_CITED_BY", "CITES", "IS_SUPPLEMENT_TO", "IS_SUPPLEMENTED_BY", "IS_CONTINUED_BY", "CONTINUES", "IS_NEW_VERSION_OF", "IS_PREVIOUS_VERSION_OF", "IS_PART_OF", "HAS_PART", "IS_REFERENCED_BY", "REFERENCES", "IS_DOCUMENTED_BY", "DOCUMENTS", "IS_COMPILED_BY", "COMPILES", "IS_VARIANT_FORM_OF", "IS_ORIGINAL_FORM_OF", "IS_IDENTICAL_TO", "HAS_METADATA", "IS_METADATA_FOR", "REVIEWS", "IS_REVIEWED_BY", "IS_DERIVED_FROM", "IS_SOURCE_OF"] - }, - "scheme": { - "$ref": "definitions/base-repo/models/scheme.json" - }, - "value": { - "type": "string" - } - } + "$ref": "definitions/base-repo/models/related_identifier.json" } }, - - "rights": { "type": "array", + "title":"Rights Information", + "description": "Rights information for the resource, e.g., access license.", "items": { + "headerTemplate": "Right #{{ i1 }} {{#if self.schemeId}} ({{ self.schemeId }}) {{else}} (None) {{/if}}", "$ref": "definitions/base-repo/models/scheme.json" } }, "sizes": { "type": "array", + "title": "Size Information", + "description": "Size information for the resource.", "items": { + "headerTemplate": "Size #{{ i1 }} {{#if self}} ({{ self }}) {{else}} (None) {{/if}}", "type": "string" } }, - "state": { - "type": "string", - "enum": ["VOLATILE", "FIXED", "REVOKED", "GONE"] - }, "subjects": { "type": "array", + "title": "Subjects", + "description": "Subject information for the resource.", "items": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "lang": { - "$ref": "definitions/base-repo/models/language.json" - }, - "scheme": { - "$ref": "definitions/base-repo/models/scheme.json" - }, - "value": { - "type": "string" - }, - "valueUri": { - "type": "string" - } - } + "headerTemplate": "Subject #{{ i1 }} {{#if self.value}} ({{ self.value }}) {{else}} (None) {{/if}}", + "$ref": "definitions/base-repo/models/subject.json" } - } + }, + + + "geoLocationsAsString": { + "type": "string", + "options":{ + "hidden":true + } + }, } }; diff --git a/definitions/base-repo/models/resource_type.json b/definitions/base-repo/models/resource_type.json index 20ca7a6..9e24341 100644 --- a/definitions/base-repo/models/resource_type.json +++ b/definitions/base-repo/models/resource_type.json @@ -3,16 +3,14 @@ "title": "Resource Type", "format": "grid-strict", "description": "The type of the resource.", - "options": { - "grid_columns": 12, - "disable_collapse": false, - "disable_edit_json": true, - "disable_properties": true, - "compact": false - }, "properties": { "id": { - "type": "integer" + "type": "integer", + "readOnly":true, + "propertyOrder":1, + "options": { + "hidden": true + } }, "typeGeneral": { "type": "string", @@ -35,14 +33,16 @@ ], "default": "DATASET", "options": { - "grid_columns": 4 + "grid_columns": 6, + "infoText": "The general type." } }, "value": { "type": "string", "title": "Specific Type", "options": { - "grid_columns": 8 + "grid_columns": 6, + "infoText": "The specific type." } } }, diff --git a/definitions/base-repo/models/scheme.json b/definitions/base-repo/models/scheme.json index d68fe32..db66474 100644 --- a/definitions/base-repo/models/scheme.json +++ b/definitions/base-repo/models/scheme.json @@ -1,14 +1,28 @@ { "type": "object", + "format": "grid-strict", "properties": { "id": { - "type": "integer" + "type": "integer", + "options": { + "hidden": true + } }, "schemeId": { - "type": "string" + "type": "string", + "title": "Identifier", + "options": { + "grid_columns": 6, + "infoText": "The scheme identifier." + } }, "schemeUri": { - "type": "string" + "type": "string", + "title": "URI", + "options": { + "grid_columns": 6, + "infoText": "The scheme URI." + } } } } diff --git a/definitions/base-repo/models/subject.json b/definitions/base-repo/models/subject.json new file mode 100644 index 0000000..fdd35cb --- /dev/null +++ b/definitions/base-repo/models/subject.json @@ -0,0 +1,45 @@ +{ + "type": "object", + "format": "grid-strict", + "properties": { + "id": { + "type": "integer", + "options": { + "hidden": true + } + }, + "value": { + "propertyOrder": 2, + "title": "Subject Value", + "type": "string", + "options": { + "grid_columns": 4, + "infoText": "The subject value, e.g., a human readable name." + } + }, + "valueUri": { + "propertyOrder": 3, + "title": "Value URI", + "type": "string", + "options": { + "grid_columns": 6, + "infoText": "The subject value URI, e.g., a machine readable description." + } + }, + "lang": { + "propertyOrder": 1, + "title": "Language", + "$ref": "language.json", + "options": { + "grid_columns": 2, + "infoText": "The subject language." + } + }, + "scheme": { + "$ref": "scheme.json", + "options": { + "hidden": true + } + } + } +} diff --git a/definitions/base-repo/models/title.json b/definitions/base-repo/models/title.json index 5598db7..a03bc48 100644 --- a/definitions/base-repo/models/title.json +++ b/definitions/base-repo/models/title.json @@ -2,42 +2,42 @@ "type": "object", "title": "Title", "format": "grid-strict", - "options": { - "disable_collapse": true, - "disable_edit_json": true, - "disable_properties": false, - "compact": false - }, "properties": { "id": { "type": "integer", "readOnly":true, - "propertyOrder":1 + "options": { + "hidden": true + } }, "lang": { + "title": "Language", "$ref": "language.json", - "propertyOrder":3, + "propertyOrder":2, "options":{ - "grid_columns":6 + "grid_columns":6, + "infoText": "The title language." } }, "titleType": { "type": "string", "title": "Title Type", - "propertyOrder":2, + "propertyOrder":1, "allowEmpty": false, "enum": ["ALTERNATIVE_TITLE", "SUBTITLE", "TRANSLATED_TITLE", "OTHER", ""], "default": "", "options":{ - "grid_columns":6 + "grid_columns":6, + "infoText": "The title type." } }, "value": { "type": "string", "title":"Value", - "propertyOrder":1, + "propertyOrder":3, "options":{ - "grid_columns":12 + "grid_columns":12, + "infoText": "The title value." } } diff --git a/definitions/base-repo/sample_schema.js b/definitions/base-repo/sample_schema.js new file mode 100644 index 0000000..70c6d76 --- /dev/null +++ b/definitions/base-repo/sample_schema.js @@ -0,0 +1,1523 @@ +var dataModel = { + "$schema": "https://json-schema.org/draft/2019-09/schema", + "title": "sample_schema", + "description":"Basic schema for sample description. It can be extended. According to the MDMC-NEP glossary, a Sample is Physical System (typically a piece of material) composed by one or more Sample Components, exposed to the Instrument during a Measurement, typically after a Sample Preparation. Sample may be held by a Sample Holder and/or carried by a Sample Carrier during the Measurement.", + "type":"object", + "required": [], + "format": "categories", + "$defs": + { + "cartesianType": + { + "type": "array", + "title": "cartesian coordinates", + "items": + { + "type": "object", + "properties": + { + "pointName": + { + "description": "Name of the point, for reference. E.g., P0 (usually the zero point of the coordinate system), P1, P2, P3", + "type": "string" + }, + "coordinates": + { + "type": "object", + "properties": + { + "x": {"type": "string"}, + "y": {"type": "string"}, + "z": {"type": "string"} + } + } + } + } + }, + "polarType": + { + "type": "array", + "title": "polar coordinates", + "items": + { + "type": "object", + "properties": + { + "pointName": + { + "description": "Name of the point, for reference. E.g., P0 (usually the zero point of the coordinate system), P1, P2, P3", + "type": "string" + }, + "coordinates": + { + "type": "object", + "properties": + { + "radius": {"type": "string"}, + "theta": {"type": "string"}, + "phi": {"type": "string"} + } + } + } + } + }, + noneType: + { + "type": "object", + "properties": {} + }, + otherType: + { + "type": "object", + "properties": {} + } + }, + "properties": + { + "sampleIdentification": + { + "type": "object", + "properties": + { + "sampleName": + { + "description": "(Required) - Name of the sample", + "type": "string" + }, + "sampleProducer": + { + "description": "(Required) - Producer or vendor of the sample, depending on whether the sample is produced in the lab by one or more research group members or is bought from a vendor. If it is preferred to avoid the name of the group member, self or own can be used as sampleProducer", + "type": "string" + }, + "samplePurpose": + { + "type": "object", + "properties": + { + "samplePurpose": + { + "description": "The tentative purpose of the sample (e.g., for which measurement(s) or subsequent analysis the sample was prepared). In this context, Correlative Characterization may be intended as a purpose. Multiple selection is allowed.", + "type": "array", + "items": + { + "type": "string", + "enum": + [ + "assessment", + "completeness check", + "correlative characterization", + "exploratory", + "feasibility", + "high quality measurement", + "test specific hypothesis", + "other (please specify in the comment)" + ] + } + }, + "samplePurposeComment": {"type": "string"} + } + }, + "sampleID": + { + "type": "object", + "properties": + { + "sampleID": + { + "description": "(Optional) - Identifier of the sample. The naming is not univocal among laboratories, thus the conventions may differ. In case of biological samples, it may be the internal ID; in case of outcome of a sample preparation, it may be the sample preparation ID; in other cases it can be the number on the box containing the sample; in other cases a convention is established. The choice of how to identify a specific sample is given to the laboratory.", + "type": "string" + }, + "sampleIDType": + { + "description": "(Optional) - Type of identifier of the sample.", + "type": "string", + "enum": + [ + "not applicable", + "text", + "code", + "value", + "other (please specify in the comment)" + ] + }, + "sampleIDTypeComment": {"type": "string"}, + "sampleIDPosition": + { + "description": "The sample has an ID printed on it. It's important to know its position on the sample. Multiple selection is allowed.", + "type": "array", + "items": + { + "type": "string", + "enum": + [ + "not applicable", + "top", + "bottom", + "right", + "left", + "front side", + "back side" + ] + } + } + } + } + } + }, + "sampleComponents": + { + "description": "Physical System (typically a piece of material) which constitutes a part of a Sample. It may include one or more substrates, layers, masks, embedding or filler or evaporation materials, coatings, conducting powders and molecules.", + "type": "array", + "items": + { + "type": "object", + "properties": + { + "componentName": + { + "description": "(Required) - Name of the sample component", + "type": "string" + }, + "componentChemicalFormula": + { + "description": "(Recommended) - Chemical formula of the sample component", + "type": "string" + }, + "componentCASNumber": + { + "description": "(Optional) - CAS number of the sample component, if known and applicable", + "type": "string" + }, + "componentMaterialDataSheet": + { + "description": "(Optional) - Link to the file describing the composition specification, usually called Material Data Sheet, if available.", + "type": "string" + }, + "componentAdditionalFeatures": + { + "description": "(Optional) - Description of the missing relevant features describing the Sample Component, if any.", + "type": "string" + } + } + } + }, + "sampleCharacterization": + { + "type": "object", + "properties": + { + "phaseOfMatter": + { + "description": "A matter object throughout which all physical properties of a material are essentially uniform. Multiple selection is allowed.", + "type": "object", + "properties": + { + "phaseOfMatterOptions": + { + "description": "A matter object throughout which all physical properties of a material are essentially uniform. Multiple selection is allowed.", + "type": "array", + "items": + { + "type": "string", + "enum": + [ + "solid", + "liquid", + "gas", + "plasma", + "crystalline", + "disordered", + "melt", + "metastable", + "nonequilibrium", + "ordered", + "other (please specify in the comment)" + ] + } + }, + "comment": {"type": "string"} + } + }, + "materialType": + { + "type": "string", + "enum": + [ + "notApplicable", + "biologicals", + "biomaterials", + "ceramics", + "metalsAndAlloys", + "metamaterials", + "molecularFluids", + "organicCompounds", + "organometallics", + "polymers", + "semiconductors" + ] + }, + "notApplicable": + { + "type": "object", + "properties": + { + "comment": {"type": "string"} + } + }, + "biological": + { + "type": "object", + "properties": {} + }, + "biomaterials": + { + "type": "object", + "properties": {} + }, + "ceramics": + { + "type": "object", + "properties": + { + "ceramicOptions": + { + "type": "string", + "enum": + [ + "carbides", + "cements", + "nitrides", + "oxides", + "perovskites", + "silicates", + "other (please specify in the comment)" + ] + }, + "comment": {"type": "string"} + } + }, + "metalsAndAlloys": + { + "type": "object", + "properties": + { + "metalsAndAlloysOptions": + { + "type": "string", + "enum": + [ + "Al-containing", + "commercially pure metals", + "Cu-containing", + "Fe-containing", + "intermetallics", + "Mg-containing", + "Ni-containing", + "rare earths", + "refractory", + "steels", + "superalloys", + "Ti-containing", + "other (please specify in the comment)" + ] + }, + "comment": {"type": "string"} + } + }, + "metamaterials": + { + "type": "object", + "properties": {} + }, + "molecularFluids": + { + "type": "object", + "properties": {} + }, + "organicCompounds": + { + "type": "object", + "properties": + { + "organicCompoundsOptions": + { + "type": "string", + "enum": + [ + "acohols", + "aldehydes", + "alkanes", + "alkenes", + "alkynes", + "amines", + "carboxylic acids", + "cyclic compounds", + "cycloalkanes", + "esters", + "ketones", + "nitriles", + "other (please specify in the comment)" + ] + }, + "comment": {"type": "string"} + } + }, + "organometallics": + { + "type": "object", + "properties": {} + }, + "polymers": + { + "type": "object", + "properties": + { + "polymersOptions": + { + "type": "string", + "enum": + [ + "copolymers", + "elastomers", + "homopolymers", + "liquid crystals", + "polymer blends", + "rubbers", + "thermoplastics", + "thermosets", + "other (please specify in the comment)" + ] + }, + "comment": {"type": "string"} + } + }, + "semiconductors": + { + "type": "object", + "properties": + { + "semiconductorsOptions": + { + "type": "string", + "enum": + [ + "extrinsic", + "II-VI", + "III-V", + "intrinsic", + "n-type", + "p-type", + "other (please specify in the comment)" + ] + }, + "comment": {"type": "string"} + } + }, + "materialDataSheet": + { + "description": "(Optional) - Link to the file describing the composition specification, usually called Material Data Sheet, if available.", + "type": "string" + } + } + }, + "structuralFeatures": + { + "type": "object", + "properties": + { + "composites": + { + "type": "object", + "properties": + { + "compositesOptions": + { + "type": "array", + "items": + { + "type": "string", + "enum": + [ + "biological or green", + "fiber-reinforced", + "metal-matrix", + "nanocomposites", + "particle-reinforced", + "polymer-matrix", + "structural", + "other (please specify in the comment)" + ] + } + }, + "comment": {"type": "string"} + } + }, + "defects": + { + "type": "object", + "properties": + { + "defectsOptions": + { + "type": "array", + "items": + { + "type": "string", + "enum": + [ + "cracks", + "crazing", + "dislocations", + "inclusions", + "interstitials", + "point defects", + "pores", + "vacancies", + "voids", + "other (please specify in the comment)" + ] + } + }, + "comment": {"type": "string"} + } + }, + "interfacial": + { + "type": "object", + "properties": + { + "interfacialOptions": + { + "type": "array", + "items": + { + "type": "string", + "enum": + [ + "grain boundaries", + "interfacial surface area", + "magnetic domain walls", + "phase boundaries", + "stacking faults", + "surfaces", + "twin boundaries", + "other (please specify in the comment)" + ] + } + }, + "comment": {"type": "string"} + } + }, + "microstructures": + { + "type": "object", + "properties": + { + "microstructuresOptions": + { + "type": "array", + "items": + { + "type": "string", + "enum": + [ + "BBC spheres", + "cellular", + "clustering", + "compound", + "crystallinity", + "defect structures", + "dentritic", + "dispersion", + "eutectic", + "grains", + "gyroid", + "HEX cylinders", + "lamellae", + "nanocrystalline", + "particle distribution", + "particle shape", + "polycrystalline", + "porosity", + "precipitates", + "quasicrystalline", + "single crystal", + "twinned", + "other (please specify in the comment)" + ] + } + }, + "comment": {"type": "string"} + } + }, + "molecularStructure": + { + "type": "object", + "properties": + { + "molecularStructureOptions": + { + "type": "array", + "items": + { + "type": "string", + "enum": + [ + "alternating copolymer", + "block copolymer", + "bottlebrush", + "dendrimer", + "end-group composition", + "funtionalization", + "gradient copolymer", + "long-chain branching", + "surfactants", + "tacticity", + "other (please specify in the comment)" + ] + } + }, + "comment": {"type": "string"} + } + }, + "morphologies": + { + "type": "object", + "properties": + { + "morphologiesOptions": + { + "type": "array", + "items": + { + "type": "string", + "enum": + [ + "aligned", + "amorphous", + "anisotropic", + "clusters", + "complex fluids", + "glass", + "isotropic", + "layered", + "nanoparticles or nanotubes", + "one-dimensional", + "open-framework", + "particles or colloids", + "percolated", + "porous", + "quantum dots or wires", + "random", + "semicrystalline", + "thin film", + "two-dimensional", + "wires", + "woven", + "other (please specify in the comment)" + ] + } + }, + "comment": {"type": "string"} + } + }, + "properties": + { + "type": "object", + "properties": + { + "propertiesOptions": + { + "type": "array", + "items": + { + "type": "string", + "enum": + [ + "diamagnetic", + "paramagnetic", + "ferromagnetic", + "antiferromagnetic", + "ferrimagnetic", + "nonmagnetic", + "conductor", + "semiconductor", + "superconductor", + "other (please add in the comments)" + ] + } + }, + "comment": {"type": "string"} + } + } + } + }, + "sampleDescription": + { + "type": "object", + "properties": + { + "expirationDate": + { + "description": "(Optional) - Sample expiration date, if any. Relevant in case of biological samples", + "type":"string", + "format": "date" + }, + "sampleSize": + { + "description": "(Optional) - Size of the sample, mainly needed to evaluate whether the sample fits a certain measurement. Regardless of the shape, the sample size can be approximated (e.g. the diameter of a cylinder can be indicated as sizeX and sizeY).", + "type": "object", + "properties": + { + "sizeX": + { + "description": "(Optional) - Size of the sample in the x dimension. Regardless of the shape, the sample size can be approximated (e.g. the diameter of a cylinder can be indicated as sizeX).", + "type": "string" + }, + "sizeY": + { + "description": "(Optional) - Size of the sample in the y dimension. Regardless of the shape, the sample size can be approximated (e.g. the diameter of a cylinder can be indicated as sizeY).", + "type": "string" + }, + "sizeZ": + { + "description": "(Optional) - Size of the sample in the z dimension. Regardless of the shape, the sample size can be approximated (e.g. the hight of a cylinder can be indicated as sizeZ).", + "type": "string" + } + } + }, + "sampleMass": {"type": "string"}, + "sampleVolume": {"type": "string"}, + "sampleDensity": {"type": "string"}, + "samplePressure": + { + "description": "(Optional) - Usually the gas pressure. It can be a numerical value, a range of numerical values, or some text (e.g., vacuum, high vacuum, ultra high vacuum, …)", + "type": "string" + }, + "sampleTemperature": + { + "description": "(Optional) - Temperature of the sample. It can be a numerical value, a range of numerical values, or some text (e.g., room temperature).", + "type": "string" + }, + "sampleVisibleElements": + { + "type": "object", + "properties": + { + "sampleVisibleElements": + { + "type": "array", + "items": + { + "type": "string", + "enum": + [ + "none", + "pattern", + "orientation", + "fiducials", + "sample ID", + "other (please specify in the comment)" + ] + } + }, + "comment": {"type": "string"} + } + }, + "sampleAdditionalFeatures": + { + "description": "(Optional) - Description of the missing relevant features describing the sample, if any.", + "type": "string" + } + } + }, + "samplePreparation": + { + "type": "object", + "properties": + { + "preparationDate": + { + "description": "(Optional) - Date of preparation", + "type": "string", + "format": "date" + }, + "consumables": + { + "description": "Auxiliary entity used during Fabrication, Sample Preparation or Measurement which has a limited time capacity or is limited in its number of uses before it is disposed of, necessary to the process itself and normally bought from third party manufacturers. Examples are: gloves, syringes, wipes, etching solutions, glass slides, spatulas, weighing paper, two-sided tape.", + "type": "array", + "items": + { + "type": "string" + } + }, + "preparationMethod": + { + "type": "array", + "items": + { + "type": "object", + "properties": + { + "preparationStep": + { + "type": "string", + "enum": + [ + "notApplicable", + "annealingHomogenization", + "depositionCoating", + "joining", + "mechanicalAndSurface", + "powderProcessing", + "cooling", + "reactive", + "other (please add in the comments)" + ] + }, + "notApplicable": + { + "type": "object", + "properties": + { + "comments": {"type": "string"} + } + }, + "annealingHomogenization": + { + "type": "object", + "properties": + { + "annealingHomogenizationMethod": + { + "type": "string", + "enum": + [ + "unspecified annealing and homogenization", + "aging", + "dry blending", + "homogenization", + "mechanical mixing", + "melt mixing", + "normalizing", + "recrystallization", + "stress relieving", + "tempering", + "twin screw excrusion", + "ultrasonication", + "vacuum annealing/heating", + "curing/hardening", + "other (please add in the comments)" + ] + }, + "comments": {"type": "string"} + } + }, + "depositionCoating": + { + "type": "object", + "properties": + { + "depositionCoatingMethod": + { + "type": "string", + "enum": + [ + "unspecified deposition and coating", + "chemical vapour deposition", + "atomic layer deposition", + "gas dosing/gas exposure", + "sputter coating", + "ion implantation", + "electrodeposition", + "evaporation/physical vapor deposition", + "electron beam deposition", + "ion beam deposition", + "beam epitaxy", + "ink-jet deposition", + "pulsed laser deposition", + "Langmuir-Blodgett film deposition", + "plasma spraying", + "carbon evaporation coating", + "spin coating", + "other (please add in the comments)" + ] + }, + "comments": {"type": "string"} + } + }, + "joining": + { + "type": "object", + "properties": + { + "joiningMethod": + { + "type": "string", + "enum": + [ + "unspecified joining", + "adhesive bonding", + "soldering/brazing/wire bonding", + "resistance welding", + "clamping", + "other (please add in the comments)" + ] + }, + "comments": {"type": "string"} + } + }, + "mechanicalAndSurface": + { + "type": "object", + "properties": + { + "mechanicalAndSurfaceMethod": + { + "type": "string", + "enum": + [ + "unspecified mechanical and surface", + "focused ion beam", + "lithography", + "polishing", + "sectioning", + "sputtering", + "thermal plasma processing", + "exfoliation/cleavage/decapping", + "grinding", + "etching", + "grit blasting", + "sterilization", + "Laser Surface Texturing (LST)", + "dimpling", + "other (please add in the comments)" + ] + }, + "comments": {"type": "string"} + } + }, + "powderProcessing": + { + "type": "object", + "properties": + { + "powderProcessingMethod": + { + "type": "string", + "enum": + [ + "unspecified powder processing", + "sieve fraction preparation", + "pressing", + "other (please add in the comments)" + ] + }, + "comments": {"type": "string"} + } + }, + "cooling": + { + "type": "object", + "properties": + { + "coolingMethod": + { + "type": "string", + "enum": + [ + "unspecified cooling", + "gas cooling", + "vacuum cooling", + "other (please add in the comments)" + ] + }, + "comments": {"type": "string"} + } + }, + "reactive": + { + "type": "object", + "properties": + { + "reactiveMethod": + { + "type": "string", + "enum": + [ + "unspecified reactive", + "addition polymerization", + "condensation polymerization", + "curing", + "dissolving/etching", + "drying", + "in-situ polymerization", + "post-polymerization modification", + "reductive roasting", + "solution processing", + "reactive ion etching (RIE/IBE)", + "other (please specify in the comments)" + ] + }, + "comments": {"type": "string"} + } + }, + "other": + { + "type": "object", + "properties": + { + "comments": {"type": "string"} + } + } + } + } + }, + "preparationDescription": + { + "description": "(Optional) - Short description to keep track of the preparation procedures and treatments required to obtain the Sample.", + "type": "string" + }, + "preparationHistoryFile": + { + "description": "(Optional) - Type of file, if any, where the complete Sample Preparation history is described", + "type": "string", + "enum": + [ + "Not Applicable", + "ELN", + "Data Repository", + "Included in the Raw Data file", + "Paper log book" + ] + }, + "preparationHistoryFileReference": + { + "description": "(Optional) - Reference to the location of the file where the complete Sample Preparation history is described. Ideally, the unique identifier to the ELN or to a data repository. Not needed in case of a paper log book, or if sample preparation history is included in the raw data", + "type": "string" + } + } + }, + + + + + + "sampleHandlingPrecaution": + { + "description": "(Optional) - Set of features about the sample which are important to know for handling it", + "type": "object", + "properties": + { + "sensitivityAgainst": + { + "type": "object", + "properties": + { + "sensitivityList": + { + "type": "array", + "items": + { + "type": "string", + "enum": + [ + "O2", + "H2O/moisture", + "N2", + "organic solvents", + "eBeam", + "iBeam", + "radiation", + "shocks", + "variations of temperature", + "variations of air pressure", + "variations of gas concentration", + "variations of humidity", + "other (please add in the comments)" + ] + } + }, + "comments": {"type": "string"} + } + }, + "safetyInfo": + { + "type": "object", + "properties": + { + "hazard": + { + "type": "array", + "items": + { + "type": "string", + "enum": + [ + "reactive", + "radioactive", + "oxidising", + "corrosive", + "contaminant", + "combustive", + "biohazard", + "carcinogenic/mutagenic/teratogenic", + "inflammable", + "toxic or irritant", + "explosive", + "nanostructured/nanoparticles", + "other (please add in the comments)" + ] + } + }, + "comments": {"type": "string"} + } + }, + "sampleHandling": + { + "type": "object", + "properties": + { + "noTweezers": + { + "description": "The sample has regions which cannot be touched or reached.", + "type":"string" + }, + "gloves": + { + "description": "The sample must be handled using gloves.", + "type": "string" + }, + "shockProtection": + { + "description": "The sample must be protected against shocks.", + "type": "string" + }, + "cleanRoom": + { + "description": "The sample should be treated only under the given specific clean room conditions.", + "type":"string" + }, + "humidity": + { + "description": "The sample should be handled at the given humidity. It can be a numerical value or a range of numerical values.", + "type": "string" + }, + "gasAtmosphere": + { + "description": "The sample has a reactive top layer and needs the given inert gas around it during treatment (e.g. Nitrogen).", + "type": "string" + }, + "additionalNotes": + { + "description": "(Optional) - Any additional notes which might be relevant for sample handling", + "type": "string" + } + } + }, + "storageConditions": + { + "type": "object", + "properties": + { + "storageTemperature": + { + "description": "(Optional) - Commonly known as sample temperature. It can be a numerical value, a range of numerical values, or some text (e.g., room temperature).", + "type":"string" + }, + "storagePressure": + { + "description": "(Optional) - Generally it does not refer to gas pressure, because usually gas pressure = storage pressure. It can be a numerical value, a range of numerical values, or some text (e.g., vacuum, high vacuum, ultra high vacuum, …)", + "type":"string" + }, + "storageHumidity": + { + "description": "(Optional) - To be indicated only if different from the humidity required for sample handling. It can be a numerical value or a range of numerical values.", + "type":"string" + }, + "storageGasAtmosphere": + { + "description": "(Optional) - To be indicated only if different from the gas atmosphere required for sample handling. It can be a numerical value or a range of numerical values", + "type":"string", + "enum": + [ + "Not applicable", + "air", + "dry air", + "vacuum", + "Ar", + "N", + "other (please add in the comments)" + ] + }, + "storageEquipment": + { + "description": "(Optional) - Equipment used for storing the sample. Multiple selection is allowed.", + "type": "object", + "properties": + { + "storageEquipmentOptions": + { + "type":"array", + "items": + { + "type":"string", + "enum": + [ + "Not applicable", + "glove box", + "fume hood", + "dessicator", + "open bench", + "refrigerator", + "freezer", + "cryostat", + "liquid N dewar", + "drying oven", + "UHV chamber", + "other (please add in the comments)" + ] + } + }, + "comments": {"type": "string"} + } + }, + "additionalNotes": + { + "description": "(Optional) - Any additional notes which might be relevant for storage conditions", + "type": "string" + } + } + } + } + }, + + + + + + + + "sampleHolder": + { + "type": "object", + "properties": + { + "sampleHolderType": + { + "description": "Type of sample holder", + "type": "string", + "enum": + [ + "Not applicable", + "stub", + "dish", + "cylinder", + "glass slide", + "TEM grid", + "tilting support", + "custom holder", + "Other (please add in the comments)" + ] + }, + "sampleHolderMaterial": + { + "type": "string" + }, + "sampleHolderTemperatureRange": + { + "description": "Supported range of temperature", + "type": "string" + }, + "supportedSamples": + { + "description": "Supported (number and/or type of) samples", + "type": "string" + }, + "sampleHolderDescription": + { + "description": "Any additional description which might be useful to identify the sample holder", + "type": "string" + }, + "fixingMethod": + { + "description": "Method used to hold the sample on the sample holder", + "type": "string", + "enum": + [ + "Not applicable", + "silver tape", + "silver paint", + "carbon paint", + "aluminium tape", + "glue", + "Other (please add in the comments)" + ] + }, + "comments": {"type": "string"} + } + }, + "sampleCarrier": + { + "type": "object", + "properties": + { + "sampleCarrierType": + { + "description": "Type of sample carrier. It may include the substrate, in case it is used as Sample Carrier.", + "type": "string", + }, + "sampleCarrierMaterial": + { + "type": "string" + }, + "sampleCarrierLength": {"type": "string"}, + "sampleCarrierWidth": {"type": "string"}, + "sampleCarrierHeight": {"type": "string"}, + "sampleCarrierTemperatureRange": + { + "description": "Supported range of temperature", + "type": "string" + }, + "supportedSamples": + { + "description": "Supported (number and/or type of) samples", + "type": "string" + }, + "supportedHolders": + { + "description": "Supported (number and/or type of) holders", + "type": "string" + }, + "sampleCarrierDescription": + { + "description": "Any additional description which might be useful to identify the sample carrier", + "type": "string" + }, + "comments": {"type": "string"} + } + }, + "sampleReferencing": + { + "type": "object", + "properties": + { + "axisOrientation": {"type": "string"}, + "sampleReference": + { + "description": "Coordinates of the markers in the sample reference system.", + "type": "array", + "enum": + [ + "notApplicable", + "cartesian", + "polar", + "other" + ] + }, + "cartesian": {"$ref": "#/$defs/cartesianType"}, + "polar": {"$ref": "#/$defs/polarType"}, + "notApplicable": {"$ref": "#/$defs/noneType"}, + "other": {"$ref": "#/$defs/otherType"}, + "comments": {"type": "string"} + } + }, + "holderReferencing": + { + "type": "object", + "properties": + { + "axisOrientation": {"type": "string"}, + "sampleOnHolder": + { + "type": "object", + "properties": + { + "samplePositionOnHolder": + { + "description": "Sample position in the holder reference system.", + "type": "array", + "enum": + [ + "notApplicable", + "cartesian", + "polar", + "other" + ] + }, + "cartesian": {"$ref": "#/$defs/cartesianType"}, + "polar": {"$ref": "#/$defs/polarType"}, + "notApplicable": {"$ref": "#/$defs/noneType"}, + "other": {"$ref": "#/$defs/otherType"} + } + }, + "markerOnHolder": + { + "type": "object", + "properties": + { + "holderReference": + { + "description": "Coordinates of the markers in the holder reference system.", + "type": "array", + "enum": + [ + "notApplicable", + "cartesian", + "polar", + "other" + ] + }, + "cartesian": {"$ref": "#/$defs/cartesianType"}, + "polar": {"$ref": "#/$defs/polarType"}, + "notApplicable": {"$ref": "#/$defs/noneType"}, + "other": {"$ref": "#/$defs/otherType"} + } + }, + "comments": {"type": "string"} + } + }, + "carrierReferencing": + { + "type": "object", + "properties": + { + "axisOrientation": {"type": "string"}, + "holderOnCarrier": + { + "type": "object", + "properties": + { + "holderPositionOnCarrier": + { + "description": "Holder position in the carrier reference system.", + "type": "array", + "enum": + [ + "notApplicable", + "cartesian", + "polar", + "other" + ] + }, + "cartesian": {"$ref": "#/$defs/cartesianType"}, + "polar": {"$ref": "#/$defs/polarType"}, + "notApplicable": {"$ref": "#/$defs/noneType"}, + "other": {"$ref": "#/$defs/otherType"} + } + }, + "markerOnCarrier": + { + "type": "object", + "properties": + { + "carrierReference": + { + "description": "Coordinates of the markers in the carrier reference system.", + "type": "array", + "enum": + [ + "notApplicable", + "cartesian", + "polar", + "other" + ] + }, + "cartesian": {"$ref": "#/$defs/cartesianType"}, + "polar": {"$ref": "#/$defs/polarType"}, + "notApplicable": {"$ref": "#/$defs/noneType"}, + "other": {"$ref": "#/$defs/otherType"} + } + }, + "comments": {"type": "string"} + } + }, + "ROI": + { + "type": "object", + "properties": + { + "axisOrientation": {"type": "string"}, + "ROIReference": + { + "description": "Coordinates of the points defining the sample ROI (Region of Interest) in the sample reference system.", + "type": "array", + "enum": + [ + "notApplicable", + "cartesian", + "polar", + "other" + ] + }, + "cartesian": {"$ref": "#/$defs/cartesianType"}, + "polar": {"$ref": "#/$defs/polarType"}, + "notApplicable": {"$ref": "#/$defs/noneType"}, + "other": {"$ref": "#/$defs/otherType"}, + "comments": {"type": "string"} + } + }, + "parents": + { + "type": "array", + "items": + { + "type": "object", + "properties": + { + "parentType": + { + "type": "string", + "default": "not applicable", + "enum": + [ + "not applicable", + "precursor", + "sample" + ] + }, + "parentReferenceType": + { + "type": "string", + "enum": + [ + "plain text", + "external URL", + "MetaStore URI" + ] + }, + "parentReference": + { + "type": "string", + "description": "If type is 'MetaStore URI' it is possible to easily fill this field in a later stage" + } + }, + "required": + [ + "parentType" + ], + "if": + { + "properties": + { + "parentType": + { + "not": + { + "const": "not applicable" + } + } + } + }, + "then": + { + "required": + [ + "parentReferenceType", + "parentReference" + ] + } + } + } + } +} diff --git a/repo-management_new.html b/repo-management_new.html index 60bb362..4f77f0b 100644 --- a/repo-management_new.html +++ b/repo-management_new.html @@ -40,7 +40,7 @@ } - + @@ -92,7 +92,7 @@ return value; }); const element = document.getElementById('editor'); - JSONEditor.defaults.options.theme = 'bootstrap4'; + JSONEditor.defaults.options.theme = 'bootstrap5'; JSONEditor.defaults.options.template = 'handlebars'; JSONEditor.defaults.options.ajax = true; JSONEditor.defaults.options.iconlib = "fontawesome5"; @@ -133,7 +133,7 @@ //JSONEditor.defaults.language = "es"; const editor = new JSONEditor(element,{ schema: model, - display_required_only: true, + display_required_only: false, compact:true, no_additional_properties: true }); diff --git a/search.html b/search.html new file mode 100644 index 0000000..2f0fcf2 --- /dev/null +++ b/search.html @@ -0,0 +1,131 @@ + + + + + Title + + + + + + +
+ +
+

Categories

+
+
+
+

Publisher

+
+
+
+

State

+
+
+
+ +
+ +
+
+ + + + + From 535d7c8b3ec894b34a75a8d4f0469f6aa3cfc501 Mon Sep 17 00:00:00 2001 From: Volker Hartmann Date: Fri, 12 Jan 2024 16:00:17 +0100 Subject: [PATCH 31/40] Add workflow for generating GitHub Packages. --- .github/workflows/docker-publish.yml | 118 +++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 .github/workflows/docker-publish.yml diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml new file mode 100644 index 0000000..2541e89 --- /dev/null +++ b/.github/workflows/docker-publish.yml @@ -0,0 +1,118 @@ +# Create and publish a Docker image on github +name: Create and publish a Docker image + +# Configures this workflow to run every time a change +# is tagged with a '-v' in between (e.g.: metastore-v1.0.0). +on: + push: + # Publish `main` as Docker `latest` image. +# branches: +# - main + + # Publish `v1.2.3` tags as releases. + tags: + # - v* + - '*-v*' + +# Defines two custom environment variables for the workflow. +# These are used for the Container registry domain, and a +# name for the Docker image that this workflow builds. +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +# Two jobs for creating and pushing Docker image +# - build-and-push-image -> triggered by commits on main and tagging with semantic version (e.g.: v1.2.3) +# - build-and-push-image-of-branch -> triggered by tags matching '*-v*' (e.g.: Version_1-v1.2.3) +jobs: + build-and-push-image: + runs-on: ubuntu-latest + if: ${{ contains(github.ref_name, '-') == failure() }} + # Sets the permissions granted to the `GITHUB_TOKEN` + # for the actions in this job. + permissions: + contents: read + packages: write + # + steps: + - name: Checkout repository + uses: actions/checkout@v4 + # Uses the `docker/login-action` action to log in to the Container + # registry using the account and password that will publish the packages. + # Once published, the packages are scoped to the account defined here. + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + # This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) + # to extract tags and labels that will be applied to the specified image. + # The `id` "meta" allows the output of this step to be referenced in a + # subsequent step. The `images` value provides the base name for the tags + # and labels. + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + # This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages. + # It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository. + # It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step. + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + build-and-push-image-of-branch: + runs-on: ubuntu-latest + if: contains(github.ref_name, '-') + # Sets the permissions granted to the `GITHUB_TOKEN` + # for the actions in this job. + permissions: + contents: read + packages: write + # + steps: + - name: Split first part + env: + TAG: ${{ github.ref_name }} + id: split + run: echo "branch=${TAG%-v*}" >> $GITHUB_OUTPUT + - name: Test variable + run: | + echo ${{ steps.split.outputs.branch }} + - name: Checkout repository + uses: actions/checkout@v4 + # Uses the `docker/login-action` action to log in to the Container + # registry using the account and password that will publish the packages. + # Once published, the packages are scoped to the account defined here. + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + # This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) + # to extract tags and labels that will be applied to the specified image. + # The `id` "meta" allows the output of this step to be referenced in a + # subsequent step. The `images` value provides the base name for the tags + # and labels. + - name: Extract metadata (tags, labels) for Docker + id: meta-branch + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-${{steps.split.outputs.branch}} + # This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages. + # It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository. + # It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step. + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: ${{ steps.meta-branch.outputs.tags }} + labels: ${{ steps.meta-branch.outputs.labels }} + From b18eb689951a144fb2dda569382e1333eb7e5865 Mon Sep 17 00:00:00 2001 From: Volker Hartmann Date: Mon, 19 Feb 2024 07:45:59 +0100 Subject: [PATCH 32/40] Replace the SCC logo with the latest version. --- images/Logo_SCC.png | Bin 6512 -> 34264 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/images/Logo_SCC.png b/images/Logo_SCC.png index dc90cccd59ab3b025b2cc425724dc0d86eba794c..e53067b9f9d5fdde78474bbcb834511a04d901a2 100644 GIT binary patch literal 34264 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 W9KCDLOOM Date: Mon, 26 Feb 2024 15:33:53 +0100 Subject: [PATCH 33/40] MetaStore: If the user is already logged in, this is now displayed directly in the 'Search' tab. --- elastic-search-metastore.html | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/elastic-search-metastore.html b/elastic-search-metastore.html index d753605..879ce41 100644 --- a/elastic-search-metastore.html +++ b/elastic-search-metastore.html @@ -21,6 +21,7 @@ + @@ -311,6 +312,16 @@

let from = 0; let size = page_size; + applyConfig(keycloak, showServiceUrl,appDescription, config, addMessage, (login, username) => { + if(login){ + $("#logged_in_as").text("Logged in as " + username); + $("#editor-create-button").removeAttr("disabled"); + }else{ + $("#logged_in_as").text("Not logged in."); + $("#editor-create-button").attr("disabled", "disabled"); + } + }); + Handlebars.registerHelper('isOpen', function (list) { if (list != null && list.indexOf("anonymousUser") > -1) { return true; @@ -438,6 +449,15 @@

from = from + size; doSearch(true); }); + + if (localStorage.getItem("userLoggedIn")) { + localStorage.removeItem("userLoggedIn") + $("#login_button").click(); + } + + if (typeof keycloak != typeof undefined && config.token == null) { + $("#editor-create-button").attr("disabled", "disabled"); + } addMessage(0, "Search successfully initialized."); From 67981a692017c365cf5f1496b422d1c0646e45f5 Mon Sep 17 00:00:00 2001 From: Volker Hartmann Date: Mon, 26 Feb 2024 16:04:39 +0100 Subject: [PATCH 34/40] MetaStore: Fix download URL for metadata documents in 'Search' tab. --- elastic-search-metastore.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/elastic-search-metastore.html b/elastic-search-metastore.html index 879ce41..166c532 100644 --- a/elastic-search-metastore.html +++ b/elastic-search-metastore.html @@ -814,14 +814,14 @@

$.ajax({ type: "GET", - url: ajaxBaseUrl + "metadata/" + id, + url: ajaxBaseUrl + id, contentType: "application/json", headers: headers, success: function (output, status, xhr) { resolve(output); }, error: function (result) { - let message = "Failed to obtain metadata " + ajaxBaseUrl + "metadata/" + id + ". (HTTP " + result.status + ")"; + let message = "Failed to obtain metadata " + ajaxBaseUrl + id + ". (HTTP " + result.status + ")"; reject(message); } }); From 4e4bfb7d9ddff49be7414daae03f30ad1eff3406 Mon Sep 17 00:00:00 2001 From: Volker Hartmann Date: Wed, 27 Mar 2024 11:11:12 +0100 Subject: [PATCH 35/40] MetaStore: Fix outdated download links for documents inside landing page. --- .../metastore/landingpage_schema.handlebars | 18 ++++++++++++++---- .../metastore/landingpage_schema.handlebars.js | 12 ++++-------- metastore-landing-page.html | 17 +++++++++++------ 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/definitions/metastore/landingpage_schema.handlebars b/definitions/metastore/landingpage_schema.handlebars index 6196dbd..953746c 100644 --- a/definitions/metastore/landingpage_schema.handlebars +++ b/definitions/metastore/landingpage_schema.handlebars @@ -73,8 +73,13 @@
- +
Metadata Document
+
+ +
+ +
+
{{md_record.documentHash}}
@@ -82,8 +87,13 @@
- +
Schema Document
+
+ +
+ +
+
{{schema_record.schemaHash}}
diff --git a/definitions/metastore/landingpage_schema.handlebars.js b/definitions/metastore/landingpage_schema.handlebars.js index c6e124d..b63e49a 100644 --- a/definitions/metastore/landingpage_schema.handlebars.js +++ b/definitions/metastore/landingpage_schema.handlebars.js @@ -48,22 +48,18 @@ templates['landingpage_schema'] = template({"1":function(container,depth0,helper + alias2(alias1(((stack1 = ((stack1 = (depth0 != null ? lookupProperty(depth0,"md_record") : depth0)) != null ? lookupProperty(stack1,"relatedResource") : stack1)) != null ? lookupProperty(stack1,"identifier") : stack1), depth0)) + "'\n target='_blank'>" + alias2(alias1(((stack1 = ((stack1 = (depth0 != null ? lookupProperty(depth0,"md_record") : depth0)) != null ? lookupProperty(stack1,"relatedResource") : stack1)) != null ? lookupProperty(stack1,"identifier") : stack1), depth0)) - + "
\n
\n \n
\n
\n
\n
Metadata Document
\n \n \n \n \n
...
\n
\n
\n
Downloads
\n \n \n \n
\n
\n
\n \n
" + + "
\n
\n \n
\n
\n
\n
Metadata Document
\n \n \n \n \n
...
\n
\n
\n
Downloads
\n \n \n \n
\n
\n
\n
Metadata Document
\n
\n
Save
\n
\n \n
\n
\n
" + alias2(alias1(((stack1 = (depth0 != null ? lookupProperty(depth0,"md_record") : depth0)) != null ? lookupProperty(stack1,"documentHash") : stack1), depth0)) - + "
\n
\n
\n
\n
\n
\n
\n \n
" + + "
\n
\n
\n
\n
\n
\n
\n
Schema Document
\n
\n
Save
\n
\n \n
\n
\n
" + alias2(alias1(((stack1 = (depth0 != null ? lookupProperty(depth0,"schema_record") : depth0)) != null ? lookupProperty(stack1,"schemaHash") : stack1), depth0)) + "
\n
\n
\n
\n
\n
\n
\n
\n
\n \n
\n
\n
\n

Metadata

\n Type:
\n " + alias2(alias1(((stack1 = (depth0 != null ? lookupProperty(depth0,"schema_record") : depth0)) != null ? lookupProperty(stack1,"type") : stack1), depth0)) + "
\n MimeType:
\n " + alias2(alias1(((stack1 = (depth0 != null ? lookupProperty(depth0,"schema_record") : depth0)) != null ? lookupProperty(stack1,"mimeType") : stack1), depth0)) + "
\n Created at:
\n " - + alias2((lookupProperty(helpers,"formatDate")||(depth0 && lookupProperty(depth0,"formatDate"))||alias4).call(alias3,((stack1 = (depth0 != null ? lookupProperty(depth0,"md_record") : depth0)) != null ? lookupProperty(stack1,"createdAt") : stack1),{"name":"formatDate","hash":{},"data":data,"loc":{"start":{"line":106,"column":41},"end":{"line":106,"column":75}}})) + + alias2((lookupProperty(helpers,"formatDate")||(depth0 && lookupProperty(depth0,"formatDate"))||alias4).call(alias3,((stack1 = (depth0 != null ? lookupProperty(depth0,"md_record") : depth0)) != null ? lookupProperty(stack1,"createdAt") : stack1),{"name":"formatDate","hash":{},"data":data,"loc":{"start":{"line":116,"column":41},"end":{"line":116,"column":75}}})) + "
\n Last Modified:
\n " - + alias2((lookupProperty(helpers,"formatDate")||(depth0 && lookupProperty(depth0,"formatDate"))||alias4).call(alias3,((stack1 = (depth0 != null ? lookupProperty(depth0,"md_record") : depth0)) != null ? lookupProperty(stack1,"lastUpdate") : stack1),{"name":"formatDate","hash":{},"data":data,"loc":{"start":{"line":108,"column":41},"end":{"line":108,"column":76}}})) + + alias2((lookupProperty(helpers,"formatDate")||(depth0 && lookupProperty(depth0,"formatDate"))||alias4).call(alias3,((stack1 = (depth0 != null ? lookupProperty(depth0,"md_record") : depth0)) != null ? lookupProperty(stack1,"lastUpdate") : stack1),{"name":"formatDate","hash":{},"data":data,"loc":{"start":{"line":118,"column":41},"end":{"line":118,"column":76}}})) + "
\n
\n
\n \n \n
\n
\n
\n\n"; },"useData":true}); })(); \ No newline at end of file diff --git a/metastore-landing-page.html b/metastore-landing-page.html index d26db9f..37849a1 100644 --- a/metastore-landing-page.html +++ b/metastore-landing-page.html @@ -114,12 +114,13 @@

}*/ let schemaId = "schema"; + let schemaIdWithVersion = "schema"; let headers = { Accept: "application/vnd.datamanager.metadata-record+json" }; let metadataUrl = ajaxURL + "metadata/" + pid + (version? ("?version=" +version):""); - + let fileName = pid + (version? ("_version" + version):""); $.ajax({ type: "GET", url: metadataUrl, @@ -144,6 +145,7 @@

success: function (schema_result) { metadata.schema_record = schema_result; schemaId = schema_result.schemaId; + schemaIdWithVersion = schemaId + (schema_result.schemaVersion ? ("_version" + schema_result.schemaVersion):""); if(schema_result.type === "JSON"){ //use JSON @@ -176,7 +178,10 @@

//attach handlers $("#download_json").click(function (e) { - // downloadJson(result.id); + downloadJson(metadataUrl, fileName); + }); + $("#download_schema").click(function (e) { + downloadJson(schemaUrl, schemaIdWithVersion); }); $("#download_zip").click(function (e) { // downloadZip(result.id); @@ -227,7 +232,7 @@

'

'; } - function downloadJson(id){ + function downloadJson(metadataUrl, id){ new Promise(function (resolve, reject) { let headers = {}; @@ -237,19 +242,19 @@

$.ajax({ type: "GET", - url: ajaxBaseUrl + "dataresources/" + id, + url: metadataUrl, contentType: "application/json", headers: headers, success: function (output, status, xhr) { resolve(output); }, error: function (result) { - let message = "Failed to obtain data resource " + ajaxBaseUrl + "dataresources/" + id + ". (HTTP " + result.status + ")"; + let message = "Failed to obtain data resource " + metadataUrl + ". (HTTP " + result.status + ")"; reject(message); } }); }).then(success => { - download(JSON.stringify(success, null, 3),"metadata.json", "application/json"); + download(JSON.stringify(success, null, 3),id, "application/json"); }, error => { addMessage(1, error); }); From 735269c0fcec47e74b1ba7e4cb0388fe279b99c7 Mon Sep 17 00:00:00 2001 From: Volker Hartmann Date: Wed, 10 Apr 2024 13:44:50 +0200 Subject: [PATCH 36/40] Restore default settings --- index.html | 2 +- settings/elastic-search-metastore.settings.js | 2 +- settings/metastore.settings.js | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/index.html b/index.html index 91eedca..2f4b3a5 100644 --- a/index.html +++ b/index.html @@ -2,7 +2,7 @@ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> - + diff --git a/settings/elastic-search-metastore.settings.js b/settings/elastic-search-metastore.settings.js index 43b0ba5..acc179b 100644 --- a/settings/elastic-search-metastore.settings.js +++ b/settings/elastic-search-metastore.settings.js @@ -1,5 +1,5 @@ //The backend service URL for the MetaStore instance used by the frontend. -export const ajaxBaseUrl = "http://metastore.docker:8040/metastore/api/v1/"; +export const ajaxBaseUrl = "http://localhost:8041/api/v1/"; //export const ajaxBaseUrl = "https://demo.datamanager.kit.edu:8443/metastore/api/v1/"; //The app description used to customize the frontend, e.g., for a specific project with a custom title and subtitle. diff --git a/settings/metastore.settings.js b/settings/metastore.settings.js index b3fffcb..000b6b6 100644 --- a/settings/metastore.settings.js +++ b/settings/metastore.settings.js @@ -1,5 +1,5 @@ //The backend service URL for the MetaStore instance used by the frontend. -export const ajaxBaseUrl = "http://metastore.docker:8040/metastore/api/v1/"; +export const ajaxBaseUrl = "http://localhost:8041/api/v1/"; //export const ajaxBaseUrl = "https://demo.datamanager.kit.edu:8443/metastore/api/v1/"; //The app description used to customize the frontend, e.g., for a specific project with a custom title and subtitle. @@ -12,7 +12,7 @@ export const appDescription = { //Enable/disable the Elastic search functionality. The availability of the search depends on the configuration of //the configured MetaStore instance. If Elastic search is not configured for the underlying MetaStore, it should //also be disabled here. -export const searchEnabled = true; +export const searchEnabled = false; From b5c9fe5adee4155d5022f74e9ee5788d9094a98d Mon Sep 17 00:00:00 2001 From: Volker Hartmann Date: Wed, 10 Apr 2024 14:48:08 +0200 Subject: [PATCH 37/40] MetaStore: Add license URI to MetadataSchemaRecord. --- definitions/metastore/schemaRecordModel.js | 8 +++++++- definitions/metastore/schemaRecordUIDefinitionCreate.js | 1 + definitions/metastore/schemaRecordUIDefinitionRead.js | 4 ++++ definitions/metastore/schemaRecordUIDefinitionUpdate.js | 3 +++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/definitions/metastore/schemaRecordModel.js b/definitions/metastore/schemaRecordModel.js index 966ea52..a518e86 100644 --- a/definitions/metastore/schemaRecordModel.js +++ b/definitions/metastore/schemaRecordModel.js @@ -5,7 +5,7 @@ let model = { "properties": { "schemaId": { "type": "string", - "title": "Schema Record Identifier.", + "title": "Schema Record Identifier", "description": "A unique identifier for the schema" }, "schemaVersion": { @@ -82,6 +82,12 @@ let model = { } } }, + "licenseUri": { + "type": "string", + "title": "License Uri", + "description": "Direct access URI where the associated license is stored.", + "optional":true + }, "schemaDocumentUri": { "type": "string", "title": "Schema Document Uri", diff --git a/definitions/metastore/schemaRecordUIDefinitionCreate.js b/definitions/metastore/schemaRecordUIDefinitionCreate.js index b689ae2..c73c4f2 100644 --- a/definitions/metastore/schemaRecordUIDefinitionCreate.js +++ b/definitions/metastore/schemaRecordUIDefinitionCreate.js @@ -5,6 +5,7 @@ let uiDefinitionCreate= { "label", "definition", "comment", + "licenseUri", "type", { "type": "array", diff --git a/definitions/metastore/schemaRecordUIDefinitionRead.js b/definitions/metastore/schemaRecordUIDefinitionRead.js index d9c6e10..7605899 100644 --- a/definitions/metastore/schemaRecordUIDefinitionRead.js +++ b/definitions/metastore/schemaRecordUIDefinitionRead.js @@ -26,6 +26,10 @@ let uiDefinitionRead = { "type": "text", "readonly": true }, + { + "key": "licenseUri", + "readonly": true + }, { "key": "createdAt", "readonly": true diff --git a/definitions/metastore/schemaRecordUIDefinitionUpdate.js b/definitions/metastore/schemaRecordUIDefinitionUpdate.js index 97adaf5..c577e5e 100644 --- a/definitions/metastore/schemaRecordUIDefinitionUpdate.js +++ b/definitions/metastore/schemaRecordUIDefinitionUpdate.js @@ -14,6 +14,9 @@ let uiDefinitionUpdate= { { "key": "comment" }, + { + "key": "licenseUri" + }, { "key": "type", "type": "text", From 292abf9d1d107824591698ec5a0cadd92eca06c1 Mon Sep 17 00:00:00 2001 From: Volker Hartmann Date: Wed, 10 Apr 2024 15:06:32 +0200 Subject: [PATCH 38/40] MetaStore: Add license URI to MetadataDocumentRecord. --- definitions/metastore/metadataRecordModel.js | 6 ++++++ definitions/metastore/metadataRecordUIDefinitionCreate.js | 8 +++++++- definitions/metastore/metadataRecordUIDefinitionRead.js | 4 ++++ definitions/metastore/metadataRecordUIDefinitionUpdate.js | 5 +++-- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/definitions/metastore/metadataRecordModel.js b/definitions/metastore/metadataRecordModel.js index a4202b7..d140082 100644 --- a/definitions/metastore/metadataRecordModel.js +++ b/definitions/metastore/metadataRecordModel.js @@ -88,6 +88,12 @@ let model = { } } }, + "licenseUri": { + "type": "string", + "title": "License Uri", + "description": "Direct access URI where the associated license is stored.", + "optional":true + }, "metadataDocumentUri": { "type": "string", "title": "Metadata Document URI", diff --git a/definitions/metastore/metadataRecordUIDefinitionCreate.js b/definitions/metastore/metadataRecordUIDefinitionCreate.js index 192c51d..fbf57b9 100644 --- a/definitions/metastore/metadataRecordUIDefinitionCreate.js +++ b/definitions/metastore/metadataRecordUIDefinitionCreate.js @@ -47,7 +47,13 @@ let uiDefinitionCreate= { {"key":"acl[].permission"} ] } - },{ + }, + { + "key": "licenseUri", + "id": "licenseUri", + "type": "text" + }, + { "key": "metadataDocument", "id": "metadataDocument", "type": "file" diff --git a/definitions/metastore/metadataRecordUIDefinitionRead.js b/definitions/metastore/metadataRecordUIDefinitionRead.js index 7dc65e3..eccea36 100644 --- a/definitions/metastore/metadataRecordUIDefinitionRead.js +++ b/definitions/metastore/metadataRecordUIDefinitionRead.js @@ -46,6 +46,10 @@ let uiDefinitionRead = { ] } }, + { + "key": "licenseUri", + "readonly": true + }, { "key": "metadataDocumentUri", "readonly": true diff --git a/definitions/metastore/metadataRecordUIDefinitionUpdate.js b/definitions/metastore/metadataRecordUIDefinitionUpdate.js index e1a60da..95cd5b7 100644 --- a/definitions/metastore/metadataRecordUIDefinitionUpdate.js +++ b/definitions/metastore/metadataRecordUIDefinitionUpdate.js @@ -8,13 +8,11 @@ let uiDefinitionUpdate= { { "title": "Related Resource Identifier", "key": "relatedResource.identifier", - "readonly": true }, { "title": "Related Resource Identifier Type", "key": "relatedResource.identifierType", "type": "text", - "readonly": true }, { "title": "Schema Identifier", @@ -51,6 +49,9 @@ let uiDefinitionUpdate= { ] } }, + { + "key": "licenseUri" + }, { "key": "metadataDocumentUri", "readonly": true From 3b632f9576f74c9fb136d8e56a251f955d1b7251 Mon Sep 17 00:00:00 2001 From: Thomas Jejkal Date: Thu, 18 Apr 2024 12:34:35 +0200 Subject: [PATCH 39/40] Update FDO.js Fixed issue with data type mapping --- js/FDO.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/FDO.js b/js/FDO.js index e9d0b82..0bbae1d 100644 --- a/js/FDO.js +++ b/js/FDO.js @@ -93,7 +93,7 @@ class FDO{ //check if attribute value is a digitalObjectType label if (labelMap.indexOf(formOutputObject[keys[i]]) >= 0) { //We have a type label, set final record value to PID for digitalObjectType label - result.addProperty(pid, known_types.slice(labelMap.indexOf(formOutputObject[keys[i]]), 1).at(0)['pid']); + result.addProperty(pid, known_types.slice(labelMap.indexOf(formOutputObject[keys[i]])).at(0)['pid']); } else { //check for checksum if (pid == '21.T11148/82e2503c49209e987740') { From 63815622b98bb72c4045b22040c8ddc08a2123b7 Mon Sep 17 00:00:00 2001 From: Thomas Jejkal Date: Thu, 25 Apr 2024 07:12:27 +0200 Subject: [PATCH 40/40] Fixed minor issues in FDO builder --- definitions/base-repo/models/contentModel.js | 68 +++++++++ definitions/base-repo/models/resourceModel.js | 2 - definitions/base-repo/resourceModel.js | 62 ++------- elastic-search-base-repo.html | 3 +- js/FDO.js | 19 ++- repo-management_new.html | 19 ++- search.html | 131 ------------------ 7 files changed, 107 insertions(+), 197 deletions(-) create mode 100644 definitions/base-repo/models/contentModel.js delete mode 100644 search.html diff --git a/definitions/base-repo/models/contentModel.js b/definitions/base-repo/models/contentModel.js new file mode 100644 index 0000000..aebc1dc --- /dev/null +++ b/definitions/base-repo/models/contentModel.js @@ -0,0 +1,68 @@ +let contentModel = { + "$schema": "https://json-schema.org/draft/2019-09/schema", + "type": "object", + "headerTemplate": "Data Resource {{#if self.id}} #{{ self.id }} {{else}} (New) {{/if}}", + "required": [ + "relativePath" + ], + "format": "categories", + "properties": { + "id": { + "type": "integer", + "readOnly": true, + "options": { + "hidden": true + } + }, + "parentResource": { + "type": "object", + "properties": { + "id": { + "type": "string" + } + }, + "readOnly": true, + "options": { + "hidden": true, + "visible": false + } + }, + "relativePath": { + "type": "string" + }, + "version": { + "type": "integer", + "readOnly": true + }, + "fileVersion": { + "type": "string", + "readOnly": true + }, + "versioningService": { + "type": "string", + "readOnly": true + }, + "uploader": { + "type": "string" + }, + "mediaType": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "size": { + "type": "integer" + }, + "metadata": { + "type": "object" + }, + "tags": { + "type": "array", + "items": {} + }, + "filename": { + "type": "string" + } + } +} diff --git a/definitions/base-repo/models/resourceModel.js b/definitions/base-repo/models/resourceModel.js index 92d33be..6e4b834 100644 --- a/definitions/base-repo/models/resourceModel.js +++ b/definitions/base-repo/models/resourceModel.js @@ -299,8 +299,6 @@ let model = { "$ref": "definitions/base-repo/models/subject.json" } }, - - "geoLocationsAsString": { "type": "string", "options":{ diff --git a/definitions/base-repo/resourceModel.js b/definitions/base-repo/resourceModel.js index 08ac49b..5046438 100644 --- a/definitions/base-repo/resourceModel.js +++ b/definitions/base-repo/resourceModel.js @@ -279,41 +279,23 @@ let model = { } }, "type": "object", - "required":[ - "titles", "publisher", "publicationYear", "resourceType" - ], "properties": { "acls": { "type": "array", - "title": "Access Control Information", - "required":true, "items": { "type": "object", - "headerTemplate": "{{self.sid}}", "properties": { "id": { - "type": "integer", - "readOnly":true + "type": "integer" }, "permission": { "type": "string", - "propertyOrder":2, "enum": ["NONE", "READ", "WRITE", "ADMINISTRATE"] }, "sid": { - "type": "string", - "format": "autocomplete", - "propertyOrder":1, - "options": { - "autocomplete": { - "search": "search_keycloak", - "getResultValue": "getResultValue_keycloak", - "renderResult": "renderResult_keycloak" - } - } + "type": "string" } - }, - "required":["sid", "permission"] + } } }, "alternateIdentifiers": { @@ -529,17 +511,7 @@ let model = { }, "publicationYear": { "type": "string", - "options": { - "inputAttributes": { - "placeholder": "YYYY" - }, - "cleave": { - "date": true, - "datePattern": ['Y'], - } - - } - //"pattern":"^(19|20)\\d{2}$" + "pattern":"^(19|20)\\d{2}$" }, "publisher": { "type": "string" @@ -573,8 +545,6 @@ let model = { }, "resourceType": { "type": "object", - "propertyOrder":2, - "required":["typeGeneral", "value"], "properties": { "id": { "type": "integer" @@ -631,40 +601,24 @@ let model = { "titles": { "type": "array", "minItems": 1, - "propertyOrder":1, "items": { "type": "object", - "title": "Title", "properties": { "id": { - "type": "integer", - "readOnly":true, - "propertyOrder":1, + "type": "integer" }, "lang": { - "$ref": "#/$defs/LANG", - "propertyOrder":4 + "$ref": "#/$defs/LANG" }, "titleType": { "type": "string", - "title": "Type", - "propertyOrder":2, "allowEmpty": false, - "enum": ["ALTERNATIVE_TITLE", "SUBTITLE", "TRANSLATED_TITLE", "OTHER", ""], - "options": { - "enum_titles": [ - "Title 1","Title 2","Title 3", "Title 4", "None" - ] - } + "enum": ["ALTERNATIVE_TITLE", "SUBTITLE", "TRANSLATED_TITLE", "OTHER", ""] }, "value": { "type": "string", - "title":"Value", - "propertyOrder":3 - } - }, - "required":["value"] + } } } } diff --git a/elastic-search-base-repo.html b/elastic-search-base-repo.html index 9ba1392..7c530a1 100644 --- a/elastic-search-base-repo.html +++ b/elastic-search-base-repo.html @@ -347,7 +347,7 @@

//initialize dropdown fields $('.ui.dropdown').dropdown(); - ajaxURL = ajaxBaseUrl + "search/"; + ajaxURL = ajaxBaseUrl + "search"; $('#search-base-url').val(ajaxBaseUrl); config.ajaxBaseUrl = ajaxBaseUrl; @@ -480,7 +480,6 @@

if (config.token != null) { headers["Authorization"] = "Bearer " + config.token; } - $.ajax({ type: "POST", url: ajaxURL, diff --git a/js/FDO.js b/js/FDO.js index 0bbae1d..6c2b901 100644 --- a/js/FDO.js +++ b/js/FDO.js @@ -21,8 +21,14 @@ class FDO{ return this.customName; } - addProperty(key, value){ - this.properties.push({"key": key, "value": value}); + addProperty(key, value, isArray){ + if(isArray && Array.isArray(value)){ + for(let elem of value){ + this.properties.push({"key": key, "value": elem}); + } + }else{ + this.properties.push({"key": key, "value": value}); + } } removeProperty(idx){ @@ -90,10 +96,11 @@ class FDO{ for (let i = 0; i < keys.length; i++) { //obtain PID from schema let pid = model['properties'][keys[i]]['pid']; + let isArray = model['properties'][keys[i]]['type'] === "array"; //check if attribute value is a digitalObjectType label if (labelMap.indexOf(formOutputObject[keys[i]]) >= 0) { //We have a type label, set final record value to PID for digitalObjectType label - result.addProperty(pid, known_types.slice(labelMap.indexOf(formOutputObject[keys[i]])).at(0)['pid']); + result.addProperty(pid, known_types.slice(labelMap.indexOf(formOutputObject[keys[i]])).at(0)['pid'], false); } else { //check for checksum if (pid == '21.T11148/82e2503c49209e987740') { @@ -112,14 +119,14 @@ class FDO{ } let checksumRecordValue = {}; checksumRecordValue[checksumAlg + "sum"] = checksumValue; - result.addProperty(pid, checksumRecordValue); + result.addProperty(pid, checksumRecordValue, isArray); }else if(pid == '21.T11148/b415e16fbe4ca40f2270'){ //topic - result.addProperty(pid, formOutputObject[keys[i]]); + result.addProperty(pid, formOutputObject[keys[i]], isArray); } else { //we have another attribute value, check if valid and set if true if (formOutputObject[keys[i]]) { - result.addProperty(pid, formOutputObject[keys[i]]); + result.addProperty(pid, formOutputObject[keys[i]], isArray); } } } diff --git a/repo-management_new.html b/repo-management_new.html index 4f77f0b..aa793c8 100644 --- a/repo-management_new.html +++ b/repo-management_new.html @@ -20,7 +20,6 @@ - +
-
+
+ +
+