diff --git a/config/config.example.yml b/config/config.example.yml index 3b46b8403f..099bea2614 100644 --- a/config/config.example.yml +++ b/config/config.example.yml @@ -23,6 +23,16 @@ ssr: # Determining which styles are critical is a relatively expensive operation; this option is # disabled (false) by default to boost server performance at the expense of loading smoothness. inlineCriticalCss: false + # Path prefixes to enable SSR for. By default these are limited to paths of primary DSpace objects. + paths: [ '/home', '/items/', '/entities/', '/collections/', '/communities/', '/bitstream/', '/bitstreams/', '/handle/' ] + # Whether to enable rendering of Search component on SSR. + # If set to true the component will be included in the HTML returned from the server side rendering. + # If set to false the component will not be included in the HTML returned from the server side rendering. + enableSearchComponent: false, + # Whether to enable rendering of Browse component on SSR. + # If set to true the component will be included in the HTML returned from the server side rendering. + # If set to false the component will not be included in the HTML returned from the server side rendering. + enableBrowseComponent: false, # The REST API server settings # NOTE: these settings define which (publicly available) REST API to use. They are usually @@ -448,6 +458,12 @@ search: enabled: false # List of filters to enable in "Advanced Search" dropdown filter: [ 'title', 'author', 'subject', 'entityType' ] + # + # Number used to render n UI elements called loading skeletons that act as placeholders. + # These elements indicate that some content will be loaded in their stead. + # Since we don't know how many filters will be loaded before we receive a response from the server we use this parameter for the skeletons count. + # e.g. If we set 5 then 5 loading skeletons will be visualized before the actual filters are retrieved. + defaultFiltersCount: 5 # Notify metrics diff --git a/cypress/e2e/admin-add-new-modals.cy.ts b/cypress/e2e/admin-add-new-modals.cy.ts index 5c40f77eca..e2ade53488 100644 --- a/cypress/e2e/admin-add-new-modals.cy.ts +++ b/cypress/e2e/admin-add-new-modals.cy.ts @@ -9,6 +9,7 @@ describe('Admin Add New Modals', () => { it('Add new Community modal should pass accessibility tests', () => { // Pin the sidebar open + cy.get('[data-test="sidebar-collapse-toggle"]').trigger('mouseover'); cy.get('[data-test="sidebar-collapse-toggle"]').click(); // Click on entry of menu @@ -23,6 +24,7 @@ describe('Admin Add New Modals', () => { it('Add new Collection modal should pass accessibility tests', () => { // Pin the sidebar open + cy.get('[data-test="sidebar-collapse-toggle"]').trigger('mouseover'); cy.get('[data-test="sidebar-collapse-toggle"]').click(); // Click on entry of menu @@ -37,6 +39,7 @@ describe('Admin Add New Modals', () => { it('Add new Item modal should pass accessibility tests', () => { // Pin the sidebar open + cy.get('[data-test="sidebar-collapse-toggle"]').trigger('mouseover'); cy.get('[data-test="sidebar-collapse-toggle"]').click(); // Click on entry of menu diff --git a/cypress/e2e/admin-edit-modals.cy.ts b/cypress/e2e/admin-edit-modals.cy.ts index fd28a8247c..d4e2438061 100644 --- a/cypress/e2e/admin-edit-modals.cy.ts +++ b/cypress/e2e/admin-edit-modals.cy.ts @@ -9,6 +9,7 @@ describe('Admin Edit Modals', () => { it('Edit Community modal should pass accessibility tests', () => { // Pin the sidebar open + cy.get('[data-test="sidebar-collapse-toggle"]').trigger('mouseover'); cy.get('[data-test="sidebar-collapse-toggle"]').click(); // Click on entry of menu @@ -23,6 +24,7 @@ describe('Admin Edit Modals', () => { it('Edit Collection modal should pass accessibility tests', () => { // Pin the sidebar open + cy.get('[data-test="sidebar-collapse-toggle"]').trigger('mouseover'); cy.get('[data-test="sidebar-collapse-toggle"]').click(); // Click on entry of menu @@ -37,6 +39,7 @@ describe('Admin Edit Modals', () => { it('Edit Item modal should pass accessibility tests', () => { // Pin the sidebar open + cy.get('[data-test="sidebar-collapse-toggle"]').trigger('mouseover'); cy.get('[data-test="sidebar-collapse-toggle"]').click(); // Click on entry of menu diff --git a/cypress/e2e/admin-export-modals.cy.ts b/cypress/e2e/admin-export-modals.cy.ts index d0a48cac23..873d16535f 100644 --- a/cypress/e2e/admin-export-modals.cy.ts +++ b/cypress/e2e/admin-export-modals.cy.ts @@ -9,6 +9,7 @@ describe('Admin Export Modals', () => { it('Export metadata modal should pass accessibility tests', () => { // Pin the sidebar open + cy.get('[data-test="sidebar-collapse-toggle"]').trigger('mouseover'); cy.get('[data-test="sidebar-collapse-toggle"]').click(); // Click on entry of menu @@ -23,6 +24,7 @@ describe('Admin Export Modals', () => { it('Export batch modal should pass accessibility tests', () => { // Pin the sidebar open + cy.get('[data-test="sidebar-collapse-toggle"]').trigger('mouseover'); cy.get('[data-test="sidebar-collapse-toggle"]').click(); // Click on entry of menu diff --git a/package-lock.json b/package-lock.json index 38de5e278f..cc36f5f080 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,22 +39,22 @@ "colors": "^1.4.0", "compression": "^1.7.5", "cookie-parser": "1.4.7", - "core-js": "^3.39.0", + "core-js": "^3.40.0", "date-fns": "^2.29.3", "date-fns-tz": "^1.3.7", "deepmerge": "^4.3.1", "ejs": "^3.1.10", - "express": "^4.21.1", + "express": "^4.21.2", "express-rate-limit": "^5.1.3", "fast-json-patch": "^3.1.1", "filesize": "^6.1.0", "http-proxy-middleware": "^2.0.7", "http-terminator": "^3.2.0", - "isbot": "^5.1.17", + "isbot": "^5.1.21", "js-cookie": "2.2.1", "js-yaml": "^4.1.0", "json5": "^2.2.3", - "jsonschema": "1.4.1", + "jsonschema": "1.5.0", "jwt-decode": "^3.1.2", "lodash": "^4.17.21", "lru-cache": "^7.14.1", @@ -67,6 +67,7 @@ "ng2-nouislider": "^2.0.0", "ngx-infinite-scroll": "^16.0.0", "ngx-pagination": "6.0.3", + "ngx-skeleton-loader": "^9.0.0", "ngx-ui-switch": "^14.1.0", "nouislider": "^15.7.1", "orejime": "^2.3.1", @@ -99,7 +100,7 @@ "@types/grecaptcha": "^3.0.9", "@types/jasmine": "~3.6.0", "@types/js-cookie": "2.2.6", - "@types/lodash": "^4.17.13", + "@types/lodash": "^4.17.14", "@types/node": "^14.14.9", "@typescript-eslint/eslint-plugin": "^7.18.0", "@typescript-eslint/parser": "^7.18.0", @@ -134,20 +135,20 @@ "karma-jasmine": "~4.0.0", "karma-jasmine-html-reporter": "^1.5.0", "karma-mocha-reporter": "2.2.5", - "ng-mocks": "^14.13.1", + "ng-mocks": "^14.13.2", "ngx-mask": "14.2.4", "nodemon": "^2.0.22", - "postcss": "^8.4", + "postcss": "^8.5", "postcss-import": "^14.0.0", "postcss-loader": "^4.0.3", "postcss-preset-env": "^7.4.2", "rimraf": "^3.0.2", - "sass": "~1.83.1", + "sass": "~1.83.4", "sass-loader": "^12.6.0", "sass-resources-loader": "^2.2.5", "ts-node": "^8.10.2", "typescript": "~5.4.5", - "webpack": "5.96.1", + "webpack": "5.97.1", "webpack-cli": "^5.1.4", "webpack-dev-server": "^4.15.1" } @@ -6897,9 +6898,9 @@ "dev": true }, "node_modules/@types/lodash": { - "version": "4.17.13", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.13.tgz", - "integrity": "sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg==", + "version": "4.17.14", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.14.tgz", + "integrity": "sha512-jsxagdikDiDBeIRaPYtArcT8my4tN1og7MtMRquFT3XNA6axxyHDRUemqDz/taRDdOUn0GnGHRCuff4q48sW9A==", "dev": true }, "node_modules/@types/mime": { @@ -7587,148 +7588,148 @@ "dev": true }, "node_modules/@webassemblyjs/ast": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", - "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", "dev": true, "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" } }, "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", - "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", "dev": true }, "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", - "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", "dev": true }, "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", - "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", "dev": true }, "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", - "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", "dev": true, "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", - "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", "dev": true }, "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", - "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/wasm-gen": "1.12.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" } }, "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", - "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", "dev": true, "dependencies": { "@xtuc/ieee754": "^1.2.0" } }, "node_modules/@webassemblyjs/leb128": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", - "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", "dev": true, "dependencies": { "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/utf8": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", - "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", "dev": true }, "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", - "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/helper-wasm-section": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-opt": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1", - "@webassemblyjs/wast-printer": "1.12.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" } }, "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", - "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" } }, "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", - "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" } }, "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", - "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-api-error": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" } }, "node_modules/@webassemblyjs/wast-printer": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", - "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/ast": "1.14.1", "@xtuc/long": "4.2.2" } }, @@ -9920,9 +9921,9 @@ } }, "node_modules/core-js": { - "version": "3.39.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.39.0.tgz", - "integrity": "sha512-raM0ew0/jJUqkJ0E6e8UDtl+y/7ktFivgWvqw8dNSQeNWoSDLvQ1H/RN3aPXB9tBd4/FhyR4RDPGhsNIMsAn7g==", + "version": "3.40.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.40.0.tgz", + "integrity": "sha512-7vsMc/Lty6AGnn7uFpYT56QesI5D2Y/UkgKounk87OP9Z2H9Z8kj6jzcSGAxFmUtDOS0ntK6lbQz+Nsa0Jj6mQ==", "hasInstallScript": true, "funding": { "type": "opencollective", @@ -12486,9 +12487,9 @@ "dev": true }, "node_modules/express": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", - "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", @@ -12509,7 +12510,7 @@ "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.10", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", @@ -12524,6 +12525,10 @@ }, "engines": { "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/express-rate-limit": { @@ -14474,9 +14479,9 @@ } }, "node_modules/isbot": { - "version": "5.1.17", - "resolved": "https://registry.npmjs.org/isbot/-/isbot-5.1.17.tgz", - "integrity": "sha512-/wch8pRKZE+aoVhRX/hYPY1C7dMCeeMyhkQLNLNlYAbGQn9bkvMB8fOUXNnk5I0m4vDYbBJ9ciVtkr9zfBJ7qA==", + "version": "5.1.21", + "resolved": "https://registry.npmjs.org/isbot/-/isbot-5.1.21.tgz", + "integrity": "sha512-0q3naRVpENL0ReKHeNcwn/G7BDynp0DqZUckKyFtM9+hmpnPqgm8+8wbjiVZ0XNhq1wPQV28/Pb8Snh5adeUHA==", "engines": { "node": ">=18" } @@ -15016,9 +15021,9 @@ ] }, "node_modules/jsonschema": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz", - "integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.5.0.tgz", + "integrity": "sha512-K+A9hhqbn0f3pJX17Q/7H6yQfD/5OXgdrR5UE12gMXCiN9D5Xq2o5mddV2QEcX/bjla99ASsAAQUyMCCRWAEhw==", "engines": { "node": "*" } @@ -16798,9 +16803,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", "funding": [ { "type": "github", @@ -16865,18 +16870,18 @@ "dev": true }, "node_modules/ng-mocks": { - "version": "14.13.1", - "resolved": "https://registry.npmjs.org/ng-mocks/-/ng-mocks-14.13.1.tgz", - "integrity": "sha512-eyfnjXeC108SqVD09i/cBwCpKkK0JjBoAg8jp7oQS2HS081K3WJTttFpgLGeLDYKmZsZ6nYpI+HHNQ3OksaJ7A==", + "version": "14.13.2", + "resolved": "https://registry.npmjs.org/ng-mocks/-/ng-mocks-14.13.2.tgz", + "integrity": "sha512-ItAB72Pc0uznL1j4TPsFp1wehhitVp7DARkc67aafeIk1FDgwnAZvzJwntMnIp/IWMSbzrEQ6kl3cc5euX1NRA==", "dev": true, "funding": { "url": "https://github.com/sponsors/help-me-mom" }, "peerDependencies": { - "@angular/common": "5.0.0-alpha - 5 || 6.0.0-alpha - 6 || 7.0.0-alpha - 7 || 8.0.0-alpha - 8 || 9.0.0-alpha - 9 || 10.0.0-alpha - 10 || 11.0.0-alpha - 11 || 12.0.0-alpha - 12 || 13.0.0-alpha - 13 || 14.0.0-alpha - 14 || 15.0.0-alpha - 15 || 16.0.0-alpha - 16 || 17.0.0-alpha - 17 || 18.0.0-alpha - 18", - "@angular/core": "5.0.0-alpha - 5 || 6.0.0-alpha - 6 || 7.0.0-alpha - 7 || 8.0.0-alpha - 8 || 9.0.0-alpha - 9 || 10.0.0-alpha - 10 || 11.0.0-alpha - 11 || 12.0.0-alpha - 12 || 13.0.0-alpha - 13 || 14.0.0-alpha - 14 || 15.0.0-alpha - 15 || 16.0.0-alpha - 16 || 17.0.0-alpha - 17 || 18.0.0-alpha - 18", - "@angular/forms": "5.0.0-alpha - 5 || 6.0.0-alpha - 6 || 7.0.0-alpha - 7 || 8.0.0-alpha - 8 || 9.0.0-alpha - 9 || 10.0.0-alpha - 10 || 11.0.0-alpha - 11 || 12.0.0-alpha - 12 || 13.0.0-alpha - 13 || 14.0.0-alpha - 14 || 15.0.0-alpha - 15 || 16.0.0-alpha - 16 || 17.0.0-alpha - 17 || 18.0.0-alpha - 18", - "@angular/platform-browser": "5.0.0-alpha - 5 || 6.0.0-alpha - 6 || 7.0.0-alpha - 7 || 8.0.0-alpha - 8 || 9.0.0-alpha - 9 || 10.0.0-alpha - 10 || 11.0.0-alpha - 11 || 12.0.0-alpha - 12 || 13.0.0-alpha - 13 || 14.0.0-alpha - 14 || 15.0.0-alpha - 15 || 16.0.0-alpha - 16 || 17.0.0-alpha - 17 || 18.0.0-alpha - 18" + "@angular/common": "5.0.0-alpha - 5 || 6.0.0-alpha - 6 || 7.0.0-alpha - 7 || 8.0.0-alpha - 8 || 9.0.0-alpha - 9 || 10.0.0-alpha - 10 || 11.0.0-alpha - 11 || 12.0.0-alpha - 12 || 13.0.0-alpha - 13 || 14.0.0-alpha - 14 || 15.0.0-alpha - 15 || 16.0.0-alpha - 16 || 17.0.0-alpha - 17 || 18.0.0-alpha - 18 || 19.0.0-alpha - 19", + "@angular/core": "5.0.0-alpha - 5 || 6.0.0-alpha - 6 || 7.0.0-alpha - 7 || 8.0.0-alpha - 8 || 9.0.0-alpha - 9 || 10.0.0-alpha - 10 || 11.0.0-alpha - 11 || 12.0.0-alpha - 12 || 13.0.0-alpha - 13 || 14.0.0-alpha - 14 || 15.0.0-alpha - 15 || 16.0.0-alpha - 16 || 17.0.0-alpha - 17 || 18.0.0-alpha - 18 || 19.0.0-alpha - 19", + "@angular/forms": "5.0.0-alpha - 5 || 6.0.0-alpha - 6 || 7.0.0-alpha - 7 || 8.0.0-alpha - 8 || 9.0.0-alpha - 9 || 10.0.0-alpha - 10 || 11.0.0-alpha - 11 || 12.0.0-alpha - 12 || 13.0.0-alpha - 13 || 14.0.0-alpha - 14 || 15.0.0-alpha - 15 || 16.0.0-alpha - 16 || 17.0.0-alpha - 17 || 18.0.0-alpha - 18 || 19.0.0-alpha - 19", + "@angular/platform-browser": "5.0.0-alpha - 5 || 6.0.0-alpha - 6 || 7.0.0-alpha - 7 || 8.0.0-alpha - 8 || 9.0.0-alpha - 9 || 10.0.0-alpha - 10 || 11.0.0-alpha - 11 || 12.0.0-alpha - 12 || 13.0.0-alpha - 13 || 14.0.0-alpha - 14 || 15.0.0-alpha - 15 || 16.0.0-alpha - 16 || 17.0.0-alpha - 17 || 18.0.0-alpha - 18 || 19.0.0-alpha - 19" } }, "node_modules/ng2-file-upload": { @@ -16941,6 +16946,19 @@ "@angular/core": ">=13.0.0" } }, + "node_modules/ngx-skeleton-loader": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/ngx-skeleton-loader/-/ngx-skeleton-loader-9.0.0.tgz", + "integrity": "sha512-aO4/V6oGdZGNcTjasTg/fwzJJYl/ZmNKgCukOEQdUK3GSFOZtB/3GGULMJuZ939hk3Hzqh1OBiLfIM1SqTfhqg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/common": ">=16.0.0", + "@angular/core": ">=16.0.0" + } + }, "node_modules/ngx-ui-switch": { "version": "14.1.0", "resolved": "https://registry.npmjs.org/ngx-ui-switch/-/ngx-ui-switch-14.1.0.tgz", @@ -18188,9 +18206,9 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", - "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" }, "node_modules/path-type": { "version": "4.0.0", @@ -18408,9 +18426,9 @@ } }, "node_modules/postcss": { - "version": "8.4.49", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", - "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz", + "integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==", "funding": [ { "type": "opencollective", @@ -18426,7 +18444,7 @@ } ], "dependencies": { - "nanoid": "^3.3.7", + "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -20477,10 +20495,11 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/sass": { - "version": "1.83.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.83.1.tgz", - "integrity": "sha512-EVJbDaEs4Rr3F0glJzFSOvtg2/oy2V/YrGFPqPY24UqcLDWcI9ZY5sN+qyO3c/QCZwzgfirvhXvINiJCE/OLcA==", + "version": "1.83.4", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.83.4.tgz", + "integrity": "sha512-B1bozCeNQiOgDcLd33e2Cs2U60wZwjUUXzh900ZyQF5qUasvMdDZYbQ566LJu7cqR+sAHlAfO6RMkaID5s6qpA==", "dev": true, + "license": "MIT", "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", @@ -22624,16 +22643,16 @@ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "node_modules/webpack": { - "version": "5.96.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.96.1.tgz", - "integrity": "sha512-l2LlBSvVZGhL4ZrPwyr8+37AunkcYj5qh8o6u2/2rzoPc8gxFJkLj1WxNgooi9pnoc06jh0BjuXnamM4qlujZA==", + "version": "5.97.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.97.1.tgz", + "integrity": "sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.6", - "@webassemblyjs/ast": "^1.12.1", - "@webassemblyjs/wasm-edit": "^1.12.1", - "@webassemblyjs/wasm-parser": "^1.12.1", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", "acorn": "^8.14.0", "browserslist": "^4.24.0", "chrome-trace-event": "^1.0.2", diff --git a/package.json b/package.json index ad69993dbe..e282145850 100644 --- a/package.json +++ b/package.json @@ -126,22 +126,22 @@ "colors": "^1.4.0", "compression": "^1.7.5", "cookie-parser": "1.4.7", - "core-js": "^3.39.0", + "core-js": "^3.40.0", "date-fns": "^2.29.3", "date-fns-tz": "^1.3.7", "deepmerge": "^4.3.1", "ejs": "^3.1.10", - "express": "^4.21.1", + "express": "^4.21.2", "express-rate-limit": "^5.1.3", "fast-json-patch": "^3.1.1", "filesize": "^6.1.0", "http-proxy-middleware": "^2.0.7", "http-terminator": "^3.2.0", - "isbot": "^5.1.17", + "isbot": "^5.1.21", "js-cookie": "2.2.1", "js-yaml": "^4.1.0", "json5": "^2.2.3", - "jsonschema": "1.4.1", + "jsonschema": "1.5.0", "jwt-decode": "^3.1.2", "lodash": "^4.17.21", "lru-cache": "^7.14.1", @@ -154,6 +154,7 @@ "ng2-nouislider": "^2.0.0", "ngx-infinite-scroll": "^16.0.0", "ngx-pagination": "6.0.3", + "ngx-skeleton-loader": "^9.0.0", "ngx-ui-switch": "^14.1.0", "nouislider": "^15.7.1", "orejime": "^2.3.1", @@ -186,7 +187,7 @@ "@types/grecaptcha": "^3.0.9", "@types/jasmine": "~3.6.0", "@types/js-cookie": "2.2.6", - "@types/lodash": "^4.17.13", + "@types/lodash": "^4.17.14", "@types/node": "^14.14.9", "@typescript-eslint/eslint-plugin": "^7.18.0", "@typescript-eslint/parser": "^7.18.0", @@ -221,20 +222,20 @@ "karma-jasmine": "~4.0.0", "karma-jasmine-html-reporter": "^1.5.0", "karma-mocha-reporter": "2.2.5", - "ng-mocks": "^14.13.1", + "ng-mocks": "^14.13.2", "ngx-mask": "14.2.4", "nodemon": "^2.0.22", - "postcss": "^8.4", + "postcss": "^8.5", "postcss-import": "^14.0.0", "postcss-loader": "^4.0.3", "postcss-preset-env": "^7.4.2", "rimraf": "^3.0.2", - "sass": "~1.83.1", + "sass": "~1.83.4", "sass-loader": "^12.6.0", "sass-resources-loader": "^2.2.5", "ts-node": "^8.10.2", "typescript": "~5.4.5", - "webpack": "5.96.1", + "webpack": "5.97.1", "webpack-cli": "^5.1.4", "webpack-dev-server": "^4.15.1" } diff --git a/server.ts b/server.ts index 07a05656d8..1276621e9d 100644 --- a/server.ts +++ b/server.ts @@ -218,7 +218,7 @@ export function app() { * The callback function to serve server side angular */ function ngApp(req, res, next) { - if (environment.ssr.enabled) { + if (environment.ssr.enabled && req.method === 'GET' && (req.path === '/' || environment.ssr.paths.some(pathPrefix => req.path.startsWith(pathPrefix)))) { // Render the page to user via SSR (server side rendering) serverSideRender(req, res, next); } else { diff --git a/src/app/bitstream-page/edit-bitstream-page/edit-bitstream-page.component.html b/src/app/bitstream-page/edit-bitstream-page/edit-bitstream-page.component.html index f7d2c60832..259ab599cb 100644 --- a/src/app/bitstream-page/edit-bitstream-page/edit-bitstream-page.component.html +++ b/src/app/bitstream-page/edit-bitstream-page/edit-bitstream-page.component.html @@ -1,6 +1,6 @@ -
-
+
+
@@ -27,7 +27,7 @@
-
diff --git a/src/app/bitstream-page/edit-bitstream-page/edit-bitstream-page.component.spec.ts b/src/app/bitstream-page/edit-bitstream-page/edit-bitstream-page.component.spec.ts index 9243a36491..7da9e040ce 100644 --- a/src/app/bitstream-page/edit-bitstream-page/edit-bitstream-page.component.spec.ts +++ b/src/app/bitstream-page/edit-bitstream-page/edit-bitstream-page.component.spec.ts @@ -261,7 +261,7 @@ describe('EditBitstreamPageComponent', () => { }); it('should select the correct format', () => { - expect(rawForm.formatContainer.selectedFormat).toEqual(selectedFormat.id); + expect(rawForm.formatContainer.selectedFormat).toEqual(selectedFormat.shortDescription); }); it('should put the \"New Format\" input on invisible', () => { @@ -292,7 +292,13 @@ describe('EditBitstreamPageComponent', () => { describe('when an unknown format is selected', () => { beforeEach(() => { - comp.updateNewFormatLayout(allFormats[0].id); + comp.onChange({ + model: { + id: 'selectedFormat', + value: allFormats[0], + }, + }); + comp.updateNewFormatLayout(); }); it('should remove the invisible class from the \"New Format\" input', () => { @@ -394,9 +400,10 @@ describe('EditBitstreamPageComponent', () => { describe('when selected format has changed', () => { beforeEach(() => { - comp.formGroup.patchValue({ - formatContainer: { - selectedFormat: allFormats[2].id, + comp.onChange({ + model: { + id: 'selectedFormat', + value: allFormats[2], }, }); fixture.detectChanges(); diff --git a/src/app/bitstream-page/edit-bitstream-page/edit-bitstream-page.component.ts b/src/app/bitstream-page/edit-bitstream-page/edit-bitstream-page.component.ts index 36b0816ade..9f1a84c19d 100644 --- a/src/app/bitstream-page/edit-bitstream-page/edit-bitstream-page.component.ts +++ b/src/app/bitstream-page/edit-bitstream-page/edit-bitstream-page.component.ts @@ -21,7 +21,6 @@ import { DynamicFormLayout, DynamicFormService, DynamicInputModel, - DynamicSelectModel, } from '@ng-dynamic-forms/core'; import { TranslateModule, @@ -39,23 +38,24 @@ import { filter, map, switchMap, + take, tap, } from 'rxjs/operators'; import { DSONameService } from '../../core/breadcrumbs/dso-name.service'; +import { FindAllDataImpl } from '../../core/data/base/find-all-data'; import { BitstreamDataService } from '../../core/data/bitstream-data.service'; import { BitstreamFormatDataService } from '../../core/data/bitstream-format-data.service'; -import { PaginatedList } from '../../core/data/paginated-list.model'; import { PrimaryBitstreamService } from '../../core/data/primary-bitstream.service'; import { RemoteData } from '../../core/data/remote-data'; import { Bitstream } from '../../core/shared/bitstream.model'; import { BitstreamFormat } from '../../core/shared/bitstream-format.model'; +import { BITSTREAM_FORMAT } from '../../core/shared/bitstream-format.resource-type'; import { BitstreamFormatSupportLevel } from '../../core/shared/bitstream-format-support-level'; import { Bundle } from '../../core/shared/bundle.model'; import { Item } from '../../core/shared/item.model'; import { Metadata } from '../../core/shared/metadata.utils'; import { - getAllSucceededRemoteDataPayload, getFirstCompletedRemoteData, getFirstSucceededRemoteData, getFirstSucceededRemoteDataPayload, @@ -72,6 +72,7 @@ import { ErrorComponent } from '../../shared/error/error.component'; import { DynamicCustomSwitchModel } from '../../shared/form/builder/ds-dynamic-form-ui/models/custom-switch/custom-switch.model'; import { DsDynamicInputModel } from '../../shared/form/builder/ds-dynamic-form-ui/models/ds-dynamic-input.model'; import { DsDynamicTextAreaModel } from '../../shared/form/builder/ds-dynamic-form-ui/models/ds-dynamic-textarea.model'; +import { DynamicScrollableDropdownModel } from '../../shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.model'; import { FormComponent } from '../../shared/form/form.component'; import { ThemedLoadingComponent } from '../../shared/loading/themed-loading.component'; import { NotificationsService } from '../../shared/notifications/notifications.service'; @@ -109,12 +110,6 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy { */ bitstreamRD$: Observable>; - /** - * The formats their remote data observable - * Tracks changes and updates the view - */ - bitstreamFormatsRD$: Observable>>; - /** * The UUID of the primary bitstream for this bundle */ @@ -130,11 +125,6 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy { */ originalFormat: BitstreamFormat; - /** - * A list of all available bitstream formats - */ - formats: BitstreamFormat[]; - /** * @type {string} Key prefix used to generate form messages */ @@ -178,7 +168,10 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy { /** * Options for fetching all bitstream formats */ - findAllOptions = { elementsPerPage: 9999 }; + findAllOptions = { + elementsPerPage: 20, + currentPage: 1, + }; /** * The Dynamic Input Model for the file's name @@ -218,9 +211,22 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy { /** * The Dynamic Input Model for the selected format */ - selectedFormatModel = new DynamicSelectModel({ + selectedFormatModel = new DynamicScrollableDropdownModel({ id: 'selectedFormat', name: 'selectedFormat', + displayKey: 'shortDescription', + repeatable: false, + metadataFields: [], + submissionId: '', + hasSelectableMetadata: false, + resourceType: BITSTREAM_FORMAT, + formatFunction: (format: BitstreamFormat | string) => { + if (format instanceof BitstreamFormat) { + return hasValue(format) && format.supportLevel === BitstreamFormatSupportLevel.Unknown ? this.translate.instant(this.KEY_PREFIX + 'selectedFormat.unknown') : format.shortDescription; + } else { + return format; + } + }, }); /** @@ -438,6 +444,11 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy { * @private */ private bundle: Bundle; + /** + * The currently selected format + * @private + */ + private selectedFormat: BitstreamFormat; constructor(private route: ActivatedRoute, private router: Router, @@ -463,18 +474,12 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy { this.itemId = this.route.snapshot.queryParams.itemId; this.entityType = this.route.snapshot.queryParams.entityType; this.bitstreamRD$ = this.route.data.pipe(map((data: any) => data.bitstream)); - this.bitstreamFormatsRD$ = this.bitstreamFormatService.findAll(this.findAllOptions); const bitstream$ = this.bitstreamRD$.pipe( getFirstSucceededRemoteData(), getRemoteDataPayload(), ); - const allFormats$ = this.bitstreamFormatsRD$.pipe( - getFirstSucceededRemoteData(), - getRemoteDataPayload(), - ); - const bundle$ = bitstream$.pipe( switchMap((bitstream: Bitstream) => bitstream.bundle), getFirstSucceededRemoteDataPayload(), @@ -490,24 +495,31 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy { switchMap((bundle: Bundle) => bundle.item), getFirstSucceededRemoteDataPayload(), ); + const format$ = bitstream$.pipe( + switchMap(bitstream => bitstream.format), + getFirstSucceededRemoteDataPayload(), + ); + this.subs.push( observableCombineLatest( bitstream$, - allFormats$, bundle$, primaryBitstream$, item$, - ).pipe() - .subscribe(([bitstream, allFormats, bundle, primaryBitstream, item]) => { - this.bitstream = bitstream as Bitstream; - this.formats = allFormats.page; - this.bundle = bundle; - // hasValue(primaryBitstream) because if there's no primaryBitstream on the bundle it will - // be a success response, but empty - this.primaryBitstreamUUID = hasValue(primaryBitstream) ? primaryBitstream.uuid : null; - this.itemId = item.uuid; - this.setIiifStatus(this.bitstream); - }), + format$, + ).subscribe(([bitstream, bundle, primaryBitstream, item, format]) => { + this.bitstream = bitstream as Bitstream; + this.bundle = bundle; + this.selectedFormat = format; + // hasValue(primaryBitstream) because if there's no primaryBitstream on the bundle it will + // be a success response, but empty + this.primaryBitstreamUUID = hasValue(primaryBitstream) ? primaryBitstream.uuid : null; + this.itemId = item.uuid; + this.setIiifStatus(this.bitstream); + }), + format$.pipe(take(1)).subscribe( + (format) => this.originalFormat = format, + ), ); this.subs.push( @@ -523,7 +535,6 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy { */ setForm() { this.formGroup = this.formService.createFormGroup(this.formModel); - this.updateFormatModel(); this.updateForm(this.bitstream); this.updateFieldTranslations(); } @@ -542,6 +553,7 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy { description: bitstream.firstMetadataValue('dc.description'), }, formatContainer: { + selectedFormat: this.selectedFormat.shortDescription, newFormat: hasValue(bitstream.firstMetadata('dc.format')) ? bitstream.firstMetadata('dc.format').value : undefined, }, }); @@ -561,36 +573,16 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy { }, }); } - this.bitstream.format.pipe( - getAllSucceededRemoteDataPayload(), - ).subscribe((format: BitstreamFormat) => { - this.originalFormat = format; - this.formGroup.patchValue({ - formatContainer: { - selectedFormat: format.id, - }, - }); - this.updateNewFormatLayout(format.id); - }); + this.updateNewFormatLayout(); } - /** - * Create the list of unknown format IDs an add options to the selectedFormatModel - */ - updateFormatModel() { - this.selectedFormatModel.options = this.formats.map((format: BitstreamFormat) => - Object.assign({ - value: format.id, - label: this.isUnknownFormat(format.id) ? this.translate.instant(this.KEY_PREFIX + 'selectedFormat.unknown') : format.shortDescription, - })); - } /** * Update the layout of the "Other Format" input depending on the selected format * @param selectedId */ - updateNewFormatLayout(selectedId: string) { - if (this.isUnknownFormat(selectedId)) { + updateNewFormatLayout() { + if (this.isUnknownFormat()) { this.formLayout.newFormat.grid.host = this.newFormatBaseLayout; } else { this.formLayout.newFormat.grid.host = this.newFormatBaseLayout + ' invisible'; @@ -601,9 +593,8 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy { * Is the provided format (id) part of the list of unknown formats? * @param id */ - isUnknownFormat(id: string): boolean { - const format = this.formats.find((f: BitstreamFormat) => f.id === id); - return hasValue(format) && format.supportLevel === BitstreamFormatSupportLevel.Unknown; + isUnknownFormat(): boolean { + return hasValue(this.selectedFormat) && this.selectedFormat.supportLevel === BitstreamFormatSupportLevel.Unknown; } /** @@ -635,7 +626,8 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy { onChange(event) { const model = event.model; if (model.id === this.selectedFormatModel.id) { - this.updateNewFormatLayout(model.value); + this.selectedFormat = model.value; + this.updateNewFormatLayout(); } } @@ -645,8 +637,7 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy { onSubmit() { const updatedValues = this.formGroup.getRawValue(); const updatedBitstream = this.formToBitstream(updatedValues); - const selectedFormat = this.formats.find((f: BitstreamFormat) => f.id === updatedValues.formatContainer.selectedFormat); - const isNewFormat = selectedFormat.id !== this.originalFormat.id; + const isNewFormat = this.selectedFormat.id !== this.originalFormat.id; const isPrimary = updatedValues.fileNamePrimaryContainer.primaryBitstream; const wasPrimary = this.primaryBitstreamUUID === this.bitstream.uuid; @@ -698,7 +689,7 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy { bundle$ = observableOf(this.bundle); } if (isNewFormat) { - bitstream$ = this.bitstreamService.updateFormat(this.bitstream, selectedFormat).pipe( + bitstream$ = this.bitstreamService.updateFormat(this.bitstream, this.selectedFormat).pipe( getFirstCompletedRemoteData(), map((formatResponse: RemoteData) => { if (hasValue(formatResponse) && formatResponse.hasFailed) { @@ -856,4 +847,7 @@ export class EditBitstreamPageComponent implements OnInit, OnDestroy { .forEach((subscription) => subscription.unsubscribe()); } + findAllFormatsServiceFactory() { + return () => this.bitstreamFormatService as any as FindAllDataImpl; + } } diff --git a/src/app/browse-by/browse-by-date/browse-by-date.component.spec.ts b/src/app/browse-by/browse-by-date/browse-by-date.component.spec.ts index edd7cd951a..fad573705c 100644 --- a/src/app/browse-by/browse-by-date/browse-by-date.component.spec.ts +++ b/src/app/browse-by/browse-by-date/browse-by-date.component.spec.ts @@ -2,10 +2,13 @@ import { CommonModule } from '@angular/common'; import { ChangeDetectorRef, NO_ERRORS_SCHEMA, + PLATFORM_ID, } from '@angular/core'; import { ComponentFixture, + fakeAsync, TestBed, + tick, waitForAsync, } from '@angular/core/testing'; import { @@ -26,6 +29,7 @@ import { BrowseEntrySearchOptions } from '../../core/browse/browse-entry-search- import { SortDirection } from '../../core/cache/models/sort-options.model'; import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.service'; import { PaginationService } from '../../core/pagination/pagination.service'; +import { BrowseEntry } from '../../core/shared/browse-entry.model'; import { Community } from '../../core/shared/community.model'; import { Item } from '../../core/shared/item.model'; import { ThemedBrowseByComponent } from '../../shared/browse-by/themed-browse-by.component'; @@ -123,6 +127,7 @@ describe('BrowseByDateComponent', () => { { provide: ChangeDetectorRef, useValue: mockCdRef }, { provide: Store, useValue: {} }, { provide: APP_CONFIG, useValue: environment }, + { provide: PLATFORM_ID, useValue: 'browser' }, ], schemas: [NO_ERRORS_SCHEMA], }) @@ -172,4 +177,33 @@ describe('BrowseByDateComponent', () => { //expect(comp.startsWithOptions[0]).toEqual(new Date().getUTCFullYear()); expect(comp.startsWithOptions[0]).toEqual(1960); }); + + describe('when rendered in SSR', () => { + beforeEach(() => { + comp.platformId = 'server'; + spyOn((comp as any).browseService, 'getBrowseItemsFor'); + }); + + it('should not call getBrowseItemsFor on init', (done) => { + comp.ngOnInit(); + expect((comp as any).browseService.getBrowseItemsFor).not.toHaveBeenCalled(); + comp.loading$.subscribe((res) => { + expect(res).toBeFalsy(); + done(); + }); + }); + }); + + describe('when rendered in CSR', () => { + beforeEach(() => { + comp.platformId = 'browser'; + spyOn((comp as any).browseService, 'getBrowseItemsFor').and.returnValue(createSuccessfulRemoteDataObject$(new BrowseEntry())); + }); + + it('should call getBrowseItemsFor on init', fakeAsync(() => { + comp.ngOnInit(); + tick(100); + expect((comp as any).browseService.getBrowseItemsFor).toHaveBeenCalled(); + })); + }); }); diff --git a/src/app/browse-by/browse-by-date/browse-by-date.component.ts b/src/app/browse-by/browse-by-date/browse-by-date.component.ts index 11818ff5f1..5c14f2109c 100644 --- a/src/app/browse-by/browse-by-date/browse-by-date.component.ts +++ b/src/app/browse-by/browse-by-date/browse-by-date.component.ts @@ -1,5 +1,6 @@ import { AsyncPipe, + isPlatformServer, NgIf, } from '@angular/common'; import { @@ -7,6 +8,7 @@ import { Component, Inject, OnInit, + PLATFORM_ID, } from '@angular/core'; import { ActivatedRoute, @@ -17,6 +19,7 @@ import { TranslateModule } from '@ngx-translate/core'; import { combineLatest as observableCombineLatest, Observable, + of as observableOf, } from 'rxjs'; import { map, @@ -28,6 +31,7 @@ import { APP_CONFIG, AppConfig, } from '../../../config/app-config.interface'; +import { environment } from '../../../environments/environment'; import { DSONameService } from '../../core/breadcrumbs/dso-name.service'; import { BrowseService } from '../../core/browse/browse.service'; import { @@ -99,11 +103,16 @@ export class BrowseByDateComponent extends BrowseByMetadataComponent implements @Inject(APP_CONFIG) public appConfig: AppConfig, public dsoNameService: DSONameService, protected cdRef: ChangeDetectorRef, + @Inject(PLATFORM_ID) public platformId: any, ) { - super(route, browseService, dsoService, paginationService, router, appConfig, dsoNameService); + super(route, browseService, dsoService, paginationService, router, appConfig, dsoNameService, platformId); } ngOnInit(): void { + if (!this.renderOnServerSide && !environment.ssr.enableBrowseComponent && isPlatformServer(this.platformId)) { + this.loading$ = observableOf(false); + return; + } const sortConfig = new SortOptions('default', SortDirection.ASC); this.startsWithType = StartsWithType.date; this.currentPagination$ = this.paginationService.getCurrentPagination(this.paginationConfig.id, this.paginationConfig); diff --git a/src/app/browse-by/browse-by-metadata/browse-by-metadata.component.html b/src/app/browse-by/browse-by-metadata/browse-by-metadata.component.html index 22e564ac27..6642b724bb 100644 --- a/src/app/browse-by/browse-by-metadata/browse-by-metadata.component.html +++ b/src/app/browse-by/browse-by-metadata/browse-by-metadata.component.html @@ -1,4 +1,4 @@ -
+