diff --git a/.eslintrc.json b/.eslintrc.json index 50a9be3d59b..4cc8c6dbc5a 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -11,7 +11,13 @@ "eslint-plugin-jsonc", "eslint-plugin-rxjs", "eslint-plugin-simple-import-sort", - "eslint-plugin-import-newlines" + "eslint-plugin-import-newlines", + "eslint-plugin-jsonc", + "dspace-angular-ts", + "dspace-angular-html" + ], + "ignorePatterns": [ + "lint/test/fixture" ], "overrides": [ { @@ -21,7 +27,8 @@ "parserOptions": { "project": [ "./tsconfig.json", - "./cypress/tsconfig.json" + "./cypress/tsconfig.json", + "./lint/tsconfig.json" ], "createDefaultProgram": true }, @@ -38,7 +45,10 @@ "error", 2, { - "SwitchCase": 1 + "SwitchCase": 1, + "ignoredNodes": [ + "ClassBody.body > PropertyDefinition[decorators.length > 0] > .key" + ] } ], "max-classes-per-file": [ @@ -212,6 +222,15 @@ "@typescript-eslint/no-unsafe-return": "off", "@typescript-eslint/restrict-template-expressions": "off", "@typescript-eslint/require-await": "off", + "@typescript-eslint/no-base-to-string": [ + "error", + { + "ignoredTypeNames": [ + "ResourceType", + "Error" + ] + } + ], "deprecation/deprecation": "warn", @@ -238,7 +257,12 @@ "method" ], - "rxjs/no-nested-subscribe": "off" // todo: go over _all_ cases + "rxjs/no-nested-subscribe": "off", // todo: go over _all_ cases + + // Custom DSpace Angular rules + "dspace-angular-ts/themed-component-classes": "error", + "dspace-angular-ts/themed-component-selectors": "error", + "dspace-angular-ts/themed-component-usages": "error" } }, { @@ -253,7 +277,10 @@ "createDefaultProgram": true }, "rules": { - "prefer-const": "off" + "prefer-const": "off", + + // Custom DSpace Angular rules + "dspace-angular-ts/themed-component-usages": "error" } }, { @@ -262,7 +289,11 @@ ], "extends": [ "plugin:@angular-eslint/template/recommended" - ] + ], + "rules": { + // Custom DSpace Angular rules + "dspace-angular-html/themed-component-usages": "error" + } }, { "files": [ diff --git a/.gitattributes b/.gitattributes index 406640bfcc9..b5ad93b1bc6 100644 --- a/.gitattributes +++ b/.gitattributes @@ -13,4 +13,7 @@ *.css eol=lf *.scss eol=lf *.html eol=lf -*.svg eol=lf \ No newline at end of file +*.svg eol=lf + +# Generated documentation should have LF line endings to reduce git noise +docs/lint/**/*.md eol=lf \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f6ffa5e004b..4f2a84ce8a6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -85,8 +85,14 @@ jobs: - name: Install Yarn dependencies run: yarn install --frozen-lockfile + - name: Build lint plugins + run: yarn run build:lint + + - name: Run lint plugin tests + run: yarn run test:lint:nobuild + - name: Run lint - run: yarn run lint --quiet + run: yarn run lint:nobuild --quiet - name: Check for circular dependencies run: yarn run check-circ-deps diff --git a/angular.json b/angular.json index 98463fa732e..5f0204249b1 100644 --- a/angular.json +++ b/angular.json @@ -266,6 +266,8 @@ "options": { "lintFilePatterns": [ "src/**/*.ts", + "cypress/**/*.ts", + "lint/**/*.ts", "src/**/*.html", "src/**/*.json5" ] diff --git a/cypress/e2e/collection-create.cy.ts b/cypress/e2e/collection-create.cy.ts new file mode 100644 index 00000000000..29f7dd5cacb --- /dev/null +++ b/cypress/e2e/collection-create.cy.ts @@ -0,0 +1,13 @@ +beforeEach(() => { + cy.visit('/collections/create?parent='.concat(Cypress.env('DSPACE_TEST_COMMUNITY'))); + cy.loginViaForm(Cypress.env('DSPACE_TEST_ADMIN_USER'), Cypress.env('DSPACE_TEST_ADMIN_PASSWORD')); +}); + +it('should show loading component while saving', () => { + const title = 'Test Collection Title'; + cy.get('#title').type(title); + + cy.get('button[type="submit"]').click(); + + cy.get('ds-loading').should('be.visible'); +}); diff --git a/cypress/e2e/community-create.cy.ts b/cypress/e2e/community-create.cy.ts new file mode 100644 index 00000000000..96bc003ba2a --- /dev/null +++ b/cypress/e2e/community-create.cy.ts @@ -0,0 +1,13 @@ +beforeEach(() => { + cy.visit('/communities/create'); + cy.loginViaForm(Cypress.env('DSPACE_TEST_ADMIN_USER'), Cypress.env('DSPACE_TEST_ADMIN_PASSWORD')); +}); + +it('should show loading component while saving', () => { + const title = 'Test Community Title'; + cy.get('#title').type(title); + + cy.get('button[type="submit"]').click(); + + cy.get('ds-loading').should('be.visible'); +}); diff --git a/cypress/e2e/login-modal.cy.ts b/cypress/e2e/login-modal.cy.ts index 190f3ff9271..3d978dfaca2 100644 --- a/cypress/e2e/login-modal.cy.ts +++ b/cypress/e2e/login-modal.cy.ts @@ -3,31 +3,31 @@ import { testA11y } from 'cypress/support/utils'; const page = { openLoginMenu() { // Click the "Log In" dropdown menu in header - cy.get('ds-themed-header [data-test="login-menu"]').click(); + cy.get('ds-header [data-test="login-menu"]').click(); }, openUserMenu() { // Once logged in, click the User menu in header - cy.get('ds-themed-header [data-test="user-menu"]').click(); + cy.get('ds-header [data-test="user-menu"]').click(); }, submitLoginAndPasswordByPressingButton(email, password) { // Enter email - cy.get('ds-themed-header [data-test="email"]').type(email); + cy.get('ds-header [data-test="email"]').type(email); // Enter password - cy.get('ds-themed-header [data-test="password"]').type(password); + cy.get('ds-header [data-test="password"]').type(password); // Click login button - cy.get('ds-themed-header [data-test="login-button"]').click(); + cy.get('ds-header [data-test="login-button"]').click(); }, submitLoginAndPasswordByPressingEnter(email, password) { // In opened Login modal, fill out email & password, then click Enter - cy.get('ds-themed-header [data-test="email"]').type(email); - cy.get('ds-themed-header [data-test="password"]').type(password); - cy.get('ds-themed-header [data-test="password"]').type('{enter}'); + cy.get('ds-header [data-test="email"]').type(email); + cy.get('ds-header [data-test="password"]').type(password); + cy.get('ds-header [data-test="password"]').type('{enter}'); }, submitLogoutByPressingButton() { // This is the POST command that will actually log us out cy.intercept('POST', '/server/api/authn/logout').as('logout'); // Click logout button - cy.get('ds-themed-header [data-test="logout-button"]').click(); + cy.get('ds-header [data-test="logout-button"]').click(); // Wait until above POST command responds before continuing // (This ensures next action waits until logout completes) cy.wait('@logout'); @@ -102,10 +102,10 @@ describe('Login Modal', () => { page.openLoginMenu(); // Registration link should be visible - cy.get('ds-themed-header [data-test="register"]').should('be.visible'); + cy.get('ds-header [data-test="register"]').should('be.visible'); // Click registration link & you should go to registration page - cy.get('ds-themed-header [data-test="register"]').click(); + cy.get('ds-header [data-test="register"]').click(); cy.location('pathname').should('eq', '/register'); cy.get('ds-register-email').should('exist'); @@ -119,10 +119,10 @@ describe('Login Modal', () => { page.openLoginMenu(); // Forgot password link should be visible - cy.get('ds-themed-header [data-test="forgot"]').should('be.visible'); + cy.get('ds-header [data-test="forgot"]').should('be.visible'); // Click link & you should go to Forgot Password page - cy.get('ds-themed-header [data-test="forgot"]').click(); + cy.get('ds-header [data-test="forgot"]').click(); cy.location('pathname').should('eq', '/forgot'); cy.get('ds-forgot-email').should('exist'); diff --git a/cypress/e2e/search-navbar.cy.ts b/cypress/e2e/search-navbar.cy.ts index b1682199161..0613e5e7124 100644 --- a/cypress/e2e/search-navbar.cy.ts +++ b/cypress/e2e/search-navbar.cy.ts @@ -1,15 +1,15 @@ const page = { fillOutQueryInNavBar(query) { // Click the magnifying glass - cy.get('ds-themed-header [data-test="header-search-icon"]').click(); + cy.get('ds-header [data-test="header-search-icon"]').click(); // Fill out a query in input that appears - cy.get('ds-themed-header [data-test="header-search-box"]').type(query); + cy.get('ds-header [data-test="header-search-box"]').type(query); }, submitQueryByPressingEnter() { - cy.get('ds-themed-header [data-test="header-search-box"]').type('{enter}'); + cy.get('ds-header [data-test="header-search-box"]').type('{enter}'); }, submitQueryByPressingIcon() { - cy.get('ds-themed-header [data-test="header-search-icon"]').click(); + cy.get('ds-header [data-test="header-search-icon"]').click(); }, }; diff --git a/docker/cli.assetstore.yml b/docker/cli.assetstore.yml index 31bc53f64d8..98f74148610 100644 --- a/docker/cli.assetstore.yml +++ b/docker/cli.assetstore.yml @@ -12,8 +12,6 @@ # https://github.com/DSpace/DSpace/blob/main/dspace/src/main/docker-compose/cli.assetstore.yml # # Therefore, it should be kept in sync with that file -version: "3.7" - services: dspace-cli: environment: diff --git a/docker/cli.ingest.yml b/docker/cli.ingest.yml index 1db241af3bf..cc3623298ed 100644 --- a/docker/cli.ingest.yml +++ b/docker/cli.ingest.yml @@ -12,8 +12,6 @@ # https://github.com/DSpace/DSpace/blob/main/dspace/src/main/docker-compose/cli.ingest.yml # # Therefore, it should be kept in sync with that file -version: "3.7" - services: dspace-cli: environment: diff --git a/docker/cli.yml b/docker/cli.yml index cc266b186f9..9b1973426f3 100644 --- a/docker/cli.yml +++ b/docker/cli.yml @@ -12,7 +12,6 @@ # https://github.com/DSpace/DSpace/blob/main/docker-compose-cli.yml # # Therefore, it should be kept in sync with that file -version: "3.7" networks: # Default to using network named 'dspacenet' from docker-compose-rest.yml. # Its full name will be prepended with the project name (e.g. "-p d7" means it will be named "d7_dspacenet") diff --git a/docker/db.entities.yml b/docker/db.entities.yml index 6473bf2e385..5c0a15c8f69 100644 --- a/docker/db.entities.yml +++ b/docker/db.entities.yml @@ -12,8 +12,6 @@ # https://github.com/DSpace/DSpace/blob/main/dspace/src/main/docker-compose/db.entities.yml # # # Therefore, it should be kept in sync with that file -version: "3.7" - services: dspacedb: image: dspace/dspace-postgres-pgcrypto:loadsql diff --git a/docker/docker-compose-ci.yml b/docker/docker-compose-ci.yml index fef7330ba10..d78a05362e8 100644 --- a/docker/docker-compose-ci.yml +++ b/docker/docker-compose-ci.yml @@ -10,7 +10,6 @@ # This is used by our GitHub CI at .github/workflows/build.yml # It is based heavily on the Backend's Docker Compose: # https://github.com/DSpace/DSpace/blob/main/docker-compose.yml -version: '3.7' networks: dspacenet: services: diff --git a/docker/docker-compose-dist.yml b/docker/docker-compose-dist.yml index 38278085cd0..67eba167852 100644 --- a/docker/docker-compose-dist.yml +++ b/docker/docker-compose-dist.yml @@ -8,7 +8,6 @@ # Docker Compose for running the DSpace Angular UI dist build # for previewing with the DSpace Demo site backend -version: '3.7' networks: dspacenet: services: diff --git a/docker/docker-compose-rest.yml b/docker/docker-compose-rest.yml index 6267b32bbe3..2ec4eccf209 100644 --- a/docker/docker-compose-rest.yml +++ b/docker/docker-compose-rest.yml @@ -10,7 +10,6 @@ # This is based heavily on the docker-compose.yml that is available in the DSpace/DSpace # (Backend) at: # https://github.com/DSpace/DSpace/blob/main/docker-compose.yml -version: '3.7' networks: dspacenet: ipam: diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 1071b8d6ce2..1c268b84b7b 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -9,7 +9,6 @@ # Docker Compose for running the DSpace Angular UI for testing/development # Requires also running a REST API backend (either locally or remotely), # for example via 'docker-compose-rest.yml' -version: '3.7' networks: dspacenet: services: diff --git a/docs/lint/html/index.md b/docs/lint/html/index.md new file mode 100644 index 00000000000..15d693843c0 --- /dev/null +++ b/docs/lint/html/index.md @@ -0,0 +1,4 @@ +[DSpace ESLint plugins](../../../lint/README.md) > HTML rules +_______ + +- [`dspace-angular-html/themed-component-usages`](./rules/themed-component-usages.md): Themeable components should be used via the selector of their `ThemedComponent` wrapper class diff --git a/docs/lint/html/rules/themed-component-usages.md b/docs/lint/html/rules/themed-component-usages.md new file mode 100644 index 00000000000..a04fe1c770a --- /dev/null +++ b/docs/lint/html/rules/themed-component-usages.md @@ -0,0 +1,110 @@ +[DSpace ESLint plugins](../../../../lint/README.md) > [HTML rules](../index.md) > `dspace-angular-html/themed-component-usages` +_______ + +Themeable components should be used via the selector of their `ThemedComponent` wrapper class + +This ensures that custom themes can correctly override _all_ instances of this component. +The only exception to this rule are unit tests, where we may want to use the base component in order to keep the test setup simple. + + +_______ + +[Source code](../../../../lint/src/rules/html/themed-component-usages.ts) + +### Examples + + +#### Valid code + +##### use no-prefix selectors in HTML templates + +```html + + + +``` + +##### use no-prefix selectors in TypeScript templates + +```html +@Component({ + template: '' +}) +class Test { +} +``` + +##### use no-prefix selectors in TypeScript test templates + +Filename: `lint/test/fixture/src/test.spec.ts` + +```html +@Component({ + template: '' +}) +class Test { +} +``` + +##### base selectors are also allowed in TypeScript test templates + +Filename: `lint/test/fixture/src/test.spec.ts` + +```html +@Component({ + template: '' +}) +class Test { +} +``` + + + + +#### Invalid code & automatic fixes + +##### themed override selectors are not allowed in HTML templates + +```html + + + +``` +Will produce the following error(s): +``` +Themeable components should be used via their ThemedComponent wrapper's selector +Themeable components should be used via their ThemedComponent wrapper's selector +Themeable components should be used via their ThemedComponent wrapper's selector +``` + +Result of `yarn lint --fix`: +```html + + + +``` + + +##### base selectors are not allowed in HTML templates + +```html + + + +``` +Will produce the following error(s): +``` +Themeable components should be used via their ThemedComponent wrapper's selector +Themeable components should be used via their ThemedComponent wrapper's selector +Themeable components should be used via their ThemedComponent wrapper's selector +``` + +Result of `yarn lint --fix`: +```html + + + +``` + + + diff --git a/docs/lint/ts/index.md b/docs/lint/ts/index.md new file mode 100644 index 00000000000..ed060c946e8 --- /dev/null +++ b/docs/lint/ts/index.md @@ -0,0 +1,6 @@ +[DSpace ESLint plugins](../../../lint/README.md) > TypeScript rules +_______ + +- [`dspace-angular-ts/themed-component-classes`](./rules/themed-component-classes.md): Formatting rules for themeable component classes +- [`dspace-angular-ts/themed-component-selectors`](./rules/themed-component-selectors.md): Themeable component selectors should follow the DSpace convention +- [`dspace-angular-ts/themed-component-usages`](./rules/themed-component-usages.md): Themeable components should be used via their `ThemedComponent` wrapper class diff --git a/docs/lint/ts/rules/themed-component-classes.md b/docs/lint/ts/rules/themed-component-classes.md new file mode 100644 index 00000000000..1f4ec72801c --- /dev/null +++ b/docs/lint/ts/rules/themed-component-classes.md @@ -0,0 +1,257 @@ +[DSpace ESLint plugins](../../../../lint/README.md) > [TypeScript rules](../index.md) > `dspace-angular-ts/themed-component-classes` +_______ + +Formatting rules for themeable component classes + +- All themeable components must be standalone. +- The base component must always be imported in the `ThemedComponent` wrapper. This ensures that it is always sufficient to import just the wrapper whenever we use the component. + + +_______ + +[Source code](../../../../lint/src/rules/ts/themed-component-classes.ts) + +### Examples + + +#### Valid code + +##### Regular non-themeable component + +```typescript +@Component({ + selector: 'ds-something', + standalone: true, +}) +class Something { +} +``` + +##### Base component + +```typescript +@Component({ + selector: 'ds-base-test-themable', + standalone: true, +}) +class TestThemeableTomponent { +} +``` + +##### Wrapper component + +Filename: `lint/test/fixture/src/app/test/themed-test-themeable.component.ts` + +```typescript +@Component({ + selector: 'ds-test-themable', + standalone: true, + imports: [ + TestThemeableComponent, + ], +}) +class ThemedTestThemeableTomponent extends ThemedComponent { +} +``` + +##### Override component + +Filename: `lint/test/fixture/src/themes/test/app/test/test-themeable.component.ts` + +```typescript +@Component({ + selector: 'ds-themed-test-themable', + standalone: true, +}) +class Override extends BaseComponent { +} +``` + + + + +#### Invalid code & automatic fixes + +##### Base component must be standalone + +```typescript +@Component({ + selector: 'ds-base-test-themable', +}) +class TestThemeableComponent { +} +``` +Will produce the following error(s): +``` +Themeable components must be standalone +``` + +Result of `yarn lint --fix`: +```typescript +@Component({ + selector: 'ds-base-test-themable', + standalone: true, +}) +class TestThemeableComponent { +} +``` + + +##### Wrapper component must be standalone and import base component + +Filename: `lint/test/fixture/src/app/test/themed-test-themeable.component.ts` + +```typescript +@Component({ + selector: 'ds-test-themable', +}) +class ThemedTestThemeableComponent extends ThemedComponent { +} +``` +Will produce the following error(s): +``` +Themeable component wrapper classes must be standalone and import the base class +``` + +Result of `yarn lint --fix`: +```typescript +@Component({ + selector: 'ds-test-themable', + standalone: true, + imports: [TestThemeableComponent], +}) +class ThemedTestThemeableComponent extends ThemedComponent { +} +``` + + +##### Wrapper component must import base component (array present but empty) + +Filename: `lint/test/fixture/src/app/test/themed-test-themeable.component.ts` + +```typescript +@Component({ + selector: 'ds-test-themable', + standalone: true, + imports: [], +}) +class ThemedTestThemeableComponent extends ThemedComponent { +} +``` +Will produce the following error(s): +``` +Themed component wrapper classes must only import the base class +``` + +Result of `yarn lint --fix`: +```typescript +@Component({ + selector: 'ds-test-themable', + standalone: true, + imports: [TestThemeableComponent], +}) +class ThemedTestThemeableComponent extends ThemedComponent { +} +``` + + +##### Wrapper component must import base component (array is wrong) + +Filename: `lint/test/fixture/src/app/test/themed-test-themeable.component.ts` + +```typescript +import { SomethingElse } from './somewhere-else'; + +@Component({ + selector: 'ds-test-themable', + standalone: true, + imports: [ + SomethingElse, + ], +}) +class ThemedTestThemeableComponent extends ThemedComponent { +} +``` +Will produce the following error(s): +``` +Themed component wrapper classes must only import the base class +``` + +Result of `yarn lint --fix`: +```typescript +import { SomethingElse } from './somewhere-else'; + +@Component({ + selector: 'ds-test-themable', + standalone: true, + imports: [TestThemeableComponent], +}) +class ThemedTestThemeableComponent extends ThemedComponent { +} +``` + + +##### Wrapper component must import base component (array is wrong) + +Filename: `lint/test/fixture/src/app/test/themed-test-themeable.component.ts` + +```typescript +import { Something, SomethingElse } from './somewhere-else'; + +@Component({ + selector: 'ds-test-themable', + standalone: true, + imports: [ + SomethingElse, + ], +}) +class ThemedTestThemeableComponent extends ThemedComponent { +} +``` +Will produce the following error(s): +``` +Themed component wrapper classes must only import the base class +``` + +Result of `yarn lint --fix`: +```typescript +import { Something, SomethingElse } from './somewhere-else'; + +@Component({ + selector: 'ds-test-themable', + standalone: true, + imports: [TestThemeableComponent], +}) +class ThemedTestThemeableComponent extends ThemedComponent { +} +``` + + +##### Override component must be standalone + +Filename: `lint/test/fixture/src/themes/test/app/test/test-themeable.component.ts` + +```typescript +@Component({ + selector: 'ds-themed-test-themable', +}) +class Override extends BaseComponent { +} +``` +Will produce the following error(s): +``` +Themeable components must be standalone +``` + +Result of `yarn lint --fix`: +```typescript +@Component({ + selector: 'ds-themed-test-themable', + standalone: true, +}) +class Override extends BaseComponent { +} +``` + + + diff --git a/docs/lint/ts/rules/themed-component-selectors.md b/docs/lint/ts/rules/themed-component-selectors.md new file mode 100644 index 00000000000..f4d0ea177c9 --- /dev/null +++ b/docs/lint/ts/rules/themed-component-selectors.md @@ -0,0 +1,156 @@ +[DSpace ESLint plugins](../../../../lint/README.md) > [TypeScript rules](../index.md) > `dspace-angular-ts/themed-component-selectors` +_______ + +Themeable component selectors should follow the DSpace convention + +Each themeable component is comprised of a base component, a wrapper component and any number of themed components +- Base components should have a selector starting with `ds-base-` +- Themed components should have a selector starting with `ds-themed-` +- Wrapper components should have a selector starting with `ds-`, but not `ds-base-` or `ds-themed-` + - This is the regular DSpace selector prefix + - **When making a regular component themeable, its selector prefix should be changed to `ds-base-`, and the new wrapper's component should reuse the previous selector** + +Unit tests are exempt from this rule, because they may redefine components using the same class name as other themeable components elsewhere in the source. + + +_______ + +[Source code](../../../../lint/src/rules/ts/themed-component-selectors.ts) + +### Examples + + +#### Valid code + +##### Regular non-themeable component selector + +```typescript +@Component({ + selector: 'ds-something', +}) +class Something { +} +``` + +##### Themeable component selector should replace the original version, unthemed version should be changed to ds-base- + +```typescript +@Component({ + selector: 'ds-base-something', +}) +class Something { +} + +@Component({ + selector: 'ds-something', +}) +class ThemedSomething extends ThemedComponent { +} + +@Component({ + selector: 'ds-themed-something', +}) +class OverrideSomething extends Something { +} +``` + +##### Other themed component wrappers should not interfere + +```typescript +@Component({ + selector: 'ds-something', +}) +class Something { +} + +@Component({ + selector: 'ds-something-else', +}) +class ThemedSomethingElse extends ThemedComponent { +} +``` + + + + +#### Invalid code & automatic fixes + +##### Wrong selector for base component + +Filename: `lint/test/fixture/src/app/test/test-themeable.component.ts` + +```typescript +@Component({ + selector: 'ds-something', +}) +class TestThemeableComponent { +} +``` +Will produce the following error(s): +``` +Unthemed version of themeable component should have a selector starting with 'ds-base-' +``` + +Result of `yarn lint --fix`: +```typescript +@Component({ + selector: 'ds-base-something', +}) +class TestThemeableComponent { +} +``` + + +##### Wrong selector for wrapper component + +Filename: `lint/test/fixture/src/app/test/themed-test-themeable.component.ts` + +```typescript +@Component({ + selector: 'ds-themed-something', +}) +class ThemedTestThemeableComponent extends ThemedComponent { +} +``` +Will produce the following error(s): +``` +Themed component wrapper of themeable component shouldn't have a selector starting with 'ds-themed-' +``` + +Result of `yarn lint --fix`: +```typescript +@Component({ + selector: 'ds-something', +}) +class ThemedTestThemeableComponent extends ThemedComponent { +} +``` + + +##### Wrong selector for theme override + +Filename: `lint/test/fixture/src/themes/test/app/test/test-themeable.component.ts` + +```typescript +@Component({ + selector: 'ds-something', +}) +class TestThememeableComponent extends BaseComponent { +} +``` +Will produce the following error(s): +``` +Theme override of themeable component should have a selector starting with 'ds-themed-' +``` + +Result of `yarn lint --fix`: +```typescript +@Component({ + selector: 'ds-themed-something', +}) +class TestThememeableComponent extends BaseComponent { +} +``` + + + diff --git a/docs/lint/ts/rules/themed-component-usages.md b/docs/lint/ts/rules/themed-component-usages.md new file mode 100644 index 00000000000..16ccb701c20 --- /dev/null +++ b/docs/lint/ts/rules/themed-component-usages.md @@ -0,0 +1,332 @@ +[DSpace ESLint plugins](../../../../lint/README.md) > [TypeScript rules](../index.md) > `dspace-angular-ts/themed-component-usages` +_______ + +Themeable components should be used via their `ThemedComponent` wrapper class + +This ensures that custom themes can correctly override _all_ instances of this component. +There are a few exceptions where the base class can still be used: +- Class declaration expressions (otherwise we can't declare, extend or override the class in the first place) +- Angular modules (except for routing modules) +- Angular `@ViewChild` decorators +- Type annotations + + +_______ + +[Source code](../../../../lint/src/rules/ts/themed-component-usages.ts) + +### Examples + + +#### Valid code + +##### allow wrapper class usages + +```typescript +import { ThemedTestThemeableComponent } from './app/test/themed-test-themeable.component'; + +const config = { + a: ThemedTestThemeableComponent, + b: ChipsComponent, +} +``` + +##### allow base class in class declaration + +```typescript +export class TestThemeableComponent { +} +``` + +##### allow inheriting from base class + +```typescript +import { TestThemeableComponent } from './app/test/test-themeable.component'; + +export class ThemedAdminSidebarComponent extends ThemedComponent { +} +``` + +##### allow base class in ViewChild + +```typescript +import { TestThemeableComponent } from './app/test/test-themeable.component'; + +export class Something { + @ViewChild(TestThemeableComponent) test: TestThemeableComponent; +} +``` + +##### allow wrapper selectors in test queries + +Filename: `lint/test/fixture/src/app/test/test.component.spec.ts` + +```typescript +By.css('ds-themeable'); +By.css('#test > ds-themeable > #nest'); +``` + +##### allow wrapper selectors in cypress queries + +Filename: `lint/test/fixture/src/app/test/test.component.cy.ts` + +```typescript +By.css('ds-themeable'); +By.css('#test > ds-themeable > #nest'); +``` + + + + +#### Invalid code & automatic fixes + +##### disallow direct usages of base class + +```typescript +import { TestThemeableComponent } from './app/test/test-themeable.component'; +import { TestComponent } from './app/test/test.component'; + +const config = { + a: TestThemeableComponent, + b: TestComponent, +} +``` +Will produce the following error(s): +``` +Themeable components should be used via their ThemedComponent wrapper +Themeable components should be used via their ThemedComponent wrapper +``` + +Result of `yarn lint --fix`: +```typescript +import { ThemedTestThemeableComponent } from './app/test/themed-test-themeable.component'; +import { TestComponent } from './app/test/test.component'; + +const config = { + a: ThemedTestThemeableComponent, + b: TestComponent, +} +``` + + +##### disallow direct usages of base class, keep other imports + +```typescript +import { Something, TestThemeableComponent } from './app/test/test-themeable.component'; +import { TestComponent } from './app/test/test.component'; + +const config = { + a: TestThemeableComponent, + b: TestComponent, + c: Something, +} +``` +Will produce the following error(s): +``` +Themeable components should be used via their ThemedComponent wrapper +Themeable components should be used via their ThemedComponent wrapper +``` + +Result of `yarn lint --fix`: +```typescript +import { Something } from './app/test/test-themeable.component'; +import { ThemedTestThemeableComponent } from './app/test/themed-test-themeable.component'; +import { TestComponent } from './app/test/test.component'; + +const config = { + a: ThemedTestThemeableComponent, + b: TestComponent, + c: Something, +} +``` + + +##### handle array replacements correctly + +```typescript +const DECLARATIONS = [ + Something, + TestThemeableComponent, + Something, + ThemedTestThemeableComponent, +]; +``` +Will produce the following error(s): +``` +Themeable components should be used via their ThemedComponent wrapper +``` + +Result of `yarn lint --fix`: +```typescript +const DECLARATIONS = [ + Something, + Something, + ThemedTestThemeableComponent, +]; +``` + + +##### disallow override selector in test queries + +Filename: `lint/test/fixture/src/app/test/test.component.spec.ts` + +```typescript +By.css('ds-themed-themeable'); +By.css('#test > ds-themed-themeable > #nest'); +``` +Will produce the following error(s): +``` +Themeable components should be used via their ThemedComponent wrapper +Themeable components should be used via their ThemedComponent wrapper +``` + +Result of `yarn lint --fix`: +```typescript +By.css('ds-themeable'); +By.css('#test > ds-themeable > #nest'); +``` + + +##### disallow base selector in test queries + +Filename: `lint/test/fixture/src/app/test/test.component.spec.ts` + +```typescript +By.css('ds-base-themeable'); +By.css('#test > ds-base-themeable > #nest'); +``` +Will produce the following error(s): +``` +Themeable components should be used via their ThemedComponent wrapper +Themeable components should be used via their ThemedComponent wrapper +``` + +Result of `yarn lint --fix`: +```typescript +By.css('ds-themeable'); +By.css('#test > ds-themeable > #nest'); +``` + + +##### disallow override selector in cypress queries + +Filename: `lint/test/fixture/src/app/test/test.component.cy.ts` + +```typescript +cy.get('ds-themed-themeable'); +cy.get('#test > ds-themed-themeable > #nest'); +``` +Will produce the following error(s): +``` +Themeable components should be used via their ThemedComponent wrapper +Themeable components should be used via their ThemedComponent wrapper +``` + +Result of `yarn lint --fix`: +```typescript +cy.get('ds-themeable'); +cy.get('#test > ds-themeable > #nest'); +``` + + +##### disallow base selector in cypress queries + +Filename: `lint/test/fixture/src/app/test/test.component.cy.ts` + +```typescript +cy.get('ds-base-themeable'); +cy.get('#test > ds-base-themeable > #nest'); +``` +Will produce the following error(s): +``` +Themeable components should be used via their ThemedComponent wrapper +Themeable components should be used via their ThemedComponent wrapper +``` + +Result of `yarn lint --fix`: +```typescript +cy.get('ds-themeable'); +cy.get('#test > ds-themeable > #nest'); +``` + + +##### edge case: unable to find usage node through usage token, but import is still flagged and fixed + +Filename: `lint/test/fixture/src/themes/test/app/test/other-themeable.component.ts` + +```typescript +import { Component } from '@angular/core'; + +import { Context } from './app/core/shared/context.model'; +import { TestThemeableComponent } from '../../../../app/test/test-themeable.component'; + +@Component({ + standalone: true, + imports: [TestThemeableComponent], +}) +export class UsageComponent { +} +``` +Will produce the following error(s): +``` +Themeable components should be used via their ThemedComponent wrapper +Themeable components should be used via their ThemedComponent wrapper +``` + +Result of `yarn lint --fix`: +```typescript +import { Component } from '@angular/core'; + +import { Context } from './app/core/shared/context.model'; +import { ThemedTestThemeableComponent } from '../../../../app/test/themed-test-themeable.component'; + +@Component({ + standalone: true, + imports: [ThemedTestThemeableComponent], +}) +export class UsageComponent { +} +``` + + +##### edge case edge case: both are imported, only wrapper is retained + +Filename: `lint/test/fixture/src/themes/test/app/test/other-themeable.component.ts` + +```typescript +import { Component } from '@angular/core'; + +import { Context } from './app/core/shared/context.model'; +import { TestThemeableComponent } from '../../../../app/test/test-themeable.component'; +import { ThemedTestThemeableComponent } from '../../../../app/test/themed-test-themeable.component'; + +@Component({ + standalone: true, + imports: [TestThemeableComponent, ThemedTestThemeableComponent], +}) +export class UsageComponent { +} +``` +Will produce the following error(s): +``` +Themeable components should be used via their ThemedComponent wrapper +Themeable components should be used via their ThemedComponent wrapper +``` + +Result of `yarn lint --fix`: +```typescript +import { Component } from '@angular/core'; + +import { Context } from './app/core/shared/context.model'; +import { ThemedTestThemeableComponent } from '../../../../app/test/themed-test-themeable.component'; + +@Component({ + standalone: true, + imports: [ThemedTestThemeableComponent], +}) +export class UsageComponent { +} +``` + + + diff --git a/lint/.gitignore b/lint/.gitignore new file mode 100644 index 00000000000..0d22081b3bc --- /dev/null +++ b/lint/.gitignore @@ -0,0 +1,3 @@ +/dist/ +/coverage/ +/node-modules/ diff --git a/lint/README.md b/lint/README.md new file mode 100644 index 00000000000..7251a35c06a --- /dev/null +++ b/lint/README.md @@ -0,0 +1,50 @@ +# DSpace ESLint plugins + +Custom ESLint rules for DSpace Angular peculiarities. + +## Usage + +These plugins are included with the rest of our ESLint configuration in [.eslintc.json](../.eslintrc.json). Individual rules can be configured or disabled there, like usual. +- In order for the new rules to be picked up by your IDE, you should first run `yarn build:lint` to build the plugins. +- This will also happen automatically each time `yarn lint` is run. + +## Documentation + +The rules are split up into plugins by language: +- [TypeScript rules](../docs/lint/ts/index.md) +- [HTML rules](../docs/lint/html/index.md) + +> Run `yarn docs:lint` to generate this documentation! + +## Developing + +### Overview + +- All rules are written in TypeScript and compiled into [`dist`](./dist) + - The plugins are linked into the main project dependencies from here + - These directories already contain the necessary `package.json` files to mark them as ESLint plugins +- Rule source files are structured, so they can be imported all in one go + - Each rule must export the following: + - `Messages`: an Enum of error message IDs + - `info`: metadata about this rule (name, description, messages, options, ...) + - `rule`: the implementation of the rule + - `tests`: the tests for this rule, as a set of valid/invalid code snippets. These snippets are used as example in the documentation. + - New rules should be added to their plugin's `index.ts` +- Some useful links + - [Developing ESLint plugins](https://eslint.org/docs/latest/extend/plugins) + - [Custom rules in typescript-eslint](https://typescript-eslint.io/developers/custom-rules) + - [Angular ESLint](https://github.com/angular-eslint/angular-eslint) + +### Parsing project metadata in advance ~ TypeScript AST + +While it is possible to retain persistent state between files during the linting process, it becomes quite complicated if the content of one file determines how we want to lint another file. +Because the two files may be linted out of order, we may not know whether the first file is wrong before we pass by the second. This means that we cannot report or fix the issue, because the first file is already detached from the linting context. + +For example, we cannot consistently determine which components are themeable (i.e. have a `ThemedComponent` wrapper) while linting. +To work around this issue, we construct a registry of themeable components _before_ linting anything. +- We don't have a good way to hook into the ESLint parser at this time +- Instead, we leverage the actual TypeScript AST parser + - Retrieve all `ThemedComponent` wrapper files by the pattern of their path (`themed-*.component.ts`) + - Determine the themed component they're linked to (by the actual type annotation/import path, since filenames are prone to errors) + - Store metadata describing these component pairs in a global registry that can be shared between rules +- This only needs to happen once, and only takes a fraction of a second (for ~100 themeable components) \ No newline at end of file diff --git a/lint/dist/src/rules/html/package.json b/lint/dist/src/rules/html/package.json new file mode 100644 index 00000000000..d3f310d23b9 --- /dev/null +++ b/lint/dist/src/rules/html/package.json @@ -0,0 +1,6 @@ +{ + "name": "eslint-plugin-dspace-angular-html", + "version": "0.0.0", + "main": "./index.js", + "private": true +} diff --git a/lint/dist/src/rules/ts/package.json b/lint/dist/src/rules/ts/package.json new file mode 100644 index 00000000000..f19e18756ac --- /dev/null +++ b/lint/dist/src/rules/ts/package.json @@ -0,0 +1,6 @@ +{ + "name": "eslint-plugin-dspace-angular-ts", + "version": "0.0.0", + "main": "./index.js", + "private": true +} diff --git a/lint/generate-docs.ts b/lint/generate-docs.ts new file mode 100644 index 00000000000..fb2bf53fb58 --- /dev/null +++ b/lint/generate-docs.ts @@ -0,0 +1,85 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ + +import { + existsSync, + mkdirSync, + readFileSync, + rmSync, + writeFileSync, +} from 'fs'; +import { join } from 'path'; + +import { default as htmlPlugin } from './src/rules/html'; +import { default as tsPlugin } from './src/rules/ts'; + +const templates = new Map(); + +function lazyEJS(path: string, data: object): string { + if (!templates.has(path)) { + templates.set(path, require('ejs').compile(readFileSync(path).toString())); + } + + return templates.get(path)(data).replace(/\r\n/g, '\n'); +} + +const docsDir = join('docs', 'lint'); +const tsDir = join(docsDir, 'ts'); +const htmlDir = join(docsDir, 'html'); + +if (existsSync(docsDir)) { + rmSync(docsDir, { recursive: true }); +} + +mkdirSync(join(tsDir, 'rules'), { recursive: true }); +mkdirSync(join(htmlDir, 'rules'), { recursive: true }); + +function template(name: string): string { + return join('lint', 'src', 'util', 'templates', name); +} + +// TypeScript docs +writeFileSync( + join(tsDir, 'index.md'), + lazyEJS(template('index.ejs'), { + plugin: tsPlugin, + rules: tsPlugin.index.map(rule => rule.info), + }), +); + +for (const rule of tsPlugin.index) { + writeFileSync( + join(tsDir, 'rules', rule.info.name + '.md'), + lazyEJS(template('rule.ejs'), { + plugin: tsPlugin, + rule: rule.info, + tests: rule.tests, + }), + ); +} + +// HTML docs +writeFileSync( + join(htmlDir, 'index.md'), + lazyEJS(template('index.ejs'), { + plugin: htmlPlugin, + rules: htmlPlugin.index.map(rule => rule.info), + }), +); + +for (const rule of htmlPlugin.index) { + writeFileSync( + join(htmlDir, 'rules', rule.info.name + '.md'), + lazyEJS(template('rule.ejs'), { + plugin: htmlPlugin, + rule: rule.info, + tests: rule.tests, + }), + ); +} + diff --git a/lint/jasmine.json b/lint/jasmine.json new file mode 100644 index 00000000000..dfacd41a96c --- /dev/null +++ b/lint/jasmine.json @@ -0,0 +1,7 @@ +{ + "spec_files": ["**/*.spec.js"], + "spec_dir": "lint/dist/test", + "helpers": [ + "./test/helpers.js" + ] +} diff --git a/lint/src/rules/html/index.ts b/lint/src/rules/html/index.ts new file mode 100644 index 00000000000..7c1370ae2d4 --- /dev/null +++ b/lint/src/rules/html/index.ts @@ -0,0 +1,22 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +/* eslint-disable import/no-namespace */ +import { + bundle, + RuleExports, +} from '../../util/structure'; +import * as themedComponentUsages from './themed-component-usages'; + +const index = [ + themedComponentUsages, +] as unknown as RuleExports[]; + +export = { + parser: require('@angular-eslint/template-parser'), + ...bundle('dspace-angular-html', 'HTML', index), +}; diff --git a/lint/src/rules/html/themed-component-usages.ts b/lint/src/rules/html/themed-component-usages.ts new file mode 100644 index 00000000000..0b9a13456a6 --- /dev/null +++ b/lint/src/rules/html/themed-component-usages.ts @@ -0,0 +1,191 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +import { TmplAstElement } from '@angular-eslint/bundled-angular-compiler'; +import { TemplateParserServices } from '@angular-eslint/utils'; +import { + ESLintUtils, + TSESLint, +} from '@typescript-eslint/utils'; + +import { fixture } from '../../../test/fixture'; +import { + DSpaceESLintRuleInfo, + NamedTests, +} from '../../util/structure'; +import { + DISALLOWED_THEME_SELECTORS, + fixSelectors, +} from '../../util/theme-support'; +import { + getFilename, + getSourceCode, +} from '../../util/typescript'; + +export enum Message { + WRONG_SELECTOR = 'mustUseThemedWrapperSelector', +} + +export const info = { + name: 'themed-component-usages', + meta: { + docs: { + description: `Themeable components should be used via the selector of their \`ThemedComponent\` wrapper class + +This ensures that custom themes can correctly override _all_ instances of this component. +The only exception to this rule are unit tests, where we may want to use the base component in order to keep the test setup simple. + `, + }, + type: 'problem', + fixable: 'code', + schema: [], + messages: { + [Message.WRONG_SELECTOR]: 'Themeable components should be used via their ThemedComponent wrapper\'s selector', + }, + }, + defaultOptions: [], +} as DSpaceESLintRuleInfo; + +export const rule = ESLintUtils.RuleCreator.withoutDocs({ + ...info, + create(context: TSESLint.RuleContext) { + if (getFilename(context).includes('.spec.ts')) { + // skip inline templates in unit tests + return {}; + } + + const parserServices = getSourceCode(context).parserServices as TemplateParserServices; + + return { + [`Element$1[name = /^${DISALLOWED_THEME_SELECTORS}/]`](node: TmplAstElement) { + const { startSourceSpan, endSourceSpan } = node; + const openStart = startSourceSpan.start.offset as number; + + context.report({ + messageId: Message.WRONG_SELECTOR, + loc: parserServices.convertNodeSourceSpanToLoc(startSourceSpan), + fix(fixer) { + const oldSelector = node.name; + const newSelector = fixSelectors(oldSelector); + + const ops = [ + fixer.replaceTextRange([openStart + 1, openStart + 1 + oldSelector.length], newSelector), + ]; + + // make sure we don't mangle self-closing tags + if (endSourceSpan !== null && startSourceSpan.end.offset !== endSourceSpan.end.offset) { + const closeStart = endSourceSpan.start.offset as number; + const closeEnd = endSourceSpan.end.offset as number; + + ops.push(fixer.replaceTextRange([closeStart + 2, closeEnd - 1], newSelector)); + } + + return ops; + }, + }); + }, + }; + }, +}); + +export const tests = { + plugin: info.name, + valid: [ + { + name: 'use no-prefix selectors in HTML templates', + code: ` + + + + `, + }, + { + name: 'use no-prefix selectors in TypeScript templates', + code: ` +@Component({ + template: '' +}) +class Test { +} + `, + }, + { + name: 'use no-prefix selectors in TypeScript test templates', + filename: fixture('src/test.spec.ts'), + code: ` +@Component({ + template: '' +}) +class Test { +} + `, + }, + { + name: 'base selectors are also allowed in TypeScript test templates', + filename: fixture('src/test.spec.ts'), + code: ` +@Component({ + template: '' +}) +class Test { +} + `, + }, + ], + invalid: [ + { + name: 'themed override selectors are not allowed in HTML templates', + code: ` + + + + `, + errors: [ + { + messageId: Message.WRONG_SELECTOR, + }, + { + messageId: Message.WRONG_SELECTOR, + }, + { + messageId: Message.WRONG_SELECTOR, + }, + ], + output: ` + + + + `, + }, + { + name: 'base selectors are not allowed in HTML templates', + code: ` + + + + `, + errors: [ + { + messageId: Message.WRONG_SELECTOR, + }, + { + messageId: Message.WRONG_SELECTOR, + }, + { + messageId: Message.WRONG_SELECTOR, + }, + ], + output: ` + + + + `, + }, + ], +} as NamedTests; + +export default rule; diff --git a/lint/src/rules/ts/index.ts b/lint/src/rules/ts/index.ts new file mode 100644 index 00000000000..a7fdfe41efe --- /dev/null +++ b/lint/src/rules/ts/index.ts @@ -0,0 +1,25 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +import { + bundle, + RuleExports, +} from '../../util/structure'; +/* eslint-disable import/no-namespace */ +import * as themedComponentClasses from './themed-component-classes'; +import * as themedComponentSelectors from './themed-component-selectors'; +import * as themedComponentUsages from './themed-component-usages'; + +const index = [ + themedComponentClasses, + themedComponentSelectors, + themedComponentUsages, +] as unknown as RuleExports[]; + +export = { + ...bundle('dspace-angular-ts', 'TypeScript', index), +}; diff --git a/lint/src/rules/ts/themed-component-classes.ts b/lint/src/rules/ts/themed-component-classes.ts new file mode 100644 index 00000000000..66c37395b4c --- /dev/null +++ b/lint/src/rules/ts/themed-component-classes.ts @@ -0,0 +1,382 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +import { + ESLintUtils, + TSESLint, + TSESTree, +} from '@typescript-eslint/utils'; + +import { fixture } from '../../../test/fixture'; +import { + getComponentImportNode, + getComponentInitializer, + getComponentStandaloneNode, +} from '../../util/angular'; +import { appendObjectProperties } from '../../util/fix'; +import { DSpaceESLintRuleInfo } from '../../util/structure'; +import { + getBaseComponentClassName, + inThemedComponentOverrideFile, + isThemeableComponent, + isThemedComponentWrapper, +} from '../../util/theme-support'; +import { getFilename } from '../../util/typescript'; + +export enum Message { + NOT_STANDALONE = 'mustBeStandalone', + NOT_STANDALONE_IMPORTS_BASE = 'mustBeStandaloneAndImportBase', + WRAPPER_IMPORTS_BASE = 'wrapperShouldImportBase', +} + +export const info = { + name: 'themed-component-classes', + meta: { + docs: { + description: `Formatting rules for themeable component classes + +- All themeable components must be standalone. +- The base component must always be imported in the \`ThemedComponent\` wrapper. This ensures that it is always sufficient to import just the wrapper whenever we use the component. + `, + }, + type: 'problem', + fixable: 'code', + schema: [], + messages: { + [Message.NOT_STANDALONE]: 'Themeable components must be standalone', + [Message.NOT_STANDALONE_IMPORTS_BASE]: 'Themeable component wrapper classes must be standalone and import the base class', + [Message.WRAPPER_IMPORTS_BASE]: 'Themed component wrapper classes must only import the base class', + }, + }, + defaultOptions: [], +} as DSpaceESLintRuleInfo; + +export const rule = ESLintUtils.RuleCreator.withoutDocs({ + ...info, + create(context: TSESLint.RuleContext) { + const filename = getFilename(context); + + if (filename.endsWith('.spec.ts')) { + return {}; + } + + function enforceStandalone(decoratorNode: TSESTree.Decorator, withBaseImport = false) { + const standaloneNode = getComponentStandaloneNode(decoratorNode); + + if (standaloneNode === undefined) { + // We may need to add these properties in one go + if (!withBaseImport) { + context.report({ + messageId: Message.NOT_STANDALONE, + node: decoratorNode, + fix(fixer) { + const initializer = getComponentInitializer(decoratorNode); + return appendObjectProperties(context, fixer, initializer, ['standalone: true']); + }, + }); + } + } else if (!standaloneNode.value) { + context.report({ + messageId: Message.NOT_STANDALONE, + node: standaloneNode, + fix(fixer) { + return fixer.replaceText(standaloneNode, 'true'); + }, + }); + } + + if (withBaseImport) { + const baseClass = getBaseComponentClassName(decoratorNode); + + if (baseClass === undefined) { + return; + } + + const importsNode = getComponentImportNode(decoratorNode); + + if (importsNode === undefined) { + if (standaloneNode === undefined) { + context.report({ + messageId: Message.NOT_STANDALONE_IMPORTS_BASE, + node: decoratorNode, + fix(fixer) { + const initializer = getComponentInitializer(decoratorNode); + return appendObjectProperties(context, fixer, initializer, ['standalone: true', `imports: [${baseClass}]`]); + }, + }); + } else { + context.report({ + messageId: Message.WRAPPER_IMPORTS_BASE, + node: decoratorNode, + fix(fixer) { + const initializer = getComponentInitializer(decoratorNode); + return appendObjectProperties(context, fixer, initializer, [`imports: [${baseClass}]`]); + }, + }); + } + } else { + // If we have an imports node, standalone: true will be enforced by another rule + + const imports = importsNode.elements.map(e => (e as TSESTree.Identifier).name); + + if (!imports.includes(baseClass) || imports.length > 1) { + // The wrapper should _only_ import the base component + context.report({ + messageId: Message.WRAPPER_IMPORTS_BASE, + node: importsNode, + fix(fixer) { + // todo: this may leave unused imports, but that's better than mangling things + return fixer.replaceText(importsNode, `[${baseClass}]`); + }, + }); + } + } + } + } + + return { + 'ClassDeclaration > Decorator[expression.callee.name = "Component"]'(node: TSESTree.Decorator) { + const classNode = node.parent as TSESTree.ClassDeclaration; + const className = classNode.id?.name; + + if (className === undefined) { + return; + } + + if (isThemedComponentWrapper(node)) { + enforceStandalone(node, true); + } else if (inThemedComponentOverrideFile(filename)) { + enforceStandalone(node); + } else if (isThemeableComponent(className)) { + enforceStandalone(node); + } + }, + }; + }, +}); + +export const tests = { + plugin: info.name, + valid: [ + { + name: 'Regular non-themeable component', + code: ` +@Component({ + selector: 'ds-something', + standalone: true, +}) +class Something { +} + `, + }, + { + name: 'Base component', + code: ` +@Component({ + selector: 'ds-base-test-themable', + standalone: true, +}) +class TestThemeableTomponent { +} + `, + }, + { + name: 'Wrapper component', + filename: fixture('src/app/test/themed-test-themeable.component.ts'), + code: ` +@Component({ + selector: 'ds-test-themable', + standalone: true, + imports: [ + TestThemeableComponent, + ], +}) +class ThemedTestThemeableTomponent extends ThemedComponent { +} + `, + }, + { + name: 'Override component', + filename: fixture('src/themes/test/app/test/test-themeable.component.ts'), + code: ` +@Component({ + selector: 'ds-themed-test-themable', + standalone: true, +}) +class Override extends BaseComponent { +} + `, + }, + ], + invalid: [ + { + name: 'Base component must be standalone', + code: ` +@Component({ + selector: 'ds-base-test-themable', +}) +class TestThemeableComponent { +} + `, + errors:[ + { + messageId: Message.NOT_STANDALONE, + }, + ], + output: ` +@Component({ + selector: 'ds-base-test-themable', + standalone: true, +}) +class TestThemeableComponent { +} + `, + }, + { + name: 'Wrapper component must be standalone and import base component', + filename: fixture('src/app/test/themed-test-themeable.component.ts'), + code: ` +@Component({ + selector: 'ds-test-themable', +}) +class ThemedTestThemeableComponent extends ThemedComponent { +} + `, + errors:[ + { + messageId: Message.NOT_STANDALONE_IMPORTS_BASE, + }, + ], + output: ` +@Component({ + selector: 'ds-test-themable', + standalone: true, + imports: [TestThemeableComponent], +}) +class ThemedTestThemeableComponent extends ThemedComponent { +} + `, + }, + + { + name: 'Wrapper component must import base component (array present but empty)', + filename: fixture('src/app/test/themed-test-themeable.component.ts'), + code: ` +@Component({ + selector: 'ds-test-themable', + standalone: true, + imports: [], +}) +class ThemedTestThemeableComponent extends ThemedComponent { +} + `, + errors:[ + { + messageId: Message.WRAPPER_IMPORTS_BASE, + }, + ], + output: ` +@Component({ + selector: 'ds-test-themable', + standalone: true, + imports: [TestThemeableComponent], +}) +class ThemedTestThemeableComponent extends ThemedComponent { +} + `, + }, + { + name: 'Wrapper component must import base component (array is wrong)', + filename: fixture('src/app/test/themed-test-themeable.component.ts'), + code: ` +import { SomethingElse } from './somewhere-else'; + +@Component({ + selector: 'ds-test-themable', + standalone: true, + imports: [ + SomethingElse, + ], +}) +class ThemedTestThemeableComponent extends ThemedComponent { +} + `, + errors:[ + { + messageId: Message.WRAPPER_IMPORTS_BASE, + }, + ], + output: ` +import { SomethingElse } from './somewhere-else'; + +@Component({ + selector: 'ds-test-themable', + standalone: true, + imports: [TestThemeableComponent], +}) +class ThemedTestThemeableComponent extends ThemedComponent { +} + `, + }, { + name: 'Wrapper component must import base component (array is wrong)', + filename: fixture('src/app/test/themed-test-themeable.component.ts'), + code: ` +import { Something, SomethingElse } from './somewhere-else'; + +@Component({ + selector: 'ds-test-themable', + standalone: true, + imports: [ + SomethingElse, + ], +}) +class ThemedTestThemeableComponent extends ThemedComponent { +} + `, + errors:[ + { + messageId: Message.WRAPPER_IMPORTS_BASE, + }, + ], + output: ` +import { Something, SomethingElse } from './somewhere-else'; + +@Component({ + selector: 'ds-test-themable', + standalone: true, + imports: [TestThemeableComponent], +}) +class ThemedTestThemeableComponent extends ThemedComponent { +} + `, + }, + { + name: 'Override component must be standalone', + filename: fixture('src/themes/test/app/test/test-themeable.component.ts'), + code: ` +@Component({ + selector: 'ds-themed-test-themable', +}) +class Override extends BaseComponent { +} + `, + errors:[ + { + messageId: Message.NOT_STANDALONE, + }, + ], + output: ` +@Component({ + selector: 'ds-themed-test-themable', + standalone: true, +}) +class Override extends BaseComponent { +} + `, + }, + ], +}; diff --git a/lint/src/rules/ts/themed-component-selectors.ts b/lint/src/rules/ts/themed-component-selectors.ts new file mode 100644 index 00000000000..e06f5ababf6 --- /dev/null +++ b/lint/src/rules/ts/themed-component-selectors.ts @@ -0,0 +1,257 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +import { + ESLintUtils, + TSESLint, + TSESTree, +} from '@typescript-eslint/utils'; + +import { fixture } from '../../../test/fixture'; +import { getComponentSelectorNode } from '../../util/angular'; +import { stringLiteral } from '../../util/misc'; +import { DSpaceESLintRuleInfo } from '../../util/structure'; +import { + inThemedComponentOverrideFile, + isThemeableComponent, + isThemedComponentWrapper, +} from '../../util/theme-support'; +import { getFilename } from '../../util/typescript'; + +export enum Message { + BASE = 'wrongSelectorUnthemedComponent', + WRAPPER = 'wrongSelectorThemedComponentWrapper', + THEMED = 'wrongSelectorThemedComponentOverride', +} + +export const info = { + name: 'themed-component-selectors', + meta: { + docs: { + description: `Themeable component selectors should follow the DSpace convention + +Each themeable component is comprised of a base component, a wrapper component and any number of themed components +- Base components should have a selector starting with \`ds-base-\` +- Themed components should have a selector starting with \`ds-themed-\` +- Wrapper components should have a selector starting with \`ds-\`, but not \`ds-base-\` or \`ds-themed-\` + - This is the regular DSpace selector prefix + - **When making a regular component themeable, its selector prefix should be changed to \`ds-base-\`, and the new wrapper's component should reuse the previous selector** + +Unit tests are exempt from this rule, because they may redefine components using the same class name as other themeable components elsewhere in the source. + `, + }, + type: 'problem', + schema: [], + fixable: 'code', + messages: { + [Message.BASE]: 'Unthemed version of themeable component should have a selector starting with \'ds-base-\'', + [Message.WRAPPER]: 'Themed component wrapper of themeable component shouldn\'t have a selector starting with \'ds-themed-\'', + [Message.THEMED]: 'Theme override of themeable component should have a selector starting with \'ds-themed-\'', + }, + }, + defaultOptions: [], +} as DSpaceESLintRuleInfo; + +export const rule = ESLintUtils.RuleCreator.withoutDocs({ + ...info, + create(context: TSESLint.RuleContext) { + const filename = getFilename(context); + + if (filename.endsWith('.spec.ts')) { + return {}; + } + + function enforceWrapperSelector(selectorNode: TSESTree.StringLiteral) { + if (selectorNode?.value.startsWith('ds-themed-')) { + context.report({ + messageId: Message.WRAPPER, + node: selectorNode, + fix(fixer) { + return fixer.replaceText(selectorNode, stringLiteral(selectorNode.value.replace('ds-themed-', 'ds-'))); + }, + }); + } + } + + function enforceBaseSelector(selectorNode: TSESTree.StringLiteral) { + if (!selectorNode?.value.startsWith('ds-base-')) { + context.report({ + messageId: Message.BASE, + node: selectorNode, + fix(fixer) { + return fixer.replaceText(selectorNode, stringLiteral(selectorNode.value.replace('ds-', 'ds-base-'))); + }, + }); + } + } + + function enforceThemedSelector(selectorNode: TSESTree.StringLiteral) { + if (!selectorNode?.value.startsWith('ds-themed-')) { + context.report({ + messageId: Message.THEMED, + node: selectorNode, + fix(fixer) { + return fixer.replaceText(selectorNode, stringLiteral(selectorNode.value.replace('ds-', 'ds-themed-'))); + }, + }); + } + } + + return { + 'ClassDeclaration > Decorator[expression.callee.name = "Component"]'(node: TSESTree.Decorator) { + const selectorNode = getComponentSelectorNode(node); + + if (selectorNode === undefined) { + return; + } + + const selector = selectorNode?.value; + const classNode = node.parent as TSESTree.ClassDeclaration; + const className = classNode.id?.name; + + if (selector === undefined || className === undefined) { + return; + } + + if (isThemedComponentWrapper(node)) { + enforceWrapperSelector(selectorNode); + } else if (inThemedComponentOverrideFile(filename)) { + enforceThemedSelector(selectorNode); + } else if (isThemeableComponent(className)) { + enforceBaseSelector(selectorNode); + } + }, + }; + }, +}); + +export const tests = { + plugin: info.name, + valid: [ + { + name: 'Regular non-themeable component selector', + code: ` +@Component({ + selector: 'ds-something', +}) +class Something { +} + `, + }, + { + name: 'Themeable component selector should replace the original version, unthemed version should be changed to ds-base-', + code: ` +@Component({ + selector: 'ds-base-something', +}) +class Something { +} + +@Component({ + selector: 'ds-something', +}) +class ThemedSomething extends ThemedComponent { +} + +@Component({ + selector: 'ds-themed-something', +}) +class OverrideSomething extends Something { +} + `, + }, + { + name: 'Other themed component wrappers should not interfere', + code: ` +@Component({ + selector: 'ds-something', +}) +class Something { +} + +@Component({ + selector: 'ds-something-else', +}) +class ThemedSomethingElse extends ThemedComponent { +} + `, + }, + ], + invalid: [ + { + name: 'Wrong selector for base component', + filename: fixture('src/app/test/test-themeable.component.ts'), + code: ` +@Component({ + selector: 'ds-something', +}) +class TestThemeableComponent { +} + `, + errors: [ + { + messageId: Message.BASE, + }, + ], + output: ` +@Component({ + selector: 'ds-base-something', +}) +class TestThemeableComponent { +} + `, + }, + { + name: 'Wrong selector for wrapper component', + filename: fixture('src/app/test/themed-test-themeable.component.ts'), + code: ` +@Component({ + selector: 'ds-themed-something', +}) +class ThemedTestThemeableComponent extends ThemedComponent { +} + `, + errors: [ + { + messageId: Message.WRAPPER, + }, + ], + output: ` +@Component({ + selector: 'ds-something', +}) +class ThemedTestThemeableComponent extends ThemedComponent { +} + `, + }, + { + name: 'Wrong selector for theme override', + filename: fixture('src/themes/test/app/test/test-themeable.component.ts'), + code: ` +@Component({ + selector: 'ds-something', +}) +class TestThememeableComponent extends BaseComponent { +} + `, + errors: [ + { + messageId: Message.THEMED, + }, + ], + output: ` +@Component({ + selector: 'ds-themed-something', +}) +class TestThememeableComponent extends BaseComponent { +} + `, + }, + ], +}; + +export default rule; diff --git a/lint/src/rules/ts/themed-component-usages.ts b/lint/src/rules/ts/themed-component-usages.ts new file mode 100644 index 00000000000..96e9962ccf7 --- /dev/null +++ b/lint/src/rules/ts/themed-component-usages.ts @@ -0,0 +1,502 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +import { + ESLintUtils, + TSESLint, + TSESTree, +} from '@typescript-eslint/utils'; + +import { fixture } from '../../../test/fixture'; +import { + removeWithCommas, + replaceOrRemoveArrayIdentifier, +} from '../../util/fix'; +import { DSpaceESLintRuleInfo } from '../../util/structure'; +import { + allThemeableComponents, + DISALLOWED_THEME_SELECTORS, + fixSelectors, + getThemeableComponentByBaseClass, + isAllowedUnthemedUsage, +} from '../../util/theme-support'; +import { + findImportSpecifier, + findUsages, + findUsagesByName, + getFilename, + relativePath, +} from '../../util/typescript'; + +export enum Message { + WRONG_CLASS = 'mustUseThemedWrapperClass', + WRONG_IMPORT = 'mustImportThemedWrapper', + WRONG_SELECTOR = 'mustUseThemedWrapperSelector', + BASE_IN_MODULE = 'baseComponentNotNeededInModule', +} + +export const info = { + name: 'themed-component-usages', + meta: { + docs: { + description: `Themeable components should be used via their \`ThemedComponent\` wrapper class + +This ensures that custom themes can correctly override _all_ instances of this component. +There are a few exceptions where the base class can still be used: +- Class declaration expressions (otherwise we can't declare, extend or override the class in the first place) +- Angular modules (except for routing modules) +- Angular \`@ViewChild\` decorators +- Type annotations + `, + }, + type: 'problem', + schema: [], + fixable: 'code', + messages: { + [Message.WRONG_CLASS]: 'Themeable components should be used via their ThemedComponent wrapper', + [Message.WRONG_IMPORT]: 'Themeable components should be used via their ThemedComponent wrapper', + [Message.WRONG_SELECTOR]: 'Themeable components should be used via their ThemedComponent wrapper', + [Message.BASE_IN_MODULE]: 'Base themeable components shouldn\'t be declared in modules', + }, + }, + defaultOptions: [], +} as DSpaceESLintRuleInfo; + +export const rule = ESLintUtils.RuleCreator.withoutDocs({ + ...info, + create(context: TSESLint.RuleContext) { + const filename = getFilename(context); + + function handleUnthemedUsagesInTypescript(node: TSESTree.Identifier) { + if (isAllowedUnthemedUsage(node)) { + return; + } + + const entry = getThemeableComponentByBaseClass(node.name); + + if (entry === undefined) { + // this should never happen + throw new Error(`No such themeable component in registry: '${node.name}'`); + } + + context.report({ + messageId: Message.WRONG_CLASS, + node: node, + fix(fixer) { + if (node.parent.type === TSESTree.AST_NODE_TYPES.ArrayExpression) { + return replaceOrRemoveArrayIdentifier(context, fixer, node, entry.wrapperClass); + } else { + return fixer.replaceText(node, entry.wrapperClass); + } + }, + }); + } + + function handleThemedSelectorQueriesInTests(node: TSESTree.Literal) { + context.report({ + node, + messageId: Message.WRONG_SELECTOR, + fix(fixer){ + const newSelector = fixSelectors(node.raw); + return fixer.replaceText(node, newSelector); + }, + }); + } + + function handleUnthemedImportsInTypescript(specifierNode: TSESTree.ImportSpecifier) { + const allUsages = findUsages(context, specifierNode.local); + const badUsages = allUsages.filter(usage => !isAllowedUnthemedUsage(usage)); + + if (badUsages.length === 0) { + return; + } + + const importedNode = specifierNode.imported; + const declarationNode = specifierNode.parent as TSESTree.ImportDeclaration; + + const entry = getThemeableComponentByBaseClass(importedNode.name); + if (entry === undefined) { + // this should never happen + throw new Error(`No such themeable component in registry: '${importedNode.name}'`); + } + + context.report({ + messageId: Message.WRONG_IMPORT, + node: importedNode, + fix(fixer) { + const ops = []; + + const wrapperImport = findImportSpecifier(context, entry.wrapperClass); + + if (findUsagesByName(context, entry.wrapperClass).length === 0) { + // Wrapper is not present in this file, safe to add import + + const newImportLine = `import { ${entry.wrapperClass} } from '${relativePath(filename, entry.wrapperPath)}';`; + + if (declarationNode.specifiers.length === 1) { + if (allUsages.length === badUsages.length) { + ops.push(fixer.replaceText(declarationNode, newImportLine)); + } else if (wrapperImport === undefined) { + ops.push(fixer.insertTextAfter(declarationNode, '\n' + newImportLine)); + } + } else { + ops.push(...removeWithCommas(context, fixer, specifierNode)); + if (wrapperImport === undefined) { + ops.push(fixer.insertTextAfter(declarationNode, '\n' + newImportLine)); + } + } + } else { + // Wrapper already present in the file, remove import instead + + if (allUsages.length === badUsages.length) { + if (declarationNode.specifiers.length === 1) { + // Make sure we remove the newline as well + ops.push(fixer.removeRange([declarationNode.range[0], declarationNode.range[1] + 1])); + } else { + ops.push(...removeWithCommas(context, fixer, specifierNode)); + } + } + } + + return ops; + }, + }); + } + + // ignore tests and non-routing modules + if (filename.endsWith('.spec.ts')) { + return { + [`CallExpression[callee.object.name = "By"][callee.property.name = "css"] > Literal:first-child[value = /.*${DISALLOWED_THEME_SELECTORS}.*/]`]: handleThemedSelectorQueriesInTests, + }; + } else if (filename.endsWith('.cy.ts')) { + return { + [`CallExpression[callee.object.name = "cy"][callee.property.name = "get"] > Literal:first-child[value = /.*${DISALLOWED_THEME_SELECTORS}.*/]`]: handleThemedSelectorQueriesInTests, + }; + } else if ( + filename.match(/(?!src\/themes\/).*(?!routing).module.ts$/) + || filename.match(/themed-.+\.component\.ts$/) + ) { + // do nothing + return {}; + } else { + return allThemeableComponents().reduce( + (rules, entry) => { + return { + ...rules, + [`:not(:matches(ClassDeclaration, ImportSpecifier)) > Identifier[name = "${entry.baseClass}"]`]: handleUnthemedUsagesInTypescript, + [`ImportSpecifier[imported.name = "${entry.baseClass}"]`]: handleUnthemedImportsInTypescript, + }; + }, {}, + ); + } + + }, +}); + +export const tests = { + plugin: info.name, + valid: [ + { + name: 'allow wrapper class usages', + code: ` +import { ThemedTestThemeableComponent } from './app/test/themed-test-themeable.component'; + +const config = { + a: ThemedTestThemeableComponent, + b: ChipsComponent, +} + `, + }, + { + name: 'allow base class in class declaration', + code: ` +export class TestThemeableComponent { +} + `, + }, + { + name: 'allow inheriting from base class', + code: ` +import { TestThemeableComponent } from './app/test/test-themeable.component'; + +export class ThemedAdminSidebarComponent extends ThemedComponent { +} + `, + }, + { + name: 'allow base class in ViewChild', + code: ` +import { TestThemeableComponent } from './app/test/test-themeable.component'; + +export class Something { + @ViewChild(TestThemeableComponent) test: TestThemeableComponent; +} + `, + }, + { + name: 'allow wrapper selectors in test queries', + filename: fixture('src/app/test/test.component.spec.ts'), + code: ` +By.css('ds-themeable'); +By.css('#test > ds-themeable > #nest'); + `, + }, + { + name: 'allow wrapper selectors in cypress queries', + filename: fixture('src/app/test/test.component.cy.ts'), + code: ` +By.css('ds-themeable'); +By.css('#test > ds-themeable > #nest'); + `, + }, + ], + invalid: [ + { + name: 'disallow direct usages of base class', + code: ` +import { TestThemeableComponent } from './app/test/test-themeable.component'; +import { TestComponent } from './app/test/test.component'; + +const config = { + a: TestThemeableComponent, + b: TestComponent, +} + `, + errors: [ + { + messageId: Message.WRONG_IMPORT, + }, + { + messageId: Message.WRONG_CLASS, + }, + ], + output: ` +import { ThemedTestThemeableComponent } from './app/test/themed-test-themeable.component'; +import { TestComponent } from './app/test/test.component'; + +const config = { + a: ThemedTestThemeableComponent, + b: TestComponent, +} + `, + }, + { + name: 'disallow direct usages of base class, keep other imports', + code: ` +import { Something, TestThemeableComponent } from './app/test/test-themeable.component'; +import { TestComponent } from './app/test/test.component'; + +const config = { + a: TestThemeableComponent, + b: TestComponent, + c: Something, +} + `, + errors: [ + { + messageId: Message.WRONG_IMPORT, + }, + { + messageId: Message.WRONG_CLASS, + }, + ], + output: ` +import { Something } from './app/test/test-themeable.component'; +import { ThemedTestThemeableComponent } from './app/test/themed-test-themeable.component'; +import { TestComponent } from './app/test/test.component'; + +const config = { + a: ThemedTestThemeableComponent, + b: TestComponent, + c: Something, +} + `, + }, + { + name: 'handle array replacements correctly', + code: ` +const DECLARATIONS = [ + Something, + TestThemeableComponent, + Something, + ThemedTestThemeableComponent, +]; + `, + errors: [ + { + messageId: Message.WRONG_CLASS, + }, + ], + output: ` +const DECLARATIONS = [ + Something, + Something, + ThemedTestThemeableComponent, +]; + `, + }, + { + name: 'disallow override selector in test queries', + filename: fixture('src/app/test/test.component.spec.ts'), + code: ` +By.css('ds-themed-themeable'); +By.css('#test > ds-themed-themeable > #nest'); + `, + errors: [ + { + messageId: Message.WRONG_SELECTOR, + }, + { + messageId: Message.WRONG_SELECTOR, + }, + ], + output: ` +By.css('ds-themeable'); +By.css('#test > ds-themeable > #nest'); + `, + }, + { + name: 'disallow base selector in test queries', + filename: fixture('src/app/test/test.component.spec.ts'), + code: ` +By.css('ds-base-themeable'); +By.css('#test > ds-base-themeable > #nest'); + `, + errors: [ + { + messageId: Message.WRONG_SELECTOR, + }, + { + messageId: Message.WRONG_SELECTOR, + }, + ], + output: ` +By.css('ds-themeable'); +By.css('#test > ds-themeable > #nest'); + `, + }, + { + name: 'disallow override selector in cypress queries', + filename: fixture('src/app/test/test.component.cy.ts'), + code: ` +cy.get('ds-themed-themeable'); +cy.get('#test > ds-themed-themeable > #nest'); + `, + errors: [ + { + messageId: Message.WRONG_SELECTOR, + }, + { + messageId: Message.WRONG_SELECTOR, + }, + ], + output: ` +cy.get('ds-themeable'); +cy.get('#test > ds-themeable > #nest'); + `, + }, + { + name: 'disallow base selector in cypress queries', + filename: fixture('src/app/test/test.component.cy.ts'), + code: ` +cy.get('ds-base-themeable'); +cy.get('#test > ds-base-themeable > #nest'); + `, + errors: [ + { + messageId: Message.WRONG_SELECTOR, + }, + { + messageId: Message.WRONG_SELECTOR, + }, + ], + output: ` +cy.get('ds-themeable'); +cy.get('#test > ds-themeable > #nest'); + `, + }, + { + name: 'edge case: unable to find usage node through usage token, but import is still flagged and fixed', + filename: fixture('src/themes/test/app/test/other-themeable.component.ts'), + code: ` +import { Component } from '@angular/core'; + +import { Context } from './app/core/shared/context.model'; +import { TestThemeableComponent } from '../../../../app/test/test-themeable.component'; + +@Component({ + standalone: true, + imports: [TestThemeableComponent], +}) +export class UsageComponent { +} + `, + errors: [ + { + messageId: Message.WRONG_IMPORT, + }, + { + messageId: Message.WRONG_CLASS, + }, + ], + output: ` +import { Component } from '@angular/core'; + +import { Context } from './app/core/shared/context.model'; +import { ThemedTestThemeableComponent } from '../../../../app/test/themed-test-themeable.component'; + +@Component({ + standalone: true, + imports: [ThemedTestThemeableComponent], +}) +export class UsageComponent { +} + `, + }, + { + name: 'edge case edge case: both are imported, only wrapper is retained', + filename: fixture('src/themes/test/app/test/other-themeable.component.ts'), + code: ` +import { Component } from '@angular/core'; + +import { Context } from './app/core/shared/context.model'; +import { TestThemeableComponent } from '../../../../app/test/test-themeable.component'; +import { ThemedTestThemeableComponent } from '../../../../app/test/themed-test-themeable.component'; + +@Component({ + standalone: true, + imports: [TestThemeableComponent, ThemedTestThemeableComponent], +}) +export class UsageComponent { +} + `, + errors: [ + { + messageId: Message.WRONG_IMPORT, + }, + { + messageId: Message.WRONG_CLASS, + }, + ], + output: ` +import { Component } from '@angular/core'; + +import { Context } from './app/core/shared/context.model'; +import { ThemedTestThemeableComponent } from '../../../../app/test/themed-test-themeable.component'; + +@Component({ + standalone: true, + imports: [ThemedTestThemeableComponent], +}) +export class UsageComponent { +} + `, + }, + ], +}; + +export default rule; diff --git a/lint/src/util/angular.ts b/lint/src/util/angular.ts new file mode 100644 index 00000000000..70ee903fb81 --- /dev/null +++ b/lint/src/util/angular.ts @@ -0,0 +1,83 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +import { TSESTree } from '@typescript-eslint/utils'; + +import { getObjectPropertyNodeByName } from './typescript'; + +export function getComponentSelectorNode(componentDecoratorNode: TSESTree.Decorator): TSESTree.StringLiteral | undefined { + const property = getComponentInitializerNodeByName(componentDecoratorNode, 'selector'); + + if (property !== undefined) { + // todo: support template literals as well + if (property.type === TSESTree.AST_NODE_TYPES.Literal && typeof property.value === 'string') { + return property as TSESTree.StringLiteral; + } + } + + return undefined; +} + +export function getComponentStandaloneNode(componentDecoratorNode: TSESTree.Decorator): TSESTree.BooleanLiteral | undefined { + const property = getComponentInitializerNodeByName(componentDecoratorNode, 'standalone'); + + if (property !== undefined) { + if (property.type === TSESTree.AST_NODE_TYPES.Literal && typeof property.value === 'boolean') { + return property as TSESTree.BooleanLiteral; + } + } + + return undefined; +} +export function getComponentImportNode(componentDecoratorNode: TSESTree.Decorator): TSESTree.ArrayExpression | undefined { + const property = getComponentInitializerNodeByName(componentDecoratorNode, 'imports'); + + if (property !== undefined) { + if (property.type === TSESTree.AST_NODE_TYPES.ArrayExpression) { + return property as TSESTree.ArrayExpression; + } + } + + return undefined; +} + +export function getComponentClassName(decoratorNode: TSESTree.Decorator): string | undefined { + if (decoratorNode.parent.type !== TSESTree.AST_NODE_TYPES.ClassDeclaration) { + return undefined; + } + + if (decoratorNode.parent.id?.type !== TSESTree.AST_NODE_TYPES.Identifier) { + return undefined; + } + + return decoratorNode.parent.id.name; +} + +export function getComponentSuperClassName(decoratorNode: TSESTree.Decorator): string | undefined { + if (decoratorNode.parent.type !== TSESTree.AST_NODE_TYPES.ClassDeclaration) { + return undefined; + } + + if (decoratorNode.parent.superClass?.type !== TSESTree.AST_NODE_TYPES.Identifier) { + return undefined; + } + + return decoratorNode.parent.superClass.name; +} + +export function getComponentInitializer(componentDecoratorNode: TSESTree.Decorator): TSESTree.ObjectExpression { + return (componentDecoratorNode.expression as TSESTree.CallExpression).arguments[0] as TSESTree.ObjectExpression; +} + +export function getComponentInitializerNodeByName(componentDecoratorNode: TSESTree.Decorator, name: string): TSESTree.Node | undefined { + const initializer = getComponentInitializer(componentDecoratorNode); + return getObjectPropertyNodeByName(initializer, name); +} + +export function isPartOfViewChild(node: TSESTree.Identifier): boolean { + return (node.parent as any)?.callee?.name === 'ViewChild'; +} diff --git a/lint/src/util/fix.ts b/lint/src/util/fix.ts new file mode 100644 index 00000000000..10408cc316c --- /dev/null +++ b/lint/src/util/fix.ts @@ -0,0 +1,125 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +import { TSESTree } from '@typescript-eslint/utils'; +import { + RuleContext, + RuleFix, + RuleFixer, +} from '@typescript-eslint/utils/ts-eslint'; + +import { getSourceCode } from './typescript'; + + + +export function appendObjectProperties(context: RuleContext, fixer: RuleFixer, objectNode: TSESTree.ObjectExpression, properties: string[]): RuleFix { + // todo: may not handle empty objects too well + const lastProperty = objectNode.properties[objectNode.properties.length - 1]; + const source = getSourceCode(context); + const nextToken = source.getTokenAfter(lastProperty); + + // todo: newline & indentation are hardcoded for @Component({}) + // todo: we're assuming that we need trailing commas, what if we don't? + const newPart = '\n' + properties.map(p => ` ${p},`).join('\n'); + + if (nextToken !== null && nextToken.value === ',') { + return fixer.insertTextAfter(nextToken, newPart); + } else { + return fixer.insertTextAfter(lastProperty, ',' + newPart); + } +} + +export function appendArrayElement(context: RuleContext, fixer: RuleFixer, arrayNode: TSESTree.ArrayExpression, value: string): RuleFix { + const source = getSourceCode(context); + + if (arrayNode.elements.length === 0) { + // This is the first element + const openArray = source.getTokenByRangeStart(arrayNode.range[0]); + + if (openArray == null) { + throw new Error('Unexpected null token for opening square bracket'); + } + + // safe to assume the list is single-line + return fixer.insertTextAfter(openArray, `${value}`); + } else { + const lastElement = arrayNode.elements[arrayNode.elements.length - 1]; + + if (lastElement == null) { + throw new Error('Unexpected null node in array'); + } + + const nextToken = source.getTokenAfter(lastElement); + + // todo: we don't know if the list is chopped or not, so we can't make any assumptions -- may produce output that will be flagged by other rules on the next run! + // todo: we're assuming that we need trailing commas, what if we don't? + if (nextToken !== null && nextToken.value === ',') { + return fixer.insertTextAfter(nextToken, ` ${value},`); + } else { + return fixer.insertTextAfter(lastElement, `, ${value},`); + } + } + +} + +export function isLast(elementNode: TSESTree.Node): boolean { + if (!elementNode.parent) { + return false; + } + + let siblingNodes: (TSESTree.Node | null)[] = [null]; + if (elementNode.parent.type === TSESTree.AST_NODE_TYPES.ArrayExpression) { + siblingNodes = elementNode.parent.elements; + } else if (elementNode.parent.type === TSESTree.AST_NODE_TYPES.ImportDeclaration) { + siblingNodes = elementNode.parent.specifiers; + } + + return elementNode === siblingNodes[siblingNodes.length - 1]; +} + +export function removeWithCommas(context: RuleContext, fixer: RuleFixer, elementNode: TSESTree.Node): RuleFix[] { + const ops = []; + + const source = getSourceCode(context); + let nextToken = source.getTokenAfter(elementNode); + let prevToken = source.getTokenBefore(elementNode); + + if (nextToken !== null && prevToken !== null) { + if (nextToken.value === ',') { + nextToken = source.getTokenAfter(nextToken); + if (nextToken !== null) { + ops.push(fixer.removeRange([elementNode.range[0], nextToken.range[0]])); + } + } + if (isLast(elementNode) && prevToken.value === ',') { + prevToken = source.getTokenBefore(prevToken); + if (prevToken !== null) { + ops.push(fixer.removeRange([prevToken.range[1], elementNode.range[1]])); + } + } + } else if (nextToken !== null) { + ops.push(fixer.removeRange([elementNode.range[0], nextToken.range[0]])); + } + + return ops; +} + +export function replaceOrRemoveArrayIdentifier(context: RuleContext, fixer: RuleFixer, identifierNode: TSESTree.Identifier, newValue: string): RuleFix[] { + if (identifierNode.parent.type !== TSESTree.AST_NODE_TYPES.ArrayExpression) { + throw new Error('Parent node is not an array expression!'); + } + + const array = identifierNode.parent as TSESTree.ArrayExpression; + + for (const element of array.elements) { + if (element !== null && element.type === TSESTree.AST_NODE_TYPES.Identifier && element.name === newValue) { + return removeWithCommas(context, fixer, identifierNode); + } + } + + return [fixer.replaceText(identifierNode, newValue)]; +} diff --git a/lint/src/util/misc.ts b/lint/src/util/misc.ts new file mode 100644 index 00000000000..49cb60124e8 --- /dev/null +++ b/lint/src/util/misc.ts @@ -0,0 +1,28 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ + +export function match(rangeA: number[], rangeB: number[]) { + return rangeA[0] === rangeB[0] && rangeA[1] === rangeB[1]; +} + + +export function stringLiteral(value: string): string { + return `'${value}'`; +} + +/** + * Transform Windows-style paths into Unix-style paths + */ +export function toUnixStylePath(path: string): string { + // note: we're assuming that none of the directory/file names contain '\' or '/' characters. + // using these characters in paths is very bad practice in general, so this should be a safe assumption. + if (path.includes('\\')) { + return path.replace(/^[A-Z]:\\/, '/').replaceAll('\\', '/'); + } + return path; +} diff --git a/lint/src/util/structure.ts b/lint/src/util/structure.ts new file mode 100644 index 00000000000..bfbf7ec7f27 --- /dev/null +++ b/lint/src/util/structure.ts @@ -0,0 +1,57 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +import { TSESLint } from '@typescript-eslint/utils'; +import { RuleTester } from 'eslint'; +import { EnumType } from 'typescript'; + +export type Meta = TSESLint.RuleMetaData; +export type Valid = TSESLint.ValidTestCase | RuleTester.ValidTestCase; +export type Invalid = TSESLint.InvalidTestCase | RuleTester.InvalidTestCase; + +export interface DSpaceESLintRuleInfo { + name: string; + meta: Meta, + defaultOptions: unknown[], +} + +export interface NamedTests { + plugin: string; + valid: Valid[]; + invalid: Invalid[]; +} + +export interface RuleExports { + Message: EnumType, + info: DSpaceESLintRuleInfo, + rule: TSESLint.RuleModule, + tests: NamedTests, + default: unknown, +} + +export interface PluginExports { + name: string, + language: string, + rules: Record, + index: RuleExports[], +} + +export function bundle( + name: string, + language: string, + index: RuleExports[], +): PluginExports { + return index.reduce((o: PluginExports, i: RuleExports) => { + o.rules[i.info.name] = i.rule; + return o; + }, { + name, + language, + rules: {}, + index, + }); +} diff --git a/lint/src/util/templates/index.ejs b/lint/src/util/templates/index.ejs new file mode 100644 index 00000000000..d959f292910 --- /dev/null +++ b/lint/src/util/templates/index.ejs @@ -0,0 +1,5 @@ +[DSpace ESLint plugins](../../../lint/README.md) > <%= plugin.language %> rules +_______ +<% rules.forEach(rule => { %> +- [`<%= plugin.name %>/<%= rule.name %>`](./rules/<%= rule.name %>.md)<% if (rule.meta?.docs?.description) {%>: <%= rule.meta.docs.description.split('\n')[0].trim() -%><% }-%> +<% }) %> diff --git a/lint/src/util/templates/rule.ejs b/lint/src/util/templates/rule.ejs new file mode 100644 index 00000000000..b39d193cc18 --- /dev/null +++ b/lint/src/util/templates/rule.ejs @@ -0,0 +1,48 @@ +[DSpace ESLint plugins](../../../../lint/README.md) > [<%= plugin.language %> rules](../index.md) > `<%= plugin.name %>/<%= rule.name %>` +_______ + +<%- rule.meta.docs?.description %> + +_______ + +[Source code](../../../../lint/src/rules/<%- plugin.name.replace('dspace-angular-', '') %>/<%- rule.name %>.ts) + +### Examples + +<% if (tests.valid) {%> +#### Valid code + <% tests.valid.forEach(test => { %> +##### <%= test.name !== undefined ? test.name : 'UNNAMED' %> + <% if (test.filename) { %> +Filename: `<%- test.filename %>` + <% } %> +```<%- plugin.language.toLowerCase() %> +<%- test.code.trim() %> +``` + <% }) %> +<% } %> + +<% if (tests.invalid) {%> +#### Invalid code <%= rule.meta.fixable ? ' & automatic fixes' : '' %> + <% tests.invalid.forEach(test => { %> +##### <%= test.name !== undefined ? test.name : 'UNNAMED' %> + <% if (test.filename) { %> +Filename: `<%- test.filename %>` + <% } %> +```<%- plugin.language.toLowerCase() %> +<%- test.code.trim() %> +``` +Will produce the following error(s): +``` +<% for (const error of test.errors) { -%> +<%- rule.meta.messages[error.messageId] %> +<% } -%> +``` + <% if (test.output) { %> +Result of `yarn lint --fix`: +```<%- plugin.language.toLowerCase() %> +<%- test.output.trim() %> +``` + <% } %> + <% }) %> +<% } %> diff --git a/lint/src/util/theme-support.ts b/lint/src/util/theme-support.ts new file mode 100644 index 00000000000..64644145fae --- /dev/null +++ b/lint/src/util/theme-support.ts @@ -0,0 +1,265 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ + +import { TSESTree } from '@typescript-eslint/utils'; +import { readFileSync } from 'fs'; +import { basename } from 'path'; +import ts, { Identifier } from 'typescript'; + +import { + getComponentClassName, + isPartOfViewChild, +} from './angular'; +import { + isPartOfClassDeclaration, + isPartOfTypeExpression, +} from './typescript'; + +/** + * Couples a themeable Component to its ThemedComponent wrapper + */ +export interface ThemeableComponentRegistryEntry { + basePath: string; + baseFileName: string, + baseClass: string; + + wrapperPath: string; + wrapperFileName: string, + wrapperClass: string; +} + +function isAngularComponentDecorator(node: ts.Node) { + if (node.kind === ts.SyntaxKind.Decorator && node.parent.kind === ts.SyntaxKind.ClassDeclaration) { + const decorator = node as ts.Decorator; + + if (decorator.expression.kind === ts.SyntaxKind.CallExpression) { + const method = decorator.expression as ts.CallExpression; + + if (method.expression.kind === ts.SyntaxKind.Identifier) { + return (method.expression as Identifier).text === 'Component'; + } + } + } + + return false; +} + +function findImportDeclaration(source: ts.SourceFile, identifierName: string): ts.ImportDeclaration | undefined { + return ts.forEachChild(source, (topNode: ts.Node) => { + if (topNode.kind === ts.SyntaxKind.ImportDeclaration) { + const importDeclaration = topNode as ts.ImportDeclaration; + + if (importDeclaration.importClause?.namedBindings?.kind === ts.SyntaxKind.NamedImports) { + const namedImports = importDeclaration.importClause?.namedBindings as ts.NamedImports; + + for (const element of namedImports.elements) { + if (element.name.text === identifierName) { + return importDeclaration; + } + } + } + } + + return undefined; + }); +} + +/** + * Listing of all themeable Components + */ +class ThemeableComponentRegistry { + public readonly entries: Set; + public readonly byBaseClass: Map; + public readonly byWrapperClass: Map; + public readonly byBasePath: Map; + public readonly byWrapperPath: Map; + + constructor() { + this.entries = new Set(); + this.byBaseClass = new Map(); + this.byWrapperClass = new Map(); + this.byBasePath = new Map(); + this.byWrapperPath = new Map(); + } + + public initialize(prefix = '') { + if (this.entries.size > 0) { + return; + } + + function registerWrapper(path: string) { + const source = getSource(path); + + function traverse(node: ts.Node) { + if (node.parent !== undefined && isAngularComponentDecorator(node)) { + const classNode = node.parent as ts.ClassDeclaration; + + if (classNode.name === undefined || classNode.heritageClauses === undefined) { + return; + } + + const wrapperClass = classNode.name?.escapedText as string; + + for (const heritageClause of classNode.heritageClauses) { + for (const type of heritageClause.types) { + if ((type as any).expression.escapedText === 'ThemedComponent') { + if (type.kind !== ts.SyntaxKind.ExpressionWithTypeArguments || type.typeArguments === undefined) { + continue; + } + + const firstTypeArg = type.typeArguments[0] as ts.TypeReferenceNode; + const baseClass = (firstTypeArg.typeName as ts.Identifier)?.escapedText; + + if (baseClass === undefined) { + continue; + } + + const importDeclaration = findImportDeclaration(source, baseClass); + + if (importDeclaration === undefined) { + continue; + } + + const basePath = resolveLocalPath((importDeclaration.moduleSpecifier as ts.StringLiteral).text, path); + + themeableComponents.add({ + baseClass, + basePath: basePath.replace(new RegExp(`^${prefix}`), ''), + baseFileName: basename(basePath).replace(/\.ts$/, ''), + wrapperClass, + wrapperPath: path.replace(new RegExp(`^${prefix}`), ''), + wrapperFileName: basename(path).replace(/\.ts$/, ''), + }); + } + } + } + + return; + } else { + ts.forEachChild(node, traverse); + } + } + + traverse(source); + } + + const glob = require('glob'); + + // note: this outputs Unix-style paths on Windows + const wrappers: string[] = glob.GlobSync(prefix + 'src/app/**/themed-*.component.ts', { ignore: 'node_modules/**' }).found; + + for (const wrapper of wrappers) { + registerWrapper(wrapper); + } + } + + private add(entry: ThemeableComponentRegistryEntry) { + this.entries.add(entry); + this.byBaseClass.set(entry.baseClass, entry); + this.byWrapperClass.set(entry.wrapperClass, entry); + this.byBasePath.set(entry.basePath, entry); + this.byWrapperPath.set(entry.wrapperPath, entry); + } +} + +export const themeableComponents = new ThemeableComponentRegistry(); + +/** + * Construct the AST of a TypeScript source file + * @param file + */ +function getSource(file: string): ts.SourceFile { + return ts.createSourceFile( + file, + readFileSync(file).toString(), + ts.ScriptTarget.ES2020, // todo: actually use tsconfig.json? + /*setParentNodes */ true, + ); +} + +/** + * Resolve a possibly relative local path into an absolute path starting from the root directory of the project + */ +function resolveLocalPath(path: string, relativeTo: string) { + if (path.startsWith('src/')) { + return path; + } else if (path.startsWith('./')) { + const parts = relativeTo.split('/'); + return [ + ...parts.slice(0, parts.length - 1), + path.replace(/^.\//, ''), + ].join('/') + '.ts'; + } else { + throw new Error(`Unsupported local path: ${path}`); + } +} + +export function isThemedComponentWrapper(decoratorNode: TSESTree.Decorator): boolean { + if (decoratorNode.parent.type !== TSESTree.AST_NODE_TYPES.ClassDeclaration) { + return false; + } + + if (decoratorNode.parent.superClass?.type !== TSESTree.AST_NODE_TYPES.Identifier) { + return false; + } + + return (decoratorNode.parent.superClass as any)?.name === 'ThemedComponent'; +} + +export function getBaseComponentClassName(decoratorNode: TSESTree.Decorator): string | undefined { + const wrapperClass = getComponentClassName(decoratorNode); + + if (wrapperClass === undefined) { + return; + } + + themeableComponents.initialize(); + const entry = themeableComponents.byWrapperClass.get(wrapperClass); + + if (entry === undefined) { + return undefined; + } + + return entry.baseClass; +} + +export function isThemeableComponent(className: string): boolean { + themeableComponents.initialize(); + return themeableComponents.byBaseClass.has(className); +} + +export function inThemedComponentOverrideFile(filename: string): boolean { + const match = filename.match(/src\/themes\/[^\/]+\/(app\/.*)/); + + if (!match) { + return false; + } + themeableComponents.initialize(); + // todo: this is fragile! + return themeableComponents.byBasePath.has(`src/${match[1]}`); +} + +export function allThemeableComponents(): ThemeableComponentRegistryEntry[] { + themeableComponents.initialize(); + return [...themeableComponents.entries]; +} + +export function getThemeableComponentByBaseClass(baseClass: string): ThemeableComponentRegistryEntry | undefined { + themeableComponents.initialize(); + return themeableComponents.byBaseClass.get(baseClass); +} + +export function isAllowedUnthemedUsage(usageNode: TSESTree.Identifier) { + return isPartOfClassDeclaration(usageNode) || isPartOfTypeExpression(usageNode) || isPartOfViewChild(usageNode); +} + +export const DISALLOWED_THEME_SELECTORS = 'ds-(base|themed)-'; + +export function fixSelectors(text: string): string { + return text.replaceAll(/ds-(base|themed)-/g, 'ds-'); +} diff --git a/lint/src/util/typescript.ts b/lint/src/util/typescript.ts new file mode 100644 index 00000000000..3fecad270e6 --- /dev/null +++ b/lint/src/util/typescript.ts @@ -0,0 +1,154 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +import { + TSESLint, + TSESTree, +} from '@typescript-eslint/utils'; + +import { + match, + toUnixStylePath, +} from './misc'; + +export type AnyRuleContext = TSESLint.RuleContext; + +/** + * Return the current filename based on the ESLint rule context as a Unix-style path. + * This is easier for regex and comparisons to glob paths. + */ +export function getFilename(context: AnyRuleContext): string { + // TSESLint claims this is deprecated, but the suggested alternative is undefined (could be a version mismatch between ESLint and TSESlint?) + // eslint-disable-next-line deprecation/deprecation + return toUnixStylePath(context.getFilename()); +} + +export function getSourceCode(context: AnyRuleContext): TSESLint.SourceCode { + // TSESLint claims this is deprecated, but the suggested alternative is undefined (could be a version mismatch between ESLint and TSESlint?) + // eslint-disable-next-line deprecation/deprecation + return context.getSourceCode(); +} + +export function getObjectPropertyNodeByName(objectNode: TSESTree.ObjectExpression, propertyName: string): TSESTree.Node | undefined { + for (const propertyNode of objectNode.properties) { + if ( + propertyNode.type === TSESTree.AST_NODE_TYPES.Property + && ( + ( + propertyNode.key?.type === TSESTree.AST_NODE_TYPES.Identifier + && propertyNode.key?.name === propertyName + ) || ( + propertyNode.key?.type === TSESTree.AST_NODE_TYPES.Literal + && propertyNode.key?.value === propertyName + ) + ) + ) { + return propertyNode.value; + } + } + return undefined; +} + +export function findUsages(context: AnyRuleContext, localNode: TSESTree.Identifier): TSESTree.Identifier[] { + const source = getSourceCode(context); + + const usages: TSESTree.Identifier[] = []; + + for (const token of source.ast.tokens) { + if (token.type === TSESTree.AST_TOKEN_TYPES.Identifier && token.value === localNode.name && !match(token.range, localNode.range)) { + const node = source.getNodeByRangeIndex(token.range[0]); + // todo: in some cases, the resulting node can actually be the whole program (!) + if (node !== null) { + usages.push(node as TSESTree.Identifier); + } + } + } + + return usages; +} + +export function findUsagesByName(context: AnyRuleContext, identifier: string): TSESTree.Identifier[] { + const source = getSourceCode(context); + + const usages: TSESTree.Identifier[] = []; + + for (const token of source.ast.tokens) { + if (token.type === TSESTree.AST_TOKEN_TYPES.Identifier && token.value === identifier) { + const node = source.getNodeByRangeIndex(token.range[0]); + // todo: in some cases, the resulting node can actually be the whole program (!) + if (node !== null) { + usages.push(node as TSESTree.Identifier); + } + } + } + + return usages; +} + +export function isPartOfTypeExpression(node: TSESTree.Identifier): boolean { + return node.parent?.type?.valueOf().startsWith('TSType'); +} + +export function isPartOfClassDeclaration(node: TSESTree.Identifier): boolean { + return node.parent?.type === TSESTree.AST_NODE_TYPES.ClassDeclaration; +} + +function fromSrc(path: string): string { + const m = path.match(/^.*(src\/.+)(\.(ts|json|js)?)$/); + + if (m) { + return m[1]; + } else { + throw new Error(`Can't infer project-absolute TS/resource path from: ${path}`); + } +} + + +export function relativePath(thisFile: string, importFile: string): string { + const fromParts = fromSrc(thisFile).split('/'); + const toParts = fromSrc(importFile).split('/'); + + let lastCommon = 0; + for (let i = 0; i < fromParts.length - 1; i++) { + if (fromParts[i] === toParts[i]) { + lastCommon++; + } else { + break; + } + } + + const path = toParts.slice(lastCommon, toParts.length).join('/'); + const backtrack = fromParts.length - lastCommon - 1; + + let prefix: string; + if (backtrack > 0) { + prefix = '../'.repeat(backtrack); + } else { + prefix = './'; + } + + return prefix + path; +} + + +export function findImportSpecifier(context: AnyRuleContext, identifier: string): TSESTree.ImportSpecifier | undefined { + const source = getSourceCode(context); + + const usages: TSESTree.Identifier[] = []; + + for (const token of source.ast.tokens) { + if (token.type === TSESTree.AST_TOKEN_TYPES.Identifier && token.value === identifier) { + const node = source.getNodeByRangeIndex(token.range[0]); + // todo: in some cases, the resulting node can actually be the whole program (!) + if (node && node.parent && node.parent.type === TSESTree.AST_NODE_TYPES.ImportSpecifier) { + return node.parent; + } + } + } + + return undefined; +} diff --git a/lint/test/fixture/README.md b/lint/test/fixture/README.md new file mode 100644 index 00000000000..b19ae11b558 --- /dev/null +++ b/lint/test/fixture/README.md @@ -0,0 +1,9 @@ +# ESLint testing fixtures + +The files in this directory are used for the ESLint testing environment +- Some rules rely on registries that must be built up _before_ the rule is run + - In order to test these registries, the fixture sources contain a few dummy components +- The TypeScript ESLint test runner requires at least one dummy file to exist to run any tests + - By default, [`test.ts`](./src/test.ts) is used. Note that this file is empty; it's only there for the TypeScript configuration, the actual content is injected from the `code` property in the tests. + - To test rules that make assertions based on the path of the file, you'll need to include the `filename` property in the test configuration. Note that it must point to an existing file too! + - The `filename` must be provided as `fixture('src/something.ts')` \ No newline at end of file diff --git a/lint/test/fixture/index.ts b/lint/test/fixture/index.ts new file mode 100644 index 00000000000..1d4f33f7e28 --- /dev/null +++ b/lint/test/fixture/index.ts @@ -0,0 +1,13 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ + +export const FIXTURE = 'lint/test/fixture/'; + +export function fixture(path: string): string { + return FIXTURE + path; +} diff --git a/lint/test/fixture/src/app/test/test-routing.module.ts b/lint/test/fixture/src/app/test/test-routing.module.ts new file mode 100644 index 00000000000..1ccbccc5994 --- /dev/null +++ b/lint/test/fixture/src/app/test/test-routing.module.ts @@ -0,0 +1,14 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +import { ThemedTestThemeableComponent } from './themed-test-themeable.component'; + +export const ROUTES = [ + { + component: ThemedTestThemeableComponent, + }, +]; diff --git a/lint/test/fixture/src/app/test/test-themeable.component.ts b/lint/test/fixture/src/app/test/test-themeable.component.ts new file mode 100644 index 00000000000..b445040539c --- /dev/null +++ b/lint/test/fixture/src/app/test/test-themeable.component.ts @@ -0,0 +1,16 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +import { Component } from '@angular/core'; + +@Component({ + selector: 'ds-base-test-themeable', + template: '', + standalone: true, +}) +export class TestThemeableComponent { +} diff --git a/lint/test/fixture/src/app/test/test.component.cy.ts b/lint/test/fixture/src/app/test/test.component.cy.ts new file mode 100644 index 00000000000..2300ac4a56f --- /dev/null +++ b/lint/test/fixture/src/app/test/test.component.cy.ts @@ -0,0 +1,8 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ + diff --git a/lint/test/fixture/src/app/test/test.component.spec.ts b/lint/test/fixture/src/app/test/test.component.spec.ts new file mode 100644 index 00000000000..2300ac4a56f --- /dev/null +++ b/lint/test/fixture/src/app/test/test.component.spec.ts @@ -0,0 +1,8 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ + diff --git a/lint/test/fixture/src/app/test/test.component.ts b/lint/test/fixture/src/app/test/test.component.ts new file mode 100644 index 00000000000..c01f104c989 --- /dev/null +++ b/lint/test/fixture/src/app/test/test.component.ts @@ -0,0 +1,15 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +import { Component } from '@angular/core'; + +@Component({ + selector: 'ds-test', + template: '', +}) +export class TestComponent { +} diff --git a/lint/test/fixture/src/app/test/test.module.ts b/lint/test/fixture/src/app/test/test.module.ts new file mode 100644 index 00000000000..a37396ef459 --- /dev/null +++ b/lint/test/fixture/src/app/test/test.module.ts @@ -0,0 +1,24 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +// @ts-ignore +import { NgModule } from '@angular/core'; + +import { TestComponent } from './test.component'; +import { TestThemeableComponent } from './test-themeable.component'; +import { ThemedTestThemeableComponent } from './themed-test-themeable.component'; + +@NgModule({ + declarations: [ + TestComponent, + TestThemeableComponent, + ThemedTestThemeableComponent, + ], +}) +export class TestModule { + +} diff --git a/lint/test/fixture/src/app/test/themed-test-themeable.component.ts b/lint/test/fixture/src/app/test/themed-test-themeable.component.ts new file mode 100644 index 00000000000..2697a8c598e --- /dev/null +++ b/lint/test/fixture/src/app/test/themed-test-themeable.component.ts @@ -0,0 +1,31 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +import { Component } from '@angular/core'; + +import { ThemedComponent } from '../../../../../../src/app/shared/theme-support/themed.component'; +import { TestThemeableComponent } from './test-themeable.component'; + +@Component({ + selector: 'ds-test-themeable', + template: '', + standalone: true, + imports: [TestThemeableComponent], +}) +export class ThemedTestThemeableComponent extends ThemedComponent { + protected getComponentName(): string { + return ''; + } + + protected importThemedComponent(themeName: string): Promise { + return Promise.resolve(undefined); + } + + protected importUnthemedComponent(): Promise { + return Promise.resolve(undefined); + } +} diff --git a/lint/test/fixture/src/test.ts b/lint/test/fixture/src/test.ts new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lint/test/fixture/src/themes/test/app/test/other-themeable.component.ts b/lint/test/fixture/src/themes/test/app/test/other-themeable.component.ts new file mode 100644 index 00000000000..f72161b2bfc --- /dev/null +++ b/lint/test/fixture/src/themes/test/app/test/other-themeable.component.ts @@ -0,0 +1,16 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +import { Component } from '@angular/core'; + +@Component({ + selector: 'ds-themed-test-themeable', + template: '', +}) +export class OtherThemeableComponent { + +} diff --git a/lint/test/fixture/src/themes/test/app/test/test-themeable.component.ts b/lint/test/fixture/src/themes/test/app/test/test-themeable.component.ts new file mode 100644 index 00000000000..d2b02ca9f1f --- /dev/null +++ b/lint/test/fixture/src/themes/test/app/test/test-themeable.component.ts @@ -0,0 +1,18 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +import { Component } from '@angular/core'; + +import { TestThemeableComponent as BaseComponent } from '../../../../app/test/test-themeable.component'; + +@Component({ + selector: 'ds-themed-test-themeable', + template: '', +}) +export class TestThemeableComponent extends BaseComponent { + +} diff --git a/lint/test/fixture/src/themes/test/test.module.ts b/lint/test/fixture/src/themes/test/test.module.ts new file mode 100644 index 00000000000..ff6ec3b2c0e --- /dev/null +++ b/lint/test/fixture/src/themes/test/test.module.ts @@ -0,0 +1,22 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +// @ts-ignore +import { NgModule } from '@angular/core'; + +import { OtherThemeableComponent } from './app/test/other-themeable.component'; +import { TestThemeableComponent } from './app/test/test-themeable.component'; + +@NgModule({ + declarations: [ + TestThemeableComponent, + OtherThemeableComponent, + ], +}) +export class TestModule { + +} diff --git a/lint/test/fixture/tsconfig.json b/lint/test/fixture/tsconfig.json new file mode 100644 index 00000000000..0fd1141ae0e --- /dev/null +++ b/lint/test/fixture/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.json", + "include": [ + "src/**/*.ts" + ], + "exclude": [] +} diff --git a/lint/test/helpers.js b/lint/test/helpers.js new file mode 100644 index 00000000000..bd648d007f5 --- /dev/null +++ b/lint/test/helpers.js @@ -0,0 +1,13 @@ +const SpecReporter = require('jasmine-spec-reporter').SpecReporter; +const StacktraceOption = require('jasmine-spec-reporter').StacktraceOption; + +jasmine.getEnv().clearReporters(); // Clear default console reporter for those instead +jasmine.getEnv().addReporter(new SpecReporter({ + spec: { + displayErrorMessages: false, + }, + summary: { + displayFailed: true, + displayStacktrace: StacktraceOption.PRETTY, + }, +})); diff --git a/lint/test/rules.spec.ts b/lint/test/rules.spec.ts new file mode 100644 index 00000000000..11c9bec46cf --- /dev/null +++ b/lint/test/rules.spec.ts @@ -0,0 +1,26 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ + +import { default as htmlPlugin } from '../src/rules/html'; +import { default as tsPlugin } from '../src/rules/ts'; +import { + htmlRuleTester, + tsRuleTester, +} from './testing'; + +describe('TypeScript rules', () => { + for (const { info, rule, tests } of tsPlugin.index) { + tsRuleTester.run(info.name, rule, tests as any); + } +}); + +describe('HTML rules', () => { + for (const { info, rule, tests } of htmlPlugin.index) { + htmlRuleTester.run(info.name, rule, tests); + } +}); diff --git a/lint/test/structure.spec.ts b/lint/test/structure.spec.ts new file mode 100644 index 00000000000..24e69e42d9a --- /dev/null +++ b/lint/test/structure.spec.ts @@ -0,0 +1,76 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ + +import { default as html } from '../src/rules/html'; +import { default as ts } from '../src/rules/ts'; + +describe('plugin structure', () => { + for (const pluginExports of [ts, html]) { + const pluginName = pluginExports.name ?? 'UNNAMED PLUGIN'; + + describe(pluginName, () => { + it('should have a name', () => { + expect(pluginExports.name).toBeTruthy(); + }); + + it('should have rules', () => { + expect(pluginExports.index).toBeTruthy(); + expect(pluginExports.rules).toBeTruthy(); + expect(pluginExports.index.length).toBeGreaterThan(0); + }); + + for (const ruleExports of pluginExports.index) { + const ruleName = ruleExports.info.name ?? 'UNNAMED RULE'; + + describe(ruleName, () => { + it('should have a name', () => { + expect(ruleExports.info.name).toBeTruthy(); + }); + + it('should be included under the right name in the plugin', () => { + expect(pluginExports.rules[ruleExports.info.name]).toBe(ruleExports.rule); + }); + + it('should contain metadata', () => { + expect(ruleExports.info).toBeTruthy(); + expect(ruleExports.info.name).toBeTruthy(); + expect(ruleExports.info.meta).toBeTruthy(); + expect(ruleExports.info.defaultOptions).toBeTruthy(); + }); + + it('should contain messages', () => { + expect(ruleExports.Message).toBeTruthy(); + expect(ruleExports.info.meta.messages).toBeTruthy(); + }); + + describe('messages', () => { + for (const member of Object.keys(ruleExports.Message)) { + describe(member, () => { + const id = (ruleExports.Message as any)[member]; + + it('should have a valid ID', () => { + expect(id).toBeTruthy(); + }); + + it('should have valid metadata', () => { + expect(ruleExports.info.meta.messages[id]).toBeTruthy(); + }); + }); + } + }); + + it('should contain tests', () => { + expect(ruleExports.tests).toBeTruthy(); + expect(ruleExports.tests.valid.length).toBeGreaterThan(0); + expect(ruleExports.tests.invalid.length).toBeGreaterThan(0); + }); + }); + } + }); + } +}); diff --git a/lint/test/testing.ts b/lint/test/testing.ts new file mode 100644 index 00000000000..cfa54c5b85c --- /dev/null +++ b/lint/test/testing.ts @@ -0,0 +1,53 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ + +import { RuleTester as TypeScriptRuleTester } from '@typescript-eslint/rule-tester'; +import { RuleTester } from 'eslint'; + +import { themeableComponents } from '../src/util/theme-support'; +import { + FIXTURE, + fixture, +} from './fixture'; + + +// Register themed components from test fixture +themeableComponents.initialize(FIXTURE); + +TypeScriptRuleTester.itOnly = fit; +TypeScriptRuleTester.itSkip = xit; + +export const tsRuleTester = new TypeScriptRuleTester({ + parser: '@typescript-eslint/parser', + defaultFilenames: { + ts: fixture('src/test.ts'), + tsx: 'n/a', + }, + parserOptions: { + project: fixture('tsconfig.json'), + }, +}); + +class HtmlRuleTester extends RuleTester { + run(name: string, rule: any, tests: { valid: any[], invalid: any[] }) { + super.run(name, rule, { + valid: tests.valid.map((test) => ({ + filename: fixture('test.html'), + ...test, + })), + invalid: tests.invalid.map((test) => ({ + filename: fixture('test.html'), + ...test, + })), + }); + } +} + +export const htmlRuleTester = new HtmlRuleTester({ + parser: require.resolve('@angular-eslint/template-parser'), +}); diff --git a/lint/test/theme-support.spec.ts b/lint/test/theme-support.spec.ts new file mode 100644 index 00000000000..2edf9594b62 --- /dev/null +++ b/lint/test/theme-support.spec.ts @@ -0,0 +1,24 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ + +import { themeableComponents } from '../src/util/theme-support'; + +describe('theme-support', () => { + describe('themeable component registry', () => { + it('should contain all themeable components from the fixture', () => { + expect(themeableComponents.entries.size).toBe(1); + expect(themeableComponents.byBasePath.size).toBe(1); + expect(themeableComponents.byWrapperPath.size).toBe(1); + expect(themeableComponents.byBaseClass.size).toBe(1); + + expect(themeableComponents.byBaseClass.get('TestThemeableComponent')).toBeTruthy(); + expect(themeableComponents.byBasePath.get('src/app/test/test-themeable.component.ts')).toBeTruthy(); + expect(themeableComponents.byWrapperPath.get('src/app/test/themed-test-themeable.component.ts')).toBeTruthy(); + }); + }); +}); diff --git a/lint/tsconfig.json b/lint/tsconfig.json new file mode 100644 index 00000000000..d3537a73762 --- /dev/null +++ b/lint/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "ES2021", + "lib": [ + "es2021" + ], + "module": "nodenext", + "moduleResolution": "nodenext", + "noImplicitReturns": true, + "skipLibCheck": true, + "strict": true, + "outDir": "./dist", + "sourceMap": true, + "allowSyntheticDefaultImports": true, + "types": [ + "jasmine", + "node" + ] + }, + "include": [ + "**/*.ts", + ], + "exclude": [ + "dist", + "test/fixture" + ] +} diff --git a/package.json b/package.json index 0571d166bc5..72b11eec8b9 100644 --- a/package.json +++ b/package.json @@ -17,11 +17,16 @@ "build:stats": "ng build --stats-json", "build:prod": "cross-env NODE_ENV=production yarn run build:ssr", "build:ssr": "ng build --configuration production && ng run dspace-angular:server:production", + "build:lint": "rimraf 'lint/dist/**/*.js' 'lint/dist/**/*.js.map' && tsc -b lint/tsconfig.json", "test": "ng test --source-map=true --watch=false --configuration test", "test:watch": "nodemon --exec \"ng test --source-map=true --watch=true --configuration test\"", "test:headless": "ng test --source-map=true --watch=false --configuration test --browsers=ChromeHeadless --code-coverage", - "lint": "ng lint", - "lint-fix": "ng lint --fix=true", + "test:lint": "yarn build:lint && yarn test:lint:nobuild", + "test:lint:nobuild": "jasmine --config=lint/jasmine.json", + "lint": "yarn build:lint && yarn lint:nobuild", + "lint:nobuild": "ng lint", + "lint-fix": "yarn build:lint && ng lint --fix=true", + "docs:lint": "ts-node --project ./lint/tsconfig.json ./lint/generate-docs.ts", "e2e": "cross-env NODE_ENV=production ng e2e", "clean:dev:config": "rimraf src/assets/config.json", "clean:coverage": "rimraf coverage", @@ -40,7 +45,8 @@ "cypress:run": "cypress run", "env:yaml": "ts-node --project ./tsconfig.ts-node.json scripts/env-to-yaml.ts", "base-href": "ts-node --project ./tsconfig.ts-node.json scripts/base-href.ts", - "check-circ-deps": "npx madge --exclude '(bitstream|bundle|collection|config-submission-form|eperson|item|version)\\.model\\.ts$' --circular --extensions ts ./" + "check-circ-deps": "npx madge --exclude '(bitstream|bundle|collection|config-submission-form|eperson|item|version)\\.model\\.ts$' --circular --extensions ts ./", + "postinstall": "yarn build:lint || echo 'Skipped DSpace ESLint plugins.'" }, "browser": { "fs": false, @@ -136,6 +142,7 @@ "@angular-builders/custom-webpack": "~17.0.1", "@angular-devkit/build-angular": "^17.3.0", "@angular-eslint/builder": "17.2.1", + "@angular-eslint/bundled-angular-compiler": "17.2.1", "@angular-eslint/eslint-plugin": "17.2.1", "@angular-eslint/eslint-plugin-template": "17.2.1", "@angular-eslint/schematics": "17.2.1", @@ -155,8 +162,10 @@ "@types/lodash": "^4.14.194", "@types/node": "^14.14.9", "@types/sanitize-html": "^2.9.0", - "@typescript-eslint/eslint-plugin": "^5.59.1", - "@typescript-eslint/parser": "^5.59.1", + "@typescript-eslint/eslint-plugin": "^7.2.0", + "@typescript-eslint/parser": "^7.2.0", + "@typescript-eslint/rule-tester": "^7.2.0", + "@typescript-eslint/utils": "^7.2.0", "axe-core": "^4.7.2", "browser-sync": "^3.0.0", "compression-webpack-plugin": "^9.2.0", @@ -167,6 +176,8 @@ "deep-freeze": "0.0.1", "eslint": "^8.39.0", "eslint-plugin-deprecation": "^1.4.1", + "eslint-plugin-dspace-angular-html": "link:./lint/dist/src/rules/html", + "eslint-plugin-dspace-angular-ts": "link:./lint/dist/src/rules/ts", "eslint-plugin-import": "^2.27.5", "eslint-plugin-import-newlines": "^1.3.1", "eslint-plugin-jsdoc": "^45.0.0", @@ -176,6 +187,7 @@ "eslint-plugin-simple-import-sort": "^10.0.0", "eslint-plugin-unused-imports": "^2.0.0", "express-static-gzip": "^2.1.7", + "jasmine": "^3.8.0", "jasmine-core": "^3.8.0", "jasmine-marbles": "0.9.2", "karma": "^6.4.2", @@ -206,4 +218,4 @@ "webpack-cli": "^4.2.0", "webpack-dev-server": "^4.13.3" } -} \ No newline at end of file +} diff --git a/src/app/access-control/bulk-access/browse/bulk-access-browse.component.html b/src/app/access-control/bulk-access/browse/bulk-access-browse.component.html index 131cb49d6be..f96ddf4a235 100644 --- a/src/app/access-control/bulk-access/browse/bulk-access-browse.component.html +++ b/src/app/access-control/bulk-access/browse/bulk-access-browse.component.html @@ -23,10 +23,10 @@ {{'admin.access-control.bulk-access-browse.search.header' | translate}}
- + [showThumbnails]="false">
diff --git a/src/app/access-control/epeople-registry/epeople-registry.component.html b/src/app/access-control/epeople-registry/epeople-registry.component.html index 641615d1825..b16d8ac6594 100644 --- a/src/app/access-control/epeople-registry/epeople-registry.component.html +++ b/src/app/access-control/epeople-registry/epeople-registry.component.html @@ -41,7 +41,7 @@ - +

{{messagePrefix + '.groupsEPersonIsMemberOf' | translate}}

- + {{messagePrefix + 'search.head' | tra
- + (); + response = new EventEmitter(); public isCoarMessageVisible = false; diff --git a/src/app/admin/admin-notify-dashboard/admin-notify-logs/admin-notify-logs-result/admin-notify-logs-result.component.html b/src/app/admin/admin-notify-dashboard/admin-notify-logs/admin-notify-logs-result/admin-notify-logs-result.component.html index f7c4f77a704..57ce83934cf 100644 --- a/src/app/admin/admin-notify-dashboard/admin-notify-logs/admin-notify-logs-result/admin-notify-logs-result.component.html +++ b/src/app/admin/admin-notify-dashboard/admin-notify-logs/admin-notify-logs-result/admin-notify-logs-result.component.html @@ -15,11 +15,11 @@
- + >
diff --git a/src/app/admin/admin-notify-dashboard/admin-notify-logs/admin-notify-logs-result/admin-notify-logs-result.component.ts b/src/app/admin/admin-notify-dashboard/admin-notify-logs/admin-notify-logs-result/admin-notify-logs-result.component.ts index 4cb6696fe25..33ac2b4cb18 100644 --- a/src/app/admin/admin-notify-dashboard/admin-notify-logs/admin-notify-logs-result/admin-notify-logs-result.component.ts +++ b/src/app/admin/admin-notify-dashboard/admin-notify-logs/admin-notify-logs-result/admin-notify-logs-result.component.ts @@ -51,7 +51,7 @@ import { ThemedSearchComponent } from '../../../../shared/search/themed-search.c export class AdminNotifyLogsResultComponent implements OnInit { @Input() - defaultConfiguration: string; + defaultConfiguration: string; public selectedSearchConfig$: Observable; diff --git a/src/app/admin/admin-notify-dashboard/admin-notify-metrics/admin-notify-metrics.component.ts b/src/app/admin/admin-notify-dashboard/admin-notify-metrics/admin-notify-metrics.component.ts index 727b081d89f..af5345f5125 100644 --- a/src/app/admin/admin-notify-dashboard/admin-notify-metrics/admin-notify-metrics.component.ts +++ b/src/app/admin/admin-notify-dashboard/admin-notify-metrics/admin-notify-metrics.component.ts @@ -27,7 +27,7 @@ import { AdminNotifyMetricsRow } from './admin-notify-metrics.model'; export class AdminNotifyMetricsComponent { @Input() - boxesConfig: AdminNotifyMetricsRow[]; + boxesConfig: AdminNotifyMetricsRow[]; private incomingConfiguration = 'NOTIFY.incoming'; private involvedItemsSuffix = 'involvedItems'; diff --git a/src/app/admin/admin-notify-dashboard/models/admin-notify-message.model.ts b/src/app/admin/admin-notify-dashboard/models/admin-notify-message.model.ts index f32451eaff1..2524ffed9b8 100644 --- a/src/app/admin/admin-notify-dashboard/models/admin-notify-message.model.ts +++ b/src/app/admin/admin-notify-dashboard/models/admin-notify-message.model.ts @@ -24,138 +24,138 @@ export class AdminNotifyMessage extends DSpaceObject { * The type of the resource */ @excludeFromEquals - type = ADMIN_NOTIFY_MESSAGE; + type = ADMIN_NOTIFY_MESSAGE; /** * The id of the message */ @autoserialize - id: string; + id: string; /** * The id of the notification */ @autoserialize - notificationId: string; + notificationId: string; /** * The type of the notification */ @autoserialize - notificationType: string; + notificationType: string; /** * The type of the notification */ @autoserialize - coarNotifyType: string; + coarNotifyType: string; /** * The type of the activity */ @autoserialize - activityStreamType: string; + activityStreamType: string; /** * The object the message reply to */ @autoserialize - inReplyTo: string; + inReplyTo: string; /** * The object the message relates to */ @autoserialize - object: string; + object: string; /** * The name of the related item */ @autoserialize - relatedItem: string; + relatedItem: string; /** * The name of the related ldn service */ @autoserialize - ldnService: string; + ldnService: string; /** * The context of the message */ @autoserialize - context: string; + context: string; /** * The related COAR message */ @autoserialize - message: string; + message: string; /** * The attempts of the queue */ @autoserialize - queueAttempts: number; + queueAttempts: number; /** * Timestamp of the last queue attempt */ @autoserialize - queueLastStartTime: string; + queueLastStartTime: string; /** * The type of the activity stream */ @autoserialize - origin: number | string; + origin: number | string; /** * The type of the activity stream */ @autoserialize - target: number | string; + target: number | string; /** * The label for the status of the queue */ @autoserialize - queueStatusLabel: string; + queueStatusLabel: string; /** * The timeout of the queue */ @autoserialize - queueTimeout: string; + queueTimeout: string; /** * The status of the queue */ @autoserialize - queueStatus: number; + queueStatus: number; /** * Thumbnail link used when browsing items with showThumbs config enabled. */ @autoserialize - thumbnail: string; + thumbnail: string; /** * The observable pointing to the item itself */ @autoserialize - item: Observable; + item: Observable; /** * The observable pointing to the access status of the item */ @autoserialize - accessStatus: Observable; + accessStatus: Observable; @deserialize - _links: { + _links: { self: { href: string; }; diff --git a/src/app/admin/admin-search-page/admin-search-page.component.html b/src/app/admin/admin-search-page/admin-search-page.component.html index 516799ddf90..69ff132fe3f 100644 --- a/src/app/admin/admin-search-page/admin-search-page.component.html +++ b/src/app/admin/admin-search-page/admin-search-page.component.html @@ -1 +1 @@ - + diff --git a/src/app/admin/admin-sidebar/admin-sidebar.component.scss b/src/app/admin/admin-sidebar/admin-sidebar.component.scss index d3607ca625a..a679155c323 100644 --- a/src/app/admin/admin-sidebar/admin-sidebar.component.scss +++ b/src/app/admin/admin-sidebar/admin-sidebar.component.scss @@ -138,3 +138,9 @@ } } } + +::ng-deep { + .browser-firefox-windows { + --ds-dark-scrollbar-width: 20px; + } +} diff --git a/src/app/admin/admin-sidebar/admin-sidebar.component.ts b/src/app/admin/admin-sidebar/admin-sidebar.component.ts index cd26a11995e..00514d2afc3 100644 --- a/src/app/admin/admin-sidebar/admin-sidebar.component.ts +++ b/src/app/admin/admin-sidebar/admin-sidebar.component.ts @@ -41,7 +41,7 @@ import { ThemeService } from '../../shared/theme-support/theme.service'; * Component representing the admin sidebar */ @Component({ - selector: 'ds-admin-sidebar', + selector: 'ds-base-admin-sidebar', templateUrl: './admin-sidebar.component.html', styleUrls: ['./admin-sidebar.component.scss'], animations: [slideSidebar], diff --git a/src/app/admin/admin-sidebar/themed-admin-sidebar.component.ts b/src/app/admin/admin-sidebar/themed-admin-sidebar.component.ts index 165f48384a0..6127fd42a99 100644 --- a/src/app/admin/admin-sidebar/themed-admin-sidebar.component.ts +++ b/src/app/admin/admin-sidebar/themed-admin-sidebar.component.ts @@ -11,10 +11,11 @@ import { AdminSidebarComponent } from './admin-sidebar.component'; * Themed wrapper for AdminSidebarComponent */ @Component({ - selector: 'ds-themed-admin-sidebar', + selector: 'ds-admin-sidebar', styleUrls: [], templateUrl: '../../shared/theme-support/themed.component.html', standalone: true, + imports: [AdminSidebarComponent], }) export class ThemedAdminSidebarComponent extends ThemedComponent { diff --git a/src/app/admin/admin-workflow-page/admin-workflow-page.component.html b/src/app/admin/admin-workflow-page/admin-workflow-page.component.html index c16ed311681..d12cefb3313 100644 --- a/src/app/admin/admin-workflow-page/admin-workflow-page.component.html +++ b/src/app/admin/admin-workflow-page/admin-workflow-page.component.html @@ -1 +1 @@ - + diff --git a/src/app/admin/admin-workflow-page/admin-workflow-search-results/actions/workspace-item/supervision-order-group-selector/supervision-order-group-selector.component.ts b/src/app/admin/admin-workflow-page/admin-workflow-search-results/actions/workspace-item/supervision-order-group-selector/supervision-order-group-selector.component.ts index 597940ca108..67dcd09b8eb 100644 --- a/src/app/admin/admin-workflow-page/admin-workflow-search-results/actions/workspace-item/supervision-order-group-selector/supervision-order-group-selector.component.ts +++ b/src/app/admin/admin-workflow-page/admin-workflow-search-results/actions/workspace-item/supervision-order-group-selector/supervision-order-group-selector.component.ts @@ -15,6 +15,7 @@ import { NotificationsService } from 'src/app/shared/notifications/notifications import { DSONameService } from '../../../../../../core/breadcrumbs/dso-name.service'; import { RemoteData } from '../../../../../../core/data/remote-data'; +import { RequestEntryState } from '../../../../../../core/data/request-entry-state.model'; import { Group } from '../../../../../../core/eperson/models/group.model'; import { SupervisionOrder } from '../../../../../../core/supervision-order/models/supervision-order.model'; import { SupervisionOrderDataService } from '../../../../../../core/supervision-order/supervision-order-data.service'; @@ -95,7 +96,7 @@ export class SupervisionOrderGroupSelectorComponent { this.supervisionOrderDataService.create(supervisionDataObject, this.itemUUID, this.selectedGroup.uuid, this.selectedOrderType).pipe( getFirstCompletedRemoteData(), ).subscribe((rd: RemoteData) => { - if (rd.state === 'Success') { + if (rd.state === RequestEntryState.Success) { this.notificationsService.success(this.translateService.get('supervision-group-selector.notification.create.success.title', { name: this.dsoNameService.getName(this.selectedGroup) })); this.create.emit(rd.payload); this.close(); diff --git a/src/app/app.component.html b/src/app/app.component.html index fb9983a6ef9..9016f42dc1e 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,3 +1,3 @@ - + [shouldShowRouteLoader]="isRouteLoading$ | async"> 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 b306eb27214..f7d2c608324 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 @@ -2,7 +2,7 @@
- +
@@ -27,7 +27,7 @@

{{dsoNameService.getName(bitstreamRD?.payload)}} - +

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 f4d285ac74d..36b0816ade1 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 @@ -80,7 +80,7 @@ import { VarDirective } from '../../shared/utils/var.directive'; import { ThemedThumbnailComponent } from '../../thumbnail/themed-thumbnail.component'; @Component({ - selector: 'ds-edit-bitstream-page', + selector: 'ds-base-edit-bitstream-page', styleUrls: ['./edit-bitstream-page.component.scss'], templateUrl: './edit-bitstream-page.component.html', changeDetection: ChangeDetectionStrategy.OnPush, diff --git a/src/app/bitstream-page/edit-bitstream-page/themed-edit-bitstream-page.component.ts b/src/app/bitstream-page/edit-bitstream-page/themed-edit-bitstream-page.component.ts index 4d8a9946f54..7e922485cb6 100644 --- a/src/app/bitstream-page/edit-bitstream-page/themed-edit-bitstream-page.component.ts +++ b/src/app/bitstream-page/edit-bitstream-page/themed-edit-bitstream-page.component.ts @@ -4,10 +4,11 @@ import { ThemedComponent } from '../../shared/theme-support/themed.component'; import { EditBitstreamPageComponent } from './edit-bitstream-page.component'; @Component({ - selector: 'ds-themed-edit-bitstream-page', + selector: 'ds-edit-bitstream-page', styleUrls: [], templateUrl: '../../shared/theme-support/themed.component.html', standalone: true, + imports: [EditBitstreamPageComponent], }) export class ThemedEditBitstreamPageComponent extends ThemedComponent { protected getComponentName(): string { diff --git a/src/app/breadcrumbs/breadcrumbs.component.ts b/src/app/breadcrumbs/breadcrumbs.component.ts index 2483335245b..9820d672c98 100644 --- a/src/app/breadcrumbs/breadcrumbs.component.ts +++ b/src/app/breadcrumbs/breadcrumbs.component.ts @@ -18,7 +18,7 @@ import { BreadcrumbsService } from './breadcrumbs.service'; * Component representing the breadcrumbs of a page */ @Component({ - selector: 'ds-breadcrumbs', + selector: 'ds-base-breadcrumbs', templateUrl: './breadcrumbs.component.html', styleUrls: ['./breadcrumbs.component.scss'], standalone: true, diff --git a/src/app/breadcrumbs/themed-breadcrumbs.component.ts b/src/app/breadcrumbs/themed-breadcrumbs.component.ts index 2e471fd92de..255af605dc5 100644 --- a/src/app/breadcrumbs/themed-breadcrumbs.component.ts +++ b/src/app/breadcrumbs/themed-breadcrumbs.component.ts @@ -7,10 +7,11 @@ import { BreadcrumbsComponent } from './breadcrumbs.component'; * Themed wrapper for BreadcrumbsComponent */ @Component({ - selector: 'ds-themed-breadcrumbs', + selector: 'ds-breadcrumbs', styleUrls: [], templateUrl: '../shared/theme-support/themed.component.html', standalone: true, + imports: [BreadcrumbsComponent], }) export class ThemedBreadcrumbsComponent extends ThemedComponent { protected getComponentName(): string { 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 7cdb083c106..edd7cd951a4 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 @@ -28,7 +28,6 @@ import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.serv import { PaginationService } from '../../core/pagination/pagination.service'; import { Community } from '../../core/shared/community.model'; import { Item } from '../../core/shared/item.model'; -import { BrowseByComponent } from '../../shared/browse-by/browse-by.component'; import { ThemedBrowseByComponent } from '../../shared/browse-by/themed-browse-by.component'; import { ThemedComcolPageBrowseByComponent } from '../../shared/comcol/comcol-page-browse-by/themed-comcol-page-browse-by.component'; import { ComcolPageContentComponent } from '../../shared/comcol/comcol-page-content/comcol-page-content.component'; @@ -135,7 +134,6 @@ describe('BrowseByDateComponent', () => { ThemedComcolPageHandleComponent, ComcolPageContentComponent, ThemedComcolPageBrowseByComponent, - BrowseByComponent, ThemedLoadingComponent, ThemedBrowseByComponent, ], 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 3382a46f583..c84fc4cb77f 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 @@ -35,7 +35,6 @@ import { DSpaceObjectDataService } from '../../core/data/dspace-object-data.serv import { RemoteData } from '../../core/data/remote-data'; import { PaginationService } from '../../core/pagination/pagination.service'; import { Item } from '../../core/shared/item.model'; -import { BrowseByComponent } from '../../shared/browse-by/browse-by.component'; import { ThemedComcolPageBrowseByComponent } from '../../shared/comcol/comcol-page-browse-by/themed-comcol-page-browse-by.component'; import { ComcolPageContentComponent } from '../../shared/comcol/comcol-page-content/comcol-page-content.component'; import { ThemedComcolPageHandleComponent } from '../../shared/comcol/comcol-page-handle/themed-comcol-page-handle.component'; @@ -72,7 +71,6 @@ import { ComcolPageContentComponent, DsoEditMenuComponent, ThemedComcolPageBrowseByComponent, - BrowseByComponent, TranslateModule, ThemedLoadingComponent, ThemedBrowseByComponent, 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 69c3c31c466..22e564ac27c 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,6 +1,6 @@
diff --git a/src/app/browse-by/browse-by-metadata/browse-by-metadata.component.ts b/src/app/browse-by/browse-by-metadata/browse-by-metadata.component.ts index c3bad2a9232..3c893f5259e 100644 --- a/src/app/browse-by/browse-by-metadata/browse-by-metadata.component.ts +++ b/src/app/browse-by/browse-by-metadata/browse-by-metadata.component.ts @@ -45,7 +45,6 @@ import { BrowseEntry } from '../../core/shared/browse-entry.model'; import { Context } from '../../core/shared/context.model'; import { Item } from '../../core/shared/item.model'; import { getFirstSucceededRemoteData } from '../../core/shared/operators'; -import { BrowseByComponent } from '../../shared/browse-by/browse-by.component'; import { ThemedComcolPageBrowseByComponent } from '../../shared/comcol/comcol-page-browse-by/themed-comcol-page-browse-by.component'; import { ComcolPageContentComponent } from '../../shared/comcol/comcol-page-content/comcol-page-content.component'; import { ThemedComcolPageHandleComponent } from '../../shared/comcol/comcol-page-handle/themed-comcol-page-handle.component'; @@ -78,7 +77,6 @@ export const BBM_PAGINATION_ID = 'bbm'; ComcolPageContentComponent, DsoEditMenuComponent, ThemedComcolPageBrowseByComponent, - BrowseByComponent, TranslateModule, ThemedLoadingComponent, ThemedBrowseByComponent, diff --git a/src/app/browse-by/browse-by-taxonomy/browse-by-taxonomy.component.ts b/src/app/browse-by/browse-by-taxonomy/browse-by-taxonomy.component.ts index 39a90de83ef..94956f257d5 100644 --- a/src/app/browse-by/browse-by-taxonomy/browse-by-taxonomy.component.ts +++ b/src/app/browse-by/browse-by-taxonomy/browse-by-taxonomy.component.ts @@ -27,7 +27,6 @@ import { Context } from '../../core/shared/context.model'; import { HierarchicalBrowseDefinition } from '../../core/shared/hierarchical-browse-definition.model'; import { VocabularyEntryDetail } from '../../core/submission/vocabularies/models/vocabulary-entry-detail.model'; import { VocabularyOptions } from '../../core/submission/vocabularies/models/vocabulary-options.model'; -import { BrowseByComponent } from '../../shared/browse-by/browse-by.component'; import { ThemedBrowseByComponent } from '../../shared/browse-by/themed-browse-by.component'; import { ThemedComcolPageBrowseByComponent } from '../../shared/comcol/comcol-page-browse-by/themed-comcol-page-browse-by.component'; import { ComcolPageContentComponent } from '../../shared/comcol/comcol-page-content/comcol-page-content.component'; @@ -55,7 +54,6 @@ import { BrowseByDataType } from '../browse-by-switcher/browse-by-data-type'; ComcolPageContentComponent, DsoEditMenuComponent, ThemedComcolPageBrowseByComponent, - BrowseByComponent, TranslateModule, ThemedLoadingComponent, ThemedBrowseByComponent, diff --git a/src/app/browse-by/browse-by-title/browse-by-title.component.spec.ts b/src/app/browse-by/browse-by-title/browse-by-title.component.spec.ts index a184a449531..e2e022391a6 100644 --- a/src/app/browse-by/browse-by-title/browse-by-title.component.spec.ts +++ b/src/app/browse-by/browse-by-title/browse-by-title.component.spec.ts @@ -25,7 +25,6 @@ import { ItemDataService } from '../../core/data/item-data.service'; import { PaginationService } from '../../core/pagination/pagination.service'; import { Community } from '../../core/shared/community.model'; import { Item } from '../../core/shared/item.model'; -import { BrowseByComponent } from '../../shared/browse-by/browse-by.component'; import { ThemedBrowseByComponent } from '../../shared/browse-by/themed-browse-by.component'; import { ThemedComcolPageBrowseByComponent } from '../../shared/comcol/comcol-page-browse-by/themed-comcol-page-browse-by.component'; import { ComcolPageContentComponent } from '../../shared/comcol/comcol-page-content/comcol-page-content.component'; @@ -108,7 +107,6 @@ describe('BrowseByTitleComponent', () => { ComcolPageContentComponent, DsoEditMenuComponent, ThemedComcolPageBrowseByComponent, - BrowseByComponent, ThemedLoadingComponent, ThemedBrowseByComponent, ] }, diff --git a/src/app/browse-by/browse-by-title/browse-by-title.component.ts b/src/app/browse-by/browse-by-title/browse-by-title.component.ts index 38c4c1333c2..d99332baf18 100644 --- a/src/app/browse-by/browse-by-title/browse-by-title.component.ts +++ b/src/app/browse-by/browse-by-title/browse-by-title.component.ts @@ -15,7 +15,6 @@ import { SortDirection, SortOptions, } from '../../core/cache/models/sort-options.model'; -import { BrowseByComponent } from '../../shared/browse-by/browse-by.component'; import { ThemedBrowseByComponent } from '../../shared/browse-by/themed-browse-by.component'; import { ThemedComcolPageBrowseByComponent } from '../../shared/comcol/comcol-page-browse-by/themed-comcol-page-browse-by.component'; import { ComcolPageContentComponent } from '../../shared/comcol/comcol-page-content/comcol-page-content.component'; @@ -47,7 +46,6 @@ import { ComcolPageContentComponent, DsoEditMenuComponent, ThemedComcolPageBrowseByComponent, - BrowseByComponent, TranslateModule, ThemedLoadingComponent, ThemedBrowseByComponent, diff --git a/src/app/collection-page/collection-item-mapper/collection-item-mapper.component.html b/src/app/collection-page/collection-item-mapper/collection-item-mapper.component.html index 77f85d5f78e..3ca9665b1cc 100644 --- a/src/app/collection-page/collection-item-mapper/collection-item-mapper.component.html +++ b/src/app/collection-page/collection-item-mapper/collection-item-mapper.component.html @@ -28,14 +28,14 @@

{{'collection.edit.item-mapper.head' | translate}}

- - +
diff --git a/src/app/collection-page/collection-page.component.html b/src/app/collection-page/collection-page.component.html index d5da37c12f7..f9739a4aa93 100644 --- a/src/app/collection-page/collection-page.component.html +++ b/src/app/collection-page/collection-page.component.html @@ -17,10 +17,10 @@ - - +
- - +
@@ -55,7 +55,7 @@
- +
\ No newline at end of file diff --git a/src/app/collection-page/collection-page.component.ts b/src/app/collection-page/collection-page.component.ts index c015213ee1d..5b5d0a84d7f 100644 --- a/src/app/collection-page/collection-page.component.ts +++ b/src/app/collection-page/collection-page.component.ts @@ -54,7 +54,7 @@ import { ViewTrackerComponent } from '../statistics/angulartics/dspace/view-trac import { getCollectionPageRoute } from './collection-page-routing-paths'; @Component({ - selector: 'ds-collection-page', + selector: 'ds-base-collection-page', styleUrls: ['./collection-page.component.scss'], templateUrl: './collection-page.component.html', changeDetection: ChangeDetectionStrategy.OnPush, diff --git a/src/app/collection-page/create-collection-page/create-collection-page.component.html b/src/app/collection-page/create-collection-page/create-collection-page.component.html index f3f97856927..0907290ac38 100644 --- a/src/app/collection-page/create-collection-page/create-collection-page.component.html +++ b/src/app/collection-page/create-collection-page/create-collection-page.component.html @@ -1,10 +1,15 @@ -
-
-
-

{{'collection.create.sub-head' | translate:{ parent: dsoNameService.getName((parentRD$| async)?.payload) } }}

-
+
+
+
+

{{ 'collection.create.sub-head' | translate:{ parent: dsoNameService.getName((parentRD$| async)?.payload) } }}

- +
+ +
+ +
+
diff --git a/src/app/collection-page/create-collection-page/create-collection-page.component.ts b/src/app/collection-page/create-collection-page/create-collection-page.component.ts index a3594ef152f..a26bc9d6f8d 100644 --- a/src/app/collection-page/create-collection-page/create-collection-page.component.ts +++ b/src/app/collection-page/create-collection-page/create-collection-page.component.ts @@ -1,4 +1,7 @@ -import { AsyncPipe } from '@angular/common'; +import { + AsyncPipe, + NgIf, +} from '@angular/common'; import { Component } from '@angular/core'; import { Router } from '@angular/router'; import { @@ -13,6 +16,7 @@ import { RequestService } from '../../core/data/request.service'; import { RouteService } from '../../core/services/route.service'; import { Collection } from '../../core/shared/collection.model'; import { CreateComColPageComponent } from '../../shared/comcol/comcol-forms/create-comcol-page/create-comcol-page.component'; +import { ThemedLoadingComponent } from '../../shared/loading/themed-loading.component'; import { NotificationsService } from '../../shared/notifications/notifications.service'; import { CollectionFormComponent } from '../collection-form/collection-form.component'; @@ -27,6 +31,8 @@ import { CollectionFormComponent } from '../collection-form/collection-form.comp CollectionFormComponent, TranslateModule, AsyncPipe, + ThemedLoadingComponent, + NgIf, ], standalone: true, }) diff --git a/src/app/collection-page/edit-collection-page/collection-source/collection-source.component.html b/src/app/collection-page/edit-collection-page/collection-source/collection-source.component.html index 7b4ac97421d..22940850963 100644 --- a/src/app/collection-page/edit-collection-page/collection-source/collection-source.component.html +++ b/src/app/collection-page/edit-collection-page/collection-source/collection-source.component.html @@ -25,7 +25,7 @@

{{ 'collection.edit.tabs.source.head' | translate }}

- +

{{ 'collection.edit.tabs.source.form.head' | translate }}

diff --git a/src/app/collection-page/edit-item-template-page/edit-item-template-page.component.html b/src/app/collection-page/edit-item-template-page/edit-item-template-page.component.html index 8d095dd2296..7f0b2efba22 100644 --- a/src/app/collection-page/edit-item-template-page/edit-item-template-page.component.html +++ b/src/app/collection-page/edit-item-template-page/edit-item-template-page.component.html @@ -3,10 +3,10 @@

{{ 'collection.edit.template.head' | translate:{ collection: dsoNameService.getName(collection) } }}

- +
- +
diff --git a/src/app/collection-page/edit-item-template-page/edit-item-template-page.component.spec.ts b/src/app/collection-page/edit-item-template-page/edit-item-template-page.component.spec.ts index 7fa29919f81..4d33e7d008a 100644 --- a/src/app/collection-page/edit-item-template-page/edit-item-template-page.component.spec.ts +++ b/src/app/collection-page/edit-item-template-page/edit-item-template-page.component.spec.ts @@ -12,7 +12,6 @@ import { of as observableOf } from 'rxjs'; import { ItemTemplateDataService } from '../../core/data/item-template-data.service'; import { Collection } from '../../core/shared/collection.model'; -import { DsoEditMetadataComponent } from '../../dso-shared/dso-edit-metadata/dso-edit-metadata.component'; import { ThemedDsoEditMetadataComponent } from '../../dso-shared/dso-edit-metadata/themed-dso-edit-metadata.component'; import { getMockThemeService } from '../../shared/mocks/theme-service.mock'; import { NotificationsService } from '../../shared/notifications/notifications.service'; @@ -51,7 +50,7 @@ describe('EditItemTemplatePageComponent', () => { schemas: [NO_ERRORS_SCHEMA], }).overrideComponent(EditItemTemplatePageComponent, { remove: { - imports: [ThemedDsoEditMetadataComponent, DsoEditMetadataComponent], + imports: [ThemedDsoEditMetadataComponent], }, }).compileComponents(); })); diff --git a/src/app/collection-page/edit-item-template-page/edit-item-template-page.component.ts b/src/app/collection-page/edit-item-template-page/edit-item-template-page.component.ts index eb44ffdc9be..f7c5dc4b14a 100644 --- a/src/app/collection-page/edit-item-template-page/edit-item-template-page.component.ts +++ b/src/app/collection-page/edit-item-template-page/edit-item-template-page.component.ts @@ -24,7 +24,6 @@ import { RemoteData } from '../../core/data/remote-data'; import { Collection } from '../../core/shared/collection.model'; import { Item } from '../../core/shared/item.model'; import { getFirstSucceededRemoteDataPayload } from '../../core/shared/operators'; -import { DsoEditMetadataComponent } from '../../dso-shared/dso-edit-metadata/dso-edit-metadata.component'; import { ThemedDsoEditMetadataComponent } from '../../dso-shared/dso-edit-metadata/themed-dso-edit-metadata.component'; import { AlertComponent } from '../../shared/alert/alert.component'; import { AlertType } from '../../shared/alert/alert-type'; @@ -33,11 +32,10 @@ import { VarDirective } from '../../shared/utils/var.directive'; import { getCollectionEditRoute } from '../collection-page-routing-paths'; @Component({ - selector: 'ds-edit-item-template-page', + selector: 'ds-base-edit-item-template-page', templateUrl: './edit-item-template-page.component.html', imports: [ ThemedDsoEditMetadataComponent, - DsoEditMetadataComponent, RouterLink, AsyncPipe, VarDirective, diff --git a/src/app/collection-page/edit-item-template-page/themed-edit-item-template-page.component.ts b/src/app/collection-page/edit-item-template-page/themed-edit-item-template-page.component.ts index 2dff5578351..421049990ae 100644 --- a/src/app/collection-page/edit-item-template-page/themed-edit-item-template-page.component.ts +++ b/src/app/collection-page/edit-item-template-page/themed-edit-item-template-page.component.ts @@ -4,10 +4,11 @@ import { ThemedComponent } from '../../shared/theme-support/themed.component'; import { EditItemTemplatePageComponent } from './edit-item-template-page.component'; @Component({ - selector: 'ds-themed-edit-item-template-page', + selector: 'ds-edit-item-template-page', styleUrls: [], templateUrl: '../../shared/theme-support/themed.component.html', standalone: true, + imports: [EditItemTemplatePageComponent], }) /** * Component for editing the item template of a collection diff --git a/src/app/collection-page/themed-collection-page.component.ts b/src/app/collection-page/themed-collection-page.component.ts index e095e6eb68a..c84d7c5fb44 100644 --- a/src/app/collection-page/themed-collection-page.component.ts +++ b/src/app/collection-page/themed-collection-page.component.ts @@ -7,10 +7,11 @@ import { CollectionPageComponent } from './collection-page.component'; * Themed wrapper for CollectionPageComponent */ @Component({ - selector: 'ds-themed-collection-page', + selector: 'ds-collection-page', styleUrls: [], templateUrl: '../shared/theme-support/themed.component.html', standalone: true, + imports: [CollectionPageComponent], }) export class ThemedCollectionPageComponent extends ThemedComponent { protected getComponentName(): string { diff --git a/src/app/community-list-page/community-list-page.component.html b/src/app/community-list-page/community-list-page.component.html index 4392fb87d03..ca052014780 100644 --- a/src/app/community-list-page/community-list-page.component.html +++ b/src/app/community-list-page/community-list-page.component.html @@ -1,4 +1,4 @@

{{ 'communityList.title' | translate }}

- +
diff --git a/src/app/community-list-page/community-list-page.component.ts b/src/app/community-list-page/community-list-page.component.ts index aaf7bc2000a..ca0db89f53d 100644 --- a/src/app/community-list-page/community-list-page.component.ts +++ b/src/app/community-list-page/community-list-page.component.ts @@ -8,7 +8,7 @@ import { ThemedCommunityListComponent } from './community-list/themed-community- * navigated to with community-list.page.routing.module */ @Component({ - selector: 'ds-community-list-page', + selector: 'ds-base-community-list-page', templateUrl: './community-list-page.component.html', standalone: true, imports: [ThemedCommunityListComponent, TranslateModule], diff --git a/src/app/community-list-page/community-list/community-list.component.html b/src/app/community-list-page/community-list/community-list.component.html index 0d678299e14..82238ddd0d1 100644 --- a/src/app/community-list-page/community-list/community-list.component.html +++ b/src/app/community-list-page/community-list/community-list.component.html @@ -1,4 +1,4 @@ - + {{ 'communityList.showMore' | translate }} - +
@@ -61,7 +61,7 @@ - +
diff --git a/src/app/community-list-page/community-list/community-list.component.ts b/src/app/community-list-page/community-list/community-list.component.ts index e0456ca700f..5819471d7e5 100644 --- a/src/app/community-list-page/community-list/community-list.component.ts +++ b/src/app/community-list-page/community-list/community-list.component.ts @@ -38,7 +38,7 @@ import { FlatNode } from '../flat-node.model'; * Which nodes were expanded is kept in the store, so this persists across pages. */ @Component({ - selector: 'ds-community-list', + selector: 'ds-base-community-list', templateUrl: './community-list.component.html', styleUrls: ['./community-list.component.scss'], standalone: true, diff --git a/src/app/community-list-page/community-list/themed-community-list.component.ts b/src/app/community-list-page/community-list/themed-community-list.component.ts index dc6c0aa3453..5340384ed5a 100644 --- a/src/app/community-list-page/community-list/themed-community-list.component.ts +++ b/src/app/community-list-page/community-list/themed-community-list.component.ts @@ -5,10 +5,11 @@ import { CommunityListComponent } from './community-list.component'; @Component({ - selector: 'ds-themed-community-list', + selector: 'ds-community-list', styleUrls: [], templateUrl: '../../shared/theme-support/themed.component.html', standalone: true, + imports: [CommunityListComponent], }) export class ThemedCommunityListComponent extends ThemedComponent { protected getComponentName(): string { diff --git a/src/app/community-list-page/themed-community-list-page.component.ts b/src/app/community-list-page/themed-community-list-page.component.ts index 4f0575c7db7..d427b1bec1c 100644 --- a/src/app/community-list-page/themed-community-list-page.component.ts +++ b/src/app/community-list-page/themed-community-list-page.component.ts @@ -7,10 +7,11 @@ import { CommunityListPageComponent } from './community-list-page.component'; * Themed wrapper for CommunityListPageComponent */ @Component({ - selector: 'ds-themed-community-list-page', + selector: 'ds-community-list-page', styleUrls: [], templateUrl: '../shared/theme-support/themed.component.html', standalone: true, + imports: [CommunityListPageComponent], }) export class ThemedCommunityListPageComponent extends ThemedComponent { protected getComponentName(): string { diff --git a/src/app/community-page/community-page.component.html b/src/app/community-page/community-page.component.html index b3e577af7d3..a695e2019a3 100644 --- a/src/app/community-page/community-page.component.html +++ b/src/app/community-page/community-page.component.html @@ -10,8 +10,8 @@ - - + + @@ -25,8 +25,8 @@
- - + +
@@ -39,5 +39,5 @@ - + diff --git a/src/app/community-page/community-page.component.ts b/src/app/community-page/community-page.component.ts index ce3d05aef9f..bdb3a50c6b7 100644 --- a/src/app/community-page/community-page.component.ts +++ b/src/app/community-page/community-page.component.ts @@ -47,7 +47,7 @@ import { ThemedCollectionPageSubCollectionListComponent } from './sections/sub-c import { ThemedCommunityPageSubCommunityListComponent } from './sections/sub-com-col-section/sub-community-list/themed-community-page-sub-community-list.component'; @Component({ - selector: 'ds-community-page', + selector: 'ds-base-community-page', styleUrls: ['./community-page.component.scss'], templateUrl: './community-page.component.html', changeDetection: ChangeDetectionStrategy.OnPush, diff --git a/src/app/community-page/create-community-page/create-community-page.component.html b/src/app/community-page/create-community-page/create-community-page.component.html index 57039040c2a..4c634dab8e9 100644 --- a/src/app/community-page/create-community-page/create-community-page.component.html +++ b/src/app/community-page/create-community-page/create-community-page.component.html @@ -1,9 +1,10 @@ -
+
-

{{ 'community.create.sub-head' | translate:{ parent: dsoNameService.getName(parent) } }}

+

{{ 'community.create.sub-head' | translate:{ parent: dsoNameService.getName(parent) } }}

@@ -11,3 +12,7 @@

{{ 'community.crea (back)="navigateToHome()" (finish)="navigateToNewPage()">

+ +
+ +
diff --git a/src/app/community-page/create-community-page/create-community-page.component.ts b/src/app/community-page/create-community-page/create-community-page.component.ts index acc5279a5c1..082f6c4f0b4 100644 --- a/src/app/community-page/create-community-page/create-community-page.component.ts +++ b/src/app/community-page/create-community-page/create-community-page.component.ts @@ -15,6 +15,7 @@ import { RequestService } from '../../core/data/request.service'; import { RouteService } from '../../core/services/route.service'; import { Community } from '../../core/shared/community.model'; import { CreateComColPageComponent } from '../../shared/comcol/comcol-forms/create-comcol-page/create-comcol-page.component'; +import { ThemedLoadingComponent } from '../../shared/loading/themed-loading.component'; import { NotificationsService } from '../../shared/notifications/notifications.service'; import { VarDirective } from '../../shared/utils/var.directive'; import { CommunityFormComponent } from '../community-form/community-form.component'; @@ -32,6 +33,7 @@ import { CommunityFormComponent } from '../community-form/community-form.compone VarDirective, NgIf, AsyncPipe, + ThemedLoadingComponent, ], standalone: true, }) diff --git a/src/app/community-page/sections/sub-com-col-section/sub-collection-list/community-page-sub-collection-list.component.html b/src/app/community-page/sections/sub-com-col-section/sub-collection-list/community-page-sub-collection-list.component.html index b5fbf1a01dd..59d7b3bb5e2 100644 --- a/src/app/community-page/sections/sub-com-col-section/sub-collection-list/community-page-sub-collection-list.component.html +++ b/src/app/community-page/sections/sub-com-col-section/sub-collection-list/community-page-sub-collection-list.component.html @@ -9,5 +9,5 @@

{{'community.sub-collection-list.head' | translate}}

- + diff --git a/src/app/community-page/sections/sub-com-col-section/sub-collection-list/community-page-sub-collection-list.component.ts b/src/app/community-page/sections/sub-com-col-section/sub-collection-list/community-page-sub-collection-list.component.ts index 2935f255958..1e8ff1d46c3 100644 --- a/src/app/community-page/sections/sub-com-col-section/sub-collection-list/community-page-sub-collection-list.component.ts +++ b/src/app/community-page/sections/sub-com-col-section/sub-collection-list/community-page-sub-collection-list.component.ts @@ -36,7 +36,7 @@ import { PaginationComponentOptions } from '../../../../shared/pagination/pagina import { VarDirective } from '../../../../shared/utils/var.directive'; @Component({ - selector: 'ds-community-page-sub-collection-list', + selector: 'ds-base-community-page-sub-collection-list', styleUrls: ['./community-page-sub-collection-list.component.scss'], templateUrl: './community-page-sub-collection-list.component.html', animations: [fadeIn], diff --git a/src/app/community-page/sections/sub-com-col-section/sub-collection-list/themed-community-page-sub-collection-list.component.ts b/src/app/community-page/sections/sub-com-col-section/sub-collection-list/themed-community-page-sub-collection-list.component.ts index ff5d057b312..4a965bc9264 100644 --- a/src/app/community-page/sections/sub-com-col-section/sub-collection-list/themed-community-page-sub-collection-list.component.ts +++ b/src/app/community-page/sections/sub-com-col-section/sub-collection-list/themed-community-page-sub-collection-list.component.ts @@ -8,10 +8,11 @@ import { ThemedComponent } from '../../../../shared/theme-support/themed.compone import { CommunityPageSubCollectionListComponent } from './community-page-sub-collection-list.component'; @Component({ - selector: 'ds-themed-community-page-sub-collection-list', + selector: 'ds-community-page-sub-collection-list', styleUrls: [], templateUrl: '../../../../shared/theme-support/themed.component.html', standalone: true, + imports: [CommunityPageSubCollectionListComponent], }) export class ThemedCollectionPageSubCollectionListComponent extends ThemedComponent { @Input() community: Community; diff --git a/src/app/community-page/sections/sub-com-col-section/sub-com-col-section.component.html b/src/app/community-page/sections/sub-com-col-section/sub-com-col-section.component.html index 515e08ffdfe..a811014bcc9 100644 --- a/src/app/community-page/sections/sub-com-col-section/sub-com-col-section.component.html +++ b/src/app/community-page/sections/sub-com-col-section/sub-com-col-section.component.html @@ -1,8 +1,8 @@ - - - + - + diff --git a/src/app/community-page/sections/sub-com-col-section/sub-community-list/community-page-sub-community-list.component.html b/src/app/community-page/sections/sub-com-col-section/sub-community-list/community-page-sub-community-list.component.html index 0834d08ba58..7f9840f6b7f 100644 --- a/src/app/community-page/sections/sub-com-col-section/sub-community-list/community-page-sub-community-list.component.html +++ b/src/app/community-page/sections/sub-com-col-section/sub-community-list/community-page-sub-community-list.component.html @@ -9,5 +9,5 @@

{{'community.sub-community-list.head' | translate}}

- + diff --git a/src/app/community-page/sections/sub-com-col-section/sub-community-list/community-page-sub-community-list.component.ts b/src/app/community-page/sections/sub-com-col-section/sub-community-list/community-page-sub-community-list.component.ts index 4f74eff601b..36bd9919bb8 100644 --- a/src/app/community-page/sections/sub-com-col-section/sub-community-list/community-page-sub-community-list.component.ts +++ b/src/app/community-page/sections/sub-com-col-section/sub-community-list/community-page-sub-community-list.component.ts @@ -35,7 +35,7 @@ import { PaginationComponentOptions } from '../../../../shared/pagination/pagina import { VarDirective } from '../../../../shared/utils/var.directive'; @Component({ - selector: 'ds-community-page-sub-community-list', + selector: 'ds-base-community-page-sub-community-list', styleUrls: ['./community-page-sub-community-list.component.scss'], templateUrl: './community-page-sub-community-list.component.html', animations: [fadeIn], diff --git a/src/app/community-page/sections/sub-com-col-section/sub-community-list/themed-community-page-sub-community-list.component.ts b/src/app/community-page/sections/sub-com-col-section/sub-community-list/themed-community-page-sub-community-list.component.ts index 11b62d68e46..5988ad0f5ea 100644 --- a/src/app/community-page/sections/sub-com-col-section/sub-community-list/themed-community-page-sub-community-list.component.ts +++ b/src/app/community-page/sections/sub-com-col-section/sub-community-list/themed-community-page-sub-community-list.component.ts @@ -8,10 +8,11 @@ import { ThemedComponent } from '../../../../shared/theme-support/themed.compone import { CommunityPageSubCommunityListComponent } from './community-page-sub-community-list.component'; @Component({ - selector: 'ds-themed-community-page-sub-community-list', + selector: 'ds-community-page-sub-community-list', styleUrls: [], templateUrl: '../../../../shared/theme-support/themed.component.html', standalone: true, + imports: [CommunityPageSubCommunityListComponent], }) export class ThemedCommunityPageSubCommunityListComponent extends ThemedComponent { diff --git a/src/app/community-page/themed-community-page.component.ts b/src/app/community-page/themed-community-page.component.ts index 41a29607190..b655452041a 100644 --- a/src/app/community-page/themed-community-page.component.ts +++ b/src/app/community-page/themed-community-page.component.ts @@ -7,10 +7,11 @@ import { CommunityPageComponent } from './community-page.component'; * Themed wrapper for CommunityPageComponent */ @Component({ - selector: 'ds-themed-community-page', + selector: 'ds-community-page', styleUrls: [], templateUrl: '../shared/theme-support/themed.component.html', standalone: true, + imports: [CommunityPageComponent], }) export class ThemedCommunityPageComponent extends ThemedComponent { protected getComponentName(): string { diff --git a/src/app/core/auth/models/auth-status.model.ts b/src/app/core/auth/models/auth-status.model.ts index 1a6938887d5..f25e5a48928 100644 --- a/src/app/core/auth/models/auth-status.model.ts +++ b/src/app/core/auth/models/auth-status.model.ts @@ -36,14 +36,14 @@ export class AuthStatus implements CacheableObject { * The unique identifier of this auth status */ @autoserialize - id: string; + id: string; /** * The type for this AuthStatus */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; /** * The UUID of this auth status @@ -57,19 +57,19 @@ export class AuthStatus implements CacheableObject { * True if REST API is up and running, should never return false */ @autoserialize - okay: boolean; + okay: boolean; /** * If the auth status represents an authenticated state */ @autoserialize - authenticated: boolean; + authenticated: boolean; /** * The {@link HALLink}s for this AuthStatus */ @deserialize - _links: { + _links: { self: HALLink; eperson: HALLink; specialGroups: HALLink; @@ -80,32 +80,32 @@ export class AuthStatus implements CacheableObject { * Will be undefined unless the eperson {@link HALLink} has been resolved. */ @link(EPERSON) - eperson?: Observable>; + eperson?: Observable>; /** * The SpecialGroup of this auth status * Will be undefined unless the SpecialGroup {@link HALLink} has been resolved. */ @link(GROUP, true) - specialGroups?: Observable>>; + specialGroups?: Observable>>; /** * True if the token is valid, false if there was no token or the token wasn't valid */ @autoserialize - token?: AuthTokenInfo; + token?: AuthTokenInfo; /** * Authentication error if there was one for this status */ // TODO should be refactored to use the RemoteData error @autoserialize - error?: AuthError; + error?: AuthError; /** * All authentication methods enabled at the backend */ @autoserialize - authMethods: AuthMethod[]; + authMethods: AuthMethod[]; } diff --git a/src/app/core/auth/models/short-lived-token.model.ts b/src/app/core/auth/models/short-lived-token.model.ts index d91a26e990a..5e8587d02dd 100644 --- a/src/app/core/auth/models/short-lived-token.model.ts +++ b/src/app/core/auth/models/short-lived-token.model.ts @@ -22,19 +22,19 @@ export class ShortLivedToken implements CacheableObject { */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; /** * The value for this ShortLivedToken */ @autoserializeAs('token') - value: string; + value: string; /** * The {@link HALLink}s for this ShortLivedToken */ @deserialize - _links: { + _links: { self: HALLink; }; } diff --git a/src/app/core/cache/models/self-link.model.ts b/src/app/core/cache/models/self-link.model.ts index 903a7794951..a87acdd5065 100644 --- a/src/app/core/cache/models/self-link.model.ts +++ b/src/app/core/cache/models/self-link.model.ts @@ -3,9 +3,9 @@ import { autoserialize } from 'cerialize'; export class SelfLink { @autoserialize - self: string; + self: string; @autoserialize - uuid: string; + uuid: string; } diff --git a/src/app/core/config/models/bulk-access-condition-options.model.ts b/src/app/core/config/models/bulk-access-condition-options.model.ts index c4913438524..514c682b4e5 100644 --- a/src/app/core/config/models/bulk-access-condition-options.model.ts +++ b/src/app/core/config/models/bulk-access-condition-options.model.ts @@ -25,19 +25,19 @@ export class BulkAccessConditionOptions extends ConfigObject { */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; @autoserializeAs(String, 'name') - uuid: string; + uuid: string; @autoserialize - id: string; + id: string; @autoserialize - itemAccessConditionOptions: AccessesConditionOption[]; + itemAccessConditionOptions: AccessesConditionOption[]; @autoserialize - bitstreamAccessConditionOptions: AccessesConditionOption[]; + bitstreamAccessConditionOptions: AccessesConditionOption[]; _links: { self: HALLink }; } diff --git a/src/app/core/config/models/config-submission-access.model.ts b/src/app/core/config/models/config-submission-access.model.ts index 4617dc47191..2e9a9291835 100644 --- a/src/app/core/config/models/config-submission-access.model.ts +++ b/src/app/core/config/models/config-submission-access.model.ts @@ -22,25 +22,25 @@ export class SubmissionAccessModel extends ConfigObject { * A list of available item access conditions */ @autoserialize - accessConditionOptions: AccessesConditionOption[]; + accessConditionOptions: AccessesConditionOption[]; /** * Boolean that indicates whether the current item must be findable via search or browse. */ @autoserialize - discoverable: boolean; + discoverable: boolean; /** * Boolean that indicates whether or not the user can change the discoverable flag. */ @autoserialize - canChangeDiscoverable: boolean; + canChangeDiscoverable: boolean; /** * The links to all related resources returned by the rest api. */ @deserialize - _links: { + _links: { self: HALLink }; diff --git a/src/app/core/config/models/config-submission-definition.model.ts b/src/app/core/config/models/config-submission-definition.model.ts index 2d6b1ad604c..eda4f54340b 100644 --- a/src/app/core/config/models/config-submission-definition.model.ts +++ b/src/app/core/config/models/config-submission-definition.model.ts @@ -23,20 +23,20 @@ export class SubmissionDefinitionModel extends ConfigObject { * A boolean representing if this submission definition is the default or not */ @autoserialize - isDefault: boolean; + isDefault: boolean; /** * A list of SubmissionSectionModel that are present in this submission definition */ // TODO refactor using remotedata @deserialize - sections: PaginatedList; + sections: PaginatedList; /** * The links to all related resources returned by the rest api. */ @deserialize - _links: { + _links: { self: HALLink, collections: HALLink, sections: HALLink diff --git a/src/app/core/config/models/config-submission-form.model.ts b/src/app/core/config/models/config-submission-form.model.ts index f6011adc764..c524a839160 100644 --- a/src/app/core/config/models/config-submission-form.model.ts +++ b/src/app/core/config/models/config-submission-form.model.ts @@ -27,5 +27,5 @@ export class SubmissionFormModel extends ConfigObject { * An array of [FormRowModel] that are present in this form */ @autoserialize - rows: FormRowModel[]; + rows: FormRowModel[]; } diff --git a/src/app/core/config/models/config-submission-section.model.ts b/src/app/core/config/models/config-submission-section.model.ts index 0d4ae9aa102..feb4fc9cb07 100644 --- a/src/app/core/config/models/config-submission-section.model.ts +++ b/src/app/core/config/models/config-submission-section.model.ts @@ -27,31 +27,31 @@ export class SubmissionSectionModel extends ConfigObject { * The header for this section */ @autoserialize - header: string; + header: string; /** * A boolean representing if this submission section is the mandatory or not */ @autoserialize - mandatory: boolean; + mandatory: boolean; /** * A string representing the kind of section object */ @autoserialize - sectionType: SectionsType; + sectionType: SectionsType; /** * The [SubmissionSectionVisibility] object for this section */ @autoserialize - visibility: SubmissionSectionVisibility; + visibility: SubmissionSectionVisibility; /** * The {@link HALLink}s for this SubmissionSectionModel */ @deserialize - _links: { + _links: { self: HALLink; config: HALLink; }; diff --git a/src/app/core/config/models/config-submission-upload.model.ts b/src/app/core/config/models/config-submission-upload.model.ts index edc4626f83e..cabc84d0f55 100644 --- a/src/app/core/config/models/config-submission-upload.model.ts +++ b/src/app/core/config/models/config-submission-upload.model.ts @@ -27,22 +27,22 @@ export class SubmissionUploadModel extends ConfigObject { * A list of available bitstream access conditions */ @autoserialize - accessConditionOptions: AccessConditionOption[]; + accessConditionOptions: AccessConditionOption[]; /** * An object representing the configuration describing the bitstream metadata form */ @link(SUBMISSION_FORMS_TYPE) - metadata?: Observable>; + metadata?: Observable>; @autoserialize - required: boolean; + required: boolean; @autoserialize - maxSize: number; + maxSize: number; @deserialize - _links: { + _links: { metadata: HALLink self: HALLink }; diff --git a/src/app/core/config/models/config.model.ts b/src/app/core/config/models/config.model.ts index c1db44e8919..74d090b89db 100644 --- a/src/app/core/config/models/config.model.ts +++ b/src/app/core/config/models/config.model.ts @@ -27,13 +27,13 @@ export abstract class ConfigObject implements CacheableObject { */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; /** * The links to all related resources returned by the rest api. */ @deserialize - _links: { + _links: { self: HALLink, [name: string]: HALLink }; diff --git a/src/app/core/data/feature-authorization/authorization-utils.ts b/src/app/core/data/feature-authorization/authorization-utils.ts index f763b1a38d8..cd4bc452a5e 100644 --- a/src/app/core/data/feature-authorization/authorization-utils.ts +++ b/src/app/core/data/feature-authorization/authorization-utils.ts @@ -91,5 +91,5 @@ export const oneAuthorizationMatchesFeature = (featureID: FeatureID) => return observableOf([]); } }), - map((features: Feature[]) => features.filter((feature: Feature) => feature.id === featureID).length > 0), + map((features: Feature[]) => features.filter((feature: Feature) => feature.id === featureID.valueOf()).length > 0), ); diff --git a/src/app/core/data/paginated-list.model.ts b/src/app/core/data/paginated-list.model.ts index e412af49863..ef2819afd8f 100644 --- a/src/app/core/data/paginated-list.model.ts +++ b/src/app/core/data/paginated-list.model.ts @@ -73,13 +73,13 @@ export class PaginatedList extends CacheableObject { * The type of the list */ @excludeFromEquals - type = PAGINATED_LIST; + type = PAGINATED_LIST; /** * The type of objects in the list */ @autoserialize - objectType?: ResourceType; + objectType?: ResourceType; /** * The list of objects that represents the current page @@ -90,13 +90,13 @@ export class PaginatedList extends CacheableObject { * the {@link PageInfo} object */ @autoserialize - pageInfo?: PageInfo; + pageInfo?: PageInfo; /** * The {@link HALLink}s for this PaginatedList */ @deserialize - _links: { + _links: { self: HALLink; page: HALLink[]; first?: HALLink; diff --git a/src/app/core/data/root.model.ts b/src/app/core/data/root.model.ts index 46a276fa1ff..ced115b0554 100644 --- a/src/app/core/data/root.model.ts +++ b/src/app/core/data/root.model.ts @@ -22,37 +22,37 @@ export class Root implements CacheableObject { */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; /** * The url for the dspace UI */ @autoserialize - dspaceUI: string; + dspaceUI: string; /** * The repository Name */ @autoserialize - dspaceName: string; + dspaceName: string; /** * The url for the rest api */ @autoserialize - dspaceServer: string; + dspaceServer: string; /** * The current DSpace version */ @autoserialize - dspaceVersion: string; + dspaceVersion: string; /** * The {@link HALLink}s for the root object */ @deserialize - _links: { + _links: { self: HALLink; [k: string]: HALLink | HALLink[]; }; diff --git a/src/app/core/dspace-rest/dspace-rest.service.ts b/src/app/core/dspace-rest/dspace-rest.service.ts index 67d74e95707..a75cef53bf2 100644 --- a/src/app/core/dspace-rest/dspace-rest.service.ts +++ b/src/app/core/dspace-rest/dspace-rest.service.ts @@ -151,7 +151,7 @@ export class DspaceRestService { return form; } - protected handleHttpError(err: unknown): RequestError | unknown { + protected handleHttpError(err: unknown): unknown { if (err instanceof HttpErrorResponse) { const error = new RequestError( (isNotEmpty(err?.error?.message)) ? err.error.message : err.message, diff --git a/src/app/core/dspace-rest/dspace.serializer.spec.ts b/src/app/core/dspace-rest/dspace.serializer.spec.ts index 9a6635bc98c..169dd97a579 100644 --- a/src/app/core/dspace-rest/dspace.serializer.spec.ts +++ b/src/app/core/dspace-rest/dspace.serializer.spec.ts @@ -9,13 +9,13 @@ import { DSpaceSerializer } from './dspace.serializer'; class TestModel implements HALResource { @autoserialize - id: string; + id: string; @autoserialize - name: string; + name: string; @deserialize - _links: { + _links: { self: HALLink; parents: HALLink; }; diff --git a/src/app/core/eperson/models/group.model.ts b/src/app/core/eperson/models/group.model.ts index bed55af0a2d..71923d6c55c 100644 --- a/src/app/core/eperson/models/group.model.ts +++ b/src/app/core/eperson/models/group.model.ts @@ -48,7 +48,7 @@ export class Group extends DSpaceObject { * The {@link HALLink}s for this Group */ @deserialize - _links: { + _links: { self: HALLink; subgroups: HALLink; epersons: HALLink; diff --git a/src/app/core/metadata/metadata-field.model.ts b/src/app/core/metadata/metadata-field.model.ts index 1084b4009fd..11b6e1c74e2 100644 --- a/src/app/core/metadata/metadata-field.model.ts +++ b/src/app/core/metadata/metadata-field.model.ts @@ -32,37 +32,37 @@ export class MetadataField extends ListableObject implements HALResource { */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; /** * The identifier of this metadata field */ @autoserialize - id: number; + id: number; /** * The element of this metadata field */ @autoserialize - element: string; + element: string; /** * The qualifier of this metadata field */ @autoserialize - qualifier: string; + qualifier: string; /** * The scope note of this metadata field */ @autoserialize - scopeNote: string; + scopeNote: string; /** * The {@link HALLink}s for this MetadataField */ @deserialize - _links: { + _links: { self: HALLink, schema: HALLink }; @@ -72,7 +72,7 @@ export class MetadataField extends ListableObject implements HALResource { * Will be undefined unless the schema {@link HALLink} has been resolved. */ @link(METADATA_SCHEMA) - schema?: Observable>; + schema?: Observable>; /** * Method to print this metadata field as a string without the schema diff --git a/src/app/core/metadata/metadata-schema.model.ts b/src/app/core/metadata/metadata-schema.model.ts index 85faf5d2ce7..656638b4c63 100644 --- a/src/app/core/metadata/metadata-schema.model.ts +++ b/src/app/core/metadata/metadata-schema.model.ts @@ -23,29 +23,29 @@ export class MetadataSchema extends ListableObject implements HALResource { * The unique identifier for this metadata schema */ @autoserialize - id: number; + id: number; /** * The object type */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; /** * A unique prefix that defines this schema */ @autoserialize - prefix: string; + prefix: string; /** * The namespace of this metadata schema */ @autoserialize - namespace: string; + namespace: string; @deserialize - _links: { + _links: { self: HALLink, }; diff --git a/src/app/core/notifications/models/suggestion-source.model.ts b/src/app/core/notifications/models/suggestion-source.model.ts index f8e7c70cf5a..1a757a5aa09 100644 --- a/src/app/core/notifications/models/suggestion-source.model.ts +++ b/src/app/core/notifications/models/suggestion-source.model.ts @@ -24,26 +24,26 @@ export class SuggestionSource implements CacheableObject { * The Suggestion Target id */ @autoserialize - id: string; + id: string; /** * The total number of suggestions provided by Suggestion Target for */ @autoserialize - total: number; + total: number; /** * The type of this ConfigObject */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; /** * The links to all related resources returned by the rest api. */ @deserialize - _links: { + _links: { self: HALLink, suggestiontargets: HALLink }; diff --git a/src/app/core/notifications/models/suggestion-target.model.ts b/src/app/core/notifications/models/suggestion-target.model.ts index 1cbd78ae6b9..cdc78eb4669 100644 --- a/src/app/core/notifications/models/suggestion-target.model.ts +++ b/src/app/core/notifications/models/suggestion-target.model.ts @@ -24,38 +24,38 @@ export class SuggestionTarget implements CacheableObject { * The Suggestion Target id */ @autoserialize - id: string; + id: string; /** * The Suggestion Target name to display */ @autoserialize - display: string; + display: string; /** * The Suggestion Target source to display */ @autoserialize - source: string; + source: string; /** * The total number of suggestions provided by Suggestion Target for */ @autoserialize - total: number; + total: number; /** * The type of this ConfigObject */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; /** * The links to all related resources returned by the rest api. */ @deserialize - _links: { + _links: { self: HALLink, suggestions: HALLink, target: HALLink diff --git a/src/app/core/notifications/models/suggestion.model.ts b/src/app/core/notifications/models/suggestion.model.ts index a84fe9ffe28..bd4015b4992 100644 --- a/src/app/core/notifications/models/suggestion.model.ts +++ b/src/app/core/notifications/models/suggestion.model.ts @@ -38,57 +38,57 @@ export class Suggestion implements CacheableObject { * The Suggestion id */ @autoserialize - id: string; + id: string; /** * The Suggestion name to display */ @autoserialize - display: string; + display: string; /** * The Suggestion source to display */ @autoserialize - source: string; + source: string; /** * The Suggestion external source uri */ @autoserialize - externalSourceUri: string; + externalSourceUri: string; /** * The Total Score of the suggestion */ @autoserialize - score: string; + score: string; /** * The total number of suggestions provided by Suggestion Target for */ @autoserialize - evidences: SuggestionEvidences; + evidences: SuggestionEvidences; /** * All metadata of this suggestion object */ @excludeFromEquals @autoserializeAs(MetadataMapSerializer) - metadata: MetadataMap; + metadata: MetadataMap; /** * The type of this ConfigObject */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; /** * The links to all related resources returned by the rest api. */ @deserialize - _links: { + _links: { self: HALLink, target: HALLink }; diff --git a/src/app/core/notifications/qa/models/quality-assurance-event.model.ts b/src/app/core/notifications/qa/models/quality-assurance-event.model.ts index 9210d8f6f90..e015dd01d92 100644 --- a/src/app/core/notifications/qa/models/quality-assurance-event.model.ts +++ b/src/app/core/notifications/qa/models/quality-assurance-event.model.ts @@ -104,62 +104,62 @@ export class QualityAssuranceEventObject implements CacheableObject { * The Quality Assurance event uuid inside DSpace */ @autoserialize - id: string; + id: string; /** * The universally unique identifier of this Quality Assurance event */ @autoserializeAs(String, 'id') - uuid: string; + uuid: string; /** * The Quality Assurance event original id (ex.: the source archive OAI-PMH identifier) */ @autoserialize - originalId: string; + originalId: string; /** * The title of the article to which the suggestion refers */ @autoserialize - title: string; + title: string; /** * Reliability of the suggestion (of the data inside 'message') */ @autoserialize - trust: number; + trust: number; /** * The timestamp Quality Assurance event was saved in DSpace */ @autoserialize - eventDate: string; + eventDate: string; /** * The Quality Assurance event status (ACCEPTED, REJECTED, DISCARDED, PENDING) */ @autoserialize - status: string; + status: string; /** * The suggestion data. Data may vary depending on the source */ @autoserialize - message: SourceQualityAssuranceEventMessageObject; + message: SourceQualityAssuranceEventMessageObject; /** * The type of this ConfigObject */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; /** * The links to all related resources returned by the rest api. */ @deserialize - _links: { + _links: { self: HALLink, target: HALLink, related: HALLink @@ -170,12 +170,12 @@ export class QualityAssuranceEventObject implements CacheableObject { * Will be undefined unless the {@item HALLink} has been resolved. */ @link(ITEM) - target?: Observable>; + target?: Observable>; /** * The related project for this Event * Will be undefined unless the {@related HALLink} has been resolved. */ @link(ITEM) - related?: Observable>; + related?: Observable>; } diff --git a/src/app/core/notifications/qa/models/quality-assurance-source.model.ts b/src/app/core/notifications/qa/models/quality-assurance-source.model.ts index cc5f874119c..56c674b031c 100644 --- a/src/app/core/notifications/qa/models/quality-assurance-source.model.ts +++ b/src/app/core/notifications/qa/models/quality-assurance-source.model.ts @@ -24,32 +24,32 @@ export class QualityAssuranceSourceObject implements CacheableObject { * The Quality Assurance source id */ @autoserialize - id: string; + id: string; /** * The date of the last udate from Notifications */ @autoserialize - lastEvent: string; + lastEvent: string; /** * The total number of suggestions provided by Notifications for this source */ @autoserialize - totalEvents: number; + totalEvents: number; /** * The type of this ConfigObject */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; /** * The links to all related resources returned by the rest api. */ @deserialize - _links: { + _links: { self: HALLink, }; } diff --git a/src/app/core/notifications/qa/models/quality-assurance-topic.model.ts b/src/app/core/notifications/qa/models/quality-assurance-topic.model.ts index ddc027d1942..0d4235a5311 100644 --- a/src/app/core/notifications/qa/models/quality-assurance-topic.model.ts +++ b/src/app/core/notifications/qa/models/quality-assurance-topic.model.ts @@ -24,38 +24,38 @@ export class QualityAssuranceTopicObject implements CacheableObject { * The Quality Assurance topic id */ @autoserialize - id: string; + id: string; /** * The Quality Assurance topic name to display */ @autoserialize - name: string; + name: string; /** * The date of the last udate from Notifications */ @autoserialize - lastEvent: string; + lastEvent: string; /** * The total number of suggestions provided by Notifications for this topic */ @autoserialize - totalEvents: number; + totalEvents: number; /** * The type of this ConfigObject */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; /** * The links to all related resources returned by the rest api. */ @deserialize - _links: { + _links: { self: HALLink, }; } diff --git a/src/app/core/orcid/model/orcid-history.model.ts b/src/app/core/orcid/model/orcid-history.model.ts index 62f5353ed26..aa8c4b41ba9 100644 --- a/src/app/core/orcid/model/orcid-history.model.ts +++ b/src/app/core/orcid/model/orcid-history.model.ts @@ -23,49 +23,49 @@ export class OrcidHistory extends CacheableObject { */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; /** * The identifier of this Orcid History record */ @autoserialize - id: number; + id: number; /** * The name of the related entity */ @autoserialize - entityName: string; + entityName: string; /** * The identifier of the profileItem of this Orcid History record. */ @autoserialize - profileItemId: string; + profileItemId: string; /** * The identifier of the entity related to this Orcid History record. */ @autoserialize - entityId: string; + entityId: string; /** * The type of the entity related to this Orcid History record. */ @autoserialize - entityType: string; + entityType: string; /** * The response status coming from ORCID api. */ @autoserialize - status: number; + status: number; /** * The putCode assigned by ORCID to the entity. */ @autoserialize - putCode: string; + putCode: string; /** * The last send attempt timestamp. @@ -86,7 +86,7 @@ export class OrcidHistory extends CacheableObject { * The {@link HALLink}s for this Orcid History record */ @deserialize - _links: { + _links: { self: HALLink, }; diff --git a/src/app/core/orcid/model/orcid-queue.model.ts b/src/app/core/orcid/model/orcid-queue.model.ts index fedb078cc56..2735114f22d 100644 --- a/src/app/core/orcid/model/orcid-queue.model.ts +++ b/src/app/core/orcid/model/orcid-queue.model.ts @@ -23,49 +23,49 @@ export class OrcidQueue extends CacheableObject { */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; /** * The identifier of this Orcid Queue record */ @autoserialize - id: number; + id: number; /** * The record description. */ @autoserialize - description: string; + description: string; /** * The identifier of the profileItem of this Orcid Queue record. */ @autoserialize - profileItemId: string; + profileItemId: string; /** * The identifier of the entity related to this Orcid Queue record. */ @autoserialize - entityId: string; + entityId: string; /** * The type of this Orcid Queue record. */ @autoserialize - recordType: string; + recordType: string; /** * The operation related to this Orcid Queue record. */ @autoserialize - operation: string; + operation: string; /** * The {@link HALLink}s for this Orcid Queue record */ @deserialize - _links: { + _links: { self: HALLink, }; diff --git a/src/app/core/profile/model/researcher-profile.model.ts b/src/app/core/profile/model/researcher-profile.model.ts index d26156123c1..28ffd09a7b8 100644 --- a/src/app/core/profile/model/researcher-profile.model.ts +++ b/src/app/core/profile/model/researcher-profile.model.ts @@ -31,28 +31,28 @@ export class ResearcherProfile extends CacheableObject { */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; /** * The identifier of this Researcher Profile */ @autoserialize - id: string; + id: string; @deserializeAs('id') - uuid: string; + uuid: string; /** * The visibility of this Researcher Profile */ @autoserialize - visible: boolean; + visible: boolean; /** * The {@link HALLink}s for this Researcher Profile */ @deserialize - _links: { + _links: { self: HALLink, item: HALLink, eperson: HALLink @@ -63,6 +63,6 @@ export class ResearcherProfile extends CacheableObject { * Will be undefined unless the item {@link HALLink} has been resolved. */ @link(ITEM) - item?: Observable>; + item?: Observable>; } diff --git a/src/app/core/resource-policy/models/resource-policy.model.ts b/src/app/core/resource-policy/models/resource-policy.model.ts index d4558cfe3ad..669844690bc 100644 --- a/src/app/core/resource-policy/models/resource-policy.model.ts +++ b/src/app/core/resource-policy/models/resource-policy.model.ts @@ -34,50 +34,50 @@ export class ResourcePolicy implements CacheableObject { * The identifier for this Resource Policy */ @autoserialize - id: string; + id: string; /** * The name for this Resource Policy */ @autoserialize - name: string; + name: string; /** * The description for this Resource Policy */ @autoserialize - description: string; + description: string; /** * The classification or this Resource Policy */ @autoserialize - policyType: PolicyType; + policyType: PolicyType; /** * The action that is allowed by this Resource Policy */ @autoserialize - action: ActionType; + action: ActionType; /** * The first day of validity of the policy (format YYYY-MM-DD) */ @autoserialize - startDate: string; + startDate: string; /** * The last day of validity of the policy (format YYYY-MM-DD) */ @autoserialize - endDate: string; + endDate: string; /** * The object type */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; /** * The universally unique identifier for this Resource Policy @@ -91,7 +91,7 @@ export class ResourcePolicy implements CacheableObject { * The {@link HALLink}s for this ResourcePolicy */ @deserialize - _links: { + _links: { eperson: HALLink, group: HALLink, self: HALLink, @@ -102,12 +102,12 @@ export class ResourcePolicy implements CacheableObject { * Will be undefined unless the version {@link HALLink} has been resolved. */ @link(EPERSON) - eperson?: Observable>; + eperson?: Observable>; /** * The group linked by this resource policy * Will be undefined unless the version {@link HALLink} has been resolved. */ @link(GROUP) - group?: Observable>; + group?: Observable>; } diff --git a/src/app/core/shared/authorization.model.ts b/src/app/core/shared/authorization.model.ts index 0031b054f6e..1712db9a078 100644 --- a/src/app/core/shared/authorization.model.ts +++ b/src/app/core/shared/authorization.model.ts @@ -31,10 +31,10 @@ export class Authorization extends DSpaceObject { * Unique identifier for this authorization */ @autoserialize - id: string; + id: string; @deserialize - _links: { + _links: { self: HALLink; eperson: HALLink; feature: HALLink; @@ -46,17 +46,17 @@ export class Authorization extends DSpaceObject { * Null if the authorization grants access to anonymous users */ @link(EPERSON) - eperson?: Observable>; + eperson?: Observable>; /** * The Feature enabled by this Authorization */ @link(FEATURE) - feature?: Observable>; + feature?: Observable>; /** * The Object this authorization applies to */ @link(ITEM) - object?: Observable>; + object?: Observable>; } diff --git a/src/app/core/shared/bitstream-format.model.ts b/src/app/core/shared/bitstream-format.model.ts index 354edb4cbd3..44ba85c9745 100644 --- a/src/app/core/shared/bitstream-format.model.ts +++ b/src/app/core/shared/bitstream-format.model.ts @@ -25,43 +25,43 @@ export class BitstreamFormat implements CacheableObject { */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; /** * Short description of this Bitstream Format */ @autoserialize - shortDescription: string; + shortDescription: string; /** * Description of this Bitstream Format */ @autoserialize - description: string; + description: string; /** * String representing the MIME type of this Bitstream Format */ @autoserialize - mimetype: string; + mimetype: string; /** * The level of support the system offers for this Bitstream Format */ @autoserialize - supportLevel: BitstreamFormatSupportLevel; + supportLevel: BitstreamFormatSupportLevel; /** * True if the Bitstream Format is used to store system information, rather than the content of items in the system */ @autoserialize - internal: boolean; + internal: boolean; /** * String representing this Bitstream Format's file extension */ @autoserialize - extensions: string[]; + extensions: string[]; /** * Universally unique identifier for this Bitstream Format @@ -77,13 +77,13 @@ export class BitstreamFormat implements CacheableObject { * but might not be unique across different object types */ @autoserialize - id: string; + id: string; /** * The {@link HALLink}s for this BitstreamFormat */ @deserialize - _links: { + _links: { self: HALLink; }; } diff --git a/src/app/core/shared/bitstream.model.ts b/src/app/core/shared/bitstream.model.ts index d1b821e8cd9..73e5e04b364 100644 --- a/src/app/core/shared/bitstream.model.ts +++ b/src/app/core/shared/bitstream.model.ts @@ -28,25 +28,25 @@ export class Bitstream extends DSpaceObject implements ChildHALResource { * The size of this bitstream in bytes */ @autoserialize - sizeBytes: number; + sizeBytes: number; /** * The description of this Bitstream */ @autoserialize - description: string; + description: string; /** * The name of the Bundle this Bitstream is part of */ @autoserialize - bundleName: string; + bundleName: string; /** * The {@link HALLink}s for this Bitstream */ @deserialize - _links: { + _links: { self: HALLink; bundle: HALLink; format: HALLink; @@ -59,21 +59,21 @@ export class Bitstream extends DSpaceObject implements ChildHALResource { * Will be undefined unless the thumbnail {@link HALLink} has been resolved. */ @link(BITSTREAM, false, 'thumbnail') - thumbnail?: Observable>; + thumbnail?: Observable>; /** * The BitstreamFormat of this Bitstream * Will be undefined unless the format {@link HALLink} has been resolved. */ @link(BITSTREAM_FORMAT, false, 'format') - format?: Observable>; + format?: Observable>; /** * The owning bundle for this Bitstream * Will be undefined unless the bundle{@link HALLink} has been resolved. */ @link(BUNDLE) - bundle?: Observable>; + bundle?: Observable>; getParentLinkKey(): keyof this['_links'] { return 'format'; diff --git a/src/app/core/shared/browse-definition.model.ts b/src/app/core/shared/browse-definition.model.ts index 8e50a57bb52..6de81727fae 100644 --- a/src/app/core/shared/browse-definition.model.ts +++ b/src/app/core/shared/browse-definition.model.ts @@ -9,7 +9,7 @@ import { CacheableObject } from '../cache/cacheable-object.model'; export abstract class BrowseDefinition extends CacheableObject { @autoserialize - id: string; + id: string; /** * Get the render type of the BrowseDefinition model diff --git a/src/app/core/shared/browse-entry.model.ts b/src/app/core/shared/browse-entry.model.ts index 03e3ab3f5b6..746333872e6 100644 --- a/src/app/core/shared/browse-entry.model.ts +++ b/src/app/core/shared/browse-entry.model.ts @@ -25,41 +25,41 @@ export class BrowseEntry extends ListableObject implements TypedObject { */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; /** * The authority string of this browse entry */ @autoserialize - authority: string; + authority: string; /** * The value of this browse entry */ @autoserialize - value: string; + value: string; /** * The language of the value of this browse entry */ @autoserializeAs('valueLang') - language: string; + language: string; /** * Thumbnail link used when browsing items with showThumbs config enabled. */ @autoserializeAs('thumbnail') - thumbnail: string; + thumbnail: string; /** * The count of this browse entry */ @excludeFromEquals @autoserialize - count: number; + count: number; @deserialize - _links: { + _links: { self: HALLink; entries: HALLink; thumbnail: HALLink; diff --git a/src/app/core/shared/bundle.model.ts b/src/app/core/shared/bundle.model.ts index e5b92799d4b..d9ea6d83dc9 100644 --- a/src/app/core/shared/bundle.model.ts +++ b/src/app/core/shared/bundle.model.ts @@ -27,7 +27,7 @@ export class Bundle extends DSpaceObject { * The {@link HALLink}s for this Bundle */ @deserialize - _links: { + _links: { self: HALLink; primaryBitstream: HALLink; bitstreams: HALLink; @@ -39,19 +39,19 @@ export class Bundle extends DSpaceObject { * Will be undefined unless the primaryBitstream {@link HALLink} has been resolved. */ @link(BITSTREAM) - primaryBitstream?: Observable>; + primaryBitstream?: Observable>; /** * The list of Bitstreams that are direct children of this Bundle * Will be undefined unless the bitstreams {@link HALLink} has been resolved. */ @link(BITSTREAM, true) - bitstreams?: Observable>>; + bitstreams?: Observable>>; /** * The owning item for this Bundle * Will be undefined unless the Item{@link HALLink} has been resolved. */ @link(ITEM) - item?: Observable>; + item?: Observable>; } diff --git a/src/app/core/shared/collection.model.ts b/src/app/core/shared/collection.model.ts index 468b0ccc644..b929e54ccb4 100644 --- a/src/app/core/shared/collection.model.ts +++ b/src/app/core/shared/collection.model.ts @@ -33,13 +33,13 @@ export class Collection extends DSpaceObject implements ChildHALResource, Handle @excludeFromEquals @autoserialize - archivedItemsCount: number; + archivedItemsCount: number; /** * The {@link HALLink}s for this Collection */ @deserialize - _links: { + _links: { license: HALLink; harvester: HALLink; mappedItems: HALLink; @@ -60,28 +60,28 @@ export class Collection extends DSpaceObject implements ChildHALResource, Handle * Will be undefined unless the license {@link HALLink} has been resolved. */ @link(LICENSE) - license?: Observable>; + license?: Observable>; /** * The logo for this Collection * Will be undefined unless the logo {@link HALLink} has been resolved. */ @link(BITSTREAM) - logo?: Observable>; + logo?: Observable>; /** * The default access conditions for this Collection * Will be undefined unless the defaultAccessConditions {@link HALLink} has been resolved. */ @link(RESOURCE_POLICY, true) - defaultAccessConditions?: Observable>>; + defaultAccessConditions?: Observable>>; /** * The Community that is a direct parent of this Collection * Will be undefined unless the parent community HALLink has been resolved. */ @link(COMMUNITY, false) - parentCommunity?: Observable>; + parentCommunity?: Observable>; /** * A string representing the unique handle of this Collection diff --git a/src/app/core/shared/community.model.ts b/src/app/core/shared/community.model.ts index 764b15e2ed0..31b00398ffb 100644 --- a/src/app/core/shared/community.model.ts +++ b/src/app/core/shared/community.model.ts @@ -29,13 +29,13 @@ export class Community extends DSpaceObject implements ChildHALResource, HandleO @excludeFromEquals @autoserialize - archivedItemsCount: number; + archivedItemsCount: number; /** * The {@link HALLink}s for this Community */ @deserialize - _links: { + _links: { collections: HALLink; logo: HALLink; subcommunities: HALLink; @@ -49,28 +49,28 @@ export class Community extends DSpaceObject implements ChildHALResource, HandleO * Will be undefined unless the logo {@link HALLink} has been resolved. */ @link(BITSTREAM) - logo?: Observable>; + logo?: Observable>; /** * The list of Collections that are direct children of this Community * Will be undefined unless the collections {@link HALLink} has been resolved. */ @link(COLLECTION, true) - collections?: Observable>>; + collections?: Observable>>; /** * The list of Communities that are direct children of this Community * Will be undefined unless the subcommunities {@link HALLink} has been resolved. */ @link(COMMUNITY, true) - subcommunities?: Observable>>; + subcommunities?: Observable>>; /** * The Community that is a direct parent of this Community * Will be undefined unless the parent community HALLink has been resolved. */ @link(COMMUNITY, false) - parentCommunity?: Observable>; + parentCommunity?: Observable>; /** * A string representing the unique handle of this Community diff --git a/src/app/core/shared/configuration-property.model.ts b/src/app/core/shared/configuration-property.model.ts index 2b6ab606c91..e15f8a5b859 100644 --- a/src/app/core/shared/configuration-property.model.ts +++ b/src/app/core/shared/configuration-property.model.ts @@ -23,31 +23,31 @@ export class ConfigurationProperty implements CacheableObject { */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; /** * The uuid of the configuration property * The name is used as id for configuration properties */ @autoserializeAs(String, 'name') - uuid: string; + uuid: string; /** * The name of the configuration property */ @autoserialize - name: string; + name: string; /** * The values of the configuration property */ @autoserialize - values: string[]; + values: string[]; /** * The links of the configuration property */ @deserialize - _links: { self: HALLink }; + _links: { self: HALLink }; } diff --git a/src/app/core/shared/content-source.model.ts b/src/app/core/shared/content-source.model.ts index ee535191d0c..cfc78f223fc 100644 --- a/src/app/core/shared/content-source.model.ts +++ b/src/app/core/shared/content-source.model.ts @@ -38,20 +38,20 @@ export class ContentSource extends CacheableObject { * and we need a custom responseparser for ContentSource responses */ @excludeFromEquals - type: ResourceType = CONTENT_SOURCE; + type: ResourceType = CONTENT_SOURCE; /** * Unique identifier, this is necessary to store the ContentSource in FieldUpdates * Because the ContentSource coming from the REST API doesn't have a UUID, we're using the selflink */ @deserializeAs('self') - uuid: string; + uuid: string; /** * OAI Provider / Source */ @autoserializeAs('oai_source') - oaiSource: string; + oaiSource: string; /** * OAI Specific set ID @@ -64,14 +64,14 @@ export class ContentSource extends CacheableObject { * The ID of the metadata format used */ @autoserializeAs('metadata_config_id') - metadataConfigId: string; + metadataConfigId: string; /** * Type of content being harvested * Defaults to 'NONE', meaning the collection doesn't harvest its content from an external source */ @autoserializeAs('harvest_type') - harvestType = ContentSourceHarvestType.None; + harvestType = ContentSourceHarvestType.None; /** * The available metadata configurations @@ -82,31 +82,31 @@ export class ContentSource extends CacheableObject { * The current harvest status */ @autoserializeAs('harvest_status') - harvestStatus: string; + harvestStatus: string; /** * The last's harvest start time */ @autoserializeAs('harvest_start_time') - harvestStartTime: string; + harvestStartTime: string; /** * When the collection was last harvested */ @autoserializeAs('last_harvested') - lastHarvested: string; + lastHarvested: string; /** * The current harvest message */ @autoserializeAs('harvest_message') - message: string; + message: string; /** * The {@link HALLink}s for this ContentSource */ @deserialize - _links: { + _links: { self: HALLink }; } diff --git a/src/app/core/shared/dspace-object.model.ts b/src/app/core/shared/dspace-object.model.ts index dc9b7f5fca6..7bc05b1d3aa 100644 --- a/src/app/core/shared/dspace-object.model.ts +++ b/src/app/core/shared/dspace-object.model.ts @@ -46,20 +46,20 @@ export class DSpaceObject extends ListableObject implements CacheableObject { */ @excludeFromEquals @autoserializeAs(String, 'uuid') - id: string; + id: string; /** * The universally unique ide ntifier of this DSpaceObject */ @autoserializeAs(String) - uuid: string; + uuid: string; /** * A string representing the kind of DSpaceObject, e.g. community, item, … */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; /** * A shorthand to get this DSpaceObject's self link @@ -100,10 +100,10 @@ export class DSpaceObject extends ListableObject implements CacheableObject { */ @excludeFromEquals @autoserializeAs(MetadataMapSerializer) - metadata: MetadataMap; + metadata: MetadataMap; @deserialize - _links: { + _links: { self: HALLink; }; diff --git a/src/app/core/shared/external-source-entry.model.ts b/src/app/core/shared/external-source-entry.model.ts index d743a923109..01e52d30d52 100644 --- a/src/app/core/shared/external-source-entry.model.ts +++ b/src/app/core/shared/external-source-entry.model.ts @@ -27,44 +27,44 @@ export class ExternalSourceEntry extends ListableObject { * Unique identifier */ @autoserialize - id: string; + id: string; /** * The object type */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; /** * The value to display */ @autoserialize - display: string; + display: string; /** * The value to store the entry with */ @autoserialize - value: string; + value: string; /** * The ID of the external source this entry originates from */ @autoserialize - externalSource: string; + externalSource: string; /** * Metadata of the entry */ @autoserializeAs(MetadataMapSerializer) - metadata: MetadataMap; + metadata: MetadataMap; /** * The {@link HALLink}s for this ExternalSourceEntry */ @deserialize - _links: { + _links: { self: HALLink; }; diff --git a/src/app/core/shared/external-source.model.ts b/src/app/core/shared/external-source.model.ts index 70766e04940..40661917e22 100644 --- a/src/app/core/shared/external-source.model.ts +++ b/src/app/core/shared/external-source.model.ts @@ -30,38 +30,38 @@ export class ExternalSource extends CacheableObject { */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; /** * Unique identifier */ @autoserialize - id: string; + id: string; /** * The name of this external source */ @autoserialize - name: string; + name: string; /** * Is the source hierarchical? */ @autoserialize - hierarchical: boolean; + hierarchical: boolean; /** * The list of entity types that are compatible with this external source * Will be undefined unless the entityTypes {@link HALLink} has been resolved. */ @link(ITEM_TYPE, true) - entityTypes?: Observable>>; + entityTypes?: Observable>>; /** * The {@link HALLink}s for this ExternalSource */ @deserialize - _links: { + _links: { self: HALLink; entries: HALLink; entityTypes: HALLink; diff --git a/src/app/core/shared/feature.model.ts b/src/app/core/shared/feature.model.ts index 270eb2de9d9..1c18d1478f6 100644 --- a/src/app/core/shared/feature.model.ts +++ b/src/app/core/shared/feature.model.ts @@ -21,22 +21,22 @@ export class Feature extends DSpaceObject { * Unique identifier for this feature */ @autoserialize - id: string; + id: string; /** * A human readable description of the feature's purpose */ @autoserialize - description: string; + description: string; /** * A list of resource types this feature applies to */ @autoserialize - resourcetypes: string[]; + resourcetypes: string[]; @deserialize - _links: { + _links: { self: HALLink; }; } diff --git a/src/app/core/shared/flat-browse-definition.model.ts b/src/app/core/shared/flat-browse-definition.model.ts index d9d59d11142..74166f937c9 100644 --- a/src/app/core/shared/flat-browse-definition.model.ts +++ b/src/app/core/shared/flat-browse-definition.model.ts @@ -23,14 +23,14 @@ export class FlatBrowseDefinition extends NonHierarchicalBrowseDefinition { * The object type */ @excludeFromEquals - type: ResourceType = FLAT_BROWSE_DEFINITION; + type: ResourceType = FLAT_BROWSE_DEFINITION; get self(): string { return this._links.self.href; } @deserialize - _links: { + _links: { self: HALLink; items: HALLink; }; diff --git a/src/app/core/shared/hal-resource.model.ts b/src/app/core/shared/hal-resource.model.ts index 5f9d107a540..a27d448bd6f 100644 --- a/src/app/core/shared/hal-resource.model.ts +++ b/src/app/core/shared/hal-resource.model.ts @@ -13,7 +13,7 @@ export class HALResource { * The {@link HALLink}s for this {@link HALResource} */ @deserialize - _links: { + _links: { /** * The {@link HALLink} that refers to this {@link HALResource} diff --git a/src/app/core/shared/hierarchical-browse-definition.model.ts b/src/app/core/shared/hierarchical-browse-definition.model.ts index 97d50c3ca67..e7c06a5372f 100644 --- a/src/app/core/shared/hierarchical-browse-definition.model.ts +++ b/src/app/core/shared/hierarchical-browse-definition.model.ts @@ -25,23 +25,23 @@ export class HierarchicalBrowseDefinition extends BrowseDefinition { * The object type */ @excludeFromEquals - type: ResourceType = HIERARCHICAL_BROWSE_DEFINITION; + type: ResourceType = HIERARCHICAL_BROWSE_DEFINITION; @autoserialize - facetType: string; + facetType: string; @autoserialize - vocabulary: string; + vocabulary: string; @autoserializeAs('metadata') - metadataKeys: string[]; + metadataKeys: string[]; get self(): string { return this._links.self.href; } @deserialize - _links: { + _links: { self: HALLink; vocabulary: HALLink; }; diff --git a/src/app/core/shared/item-relationships/item-type.model.ts b/src/app/core/shared/item-relationships/item-type.model.ts index 1d8ca6df988..bbf1cb3be03 100644 --- a/src/app/core/shared/item-relationships/item-type.model.ts +++ b/src/app/core/shared/item-relationships/item-type.model.ts @@ -24,16 +24,16 @@ export class ItemType implements CacheableObject { */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; /** * The identifier of this ItemType */ @autoserialize - id: string; + id: string; @autoserialize - label: string; + label: string; /** * The universally unique identifier of this ItemType @@ -47,7 +47,7 @@ export class ItemType implements CacheableObject { * The {@link HALLink}s for this ItemType */ @deserialize - _links: { + _links: { self: HALLink, }; } diff --git a/src/app/core/shared/item-relationships/relationship-type.model.ts b/src/app/core/shared/item-relationships/relationship-type.model.ts index 75d5d70af6a..3a86ee34f84 100644 --- a/src/app/core/shared/item-relationships/relationship-type.model.ts +++ b/src/app/core/shared/item-relationships/relationship-type.model.ts @@ -31,19 +31,19 @@ export class RelationshipType implements CacheableObject { */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; /** * The label that describes this RelationshipType */ @autoserialize - label: string; + label: string; /** * The identifier of this RelationshipType */ @autoserialize - id: string; + id: string; /** * The universally unique identifier of this RelationshipType @@ -57,43 +57,43 @@ export class RelationshipType implements CacheableObject { * The label that describes the Relation to the left of this RelationshipType */ @autoserialize - leftwardType: string; + leftwardType: string; /** * The maximum amount of Relationships allowed to the left of this RelationshipType */ @autoserialize - leftMaxCardinality: number; + leftMaxCardinality: number; /** * The minimum amount of Relationships allowed to the left of this RelationshipType */ @autoserialize - leftMinCardinality: number; + leftMinCardinality: number; /** * The label that describes the Relation to the right of this RelationshipType */ @autoserialize - rightwardType: string; + rightwardType: string; /** * The maximum amount of Relationships allowed to the right of this RelationshipType */ @autoserialize - rightMaxCardinality: number; + rightMaxCardinality: number; /** * The minimum amount of Relationships allowed to the right of this RelationshipType */ @autoserialize - rightMinCardinality: number; + rightMinCardinality: number; /** * The {@link HALLink}s for this RelationshipType */ @deserialize - _links: { + _links: { self: HALLink; leftType: HALLink; rightType: HALLink; @@ -104,12 +104,12 @@ export class RelationshipType implements CacheableObject { * Will be undefined unless the leftType {@link HALLink} has been resolved. */ @link(ITEM_TYPE) - leftType?: Observable>; + leftType?: Observable>; /** * The type of Item found on the right side of this RelationshipType * Will be undefined unless the rightType {@link HALLink} has been resolved. */ @link(ITEM_TYPE) - rightType?: Observable>; + rightType?: Observable>; } diff --git a/src/app/core/shared/item-relationships/relationship.model.ts b/src/app/core/shared/item-relationships/relationship.model.ts index 4f6fe2796d0..77fdff8651f 100644 --- a/src/app/core/shared/item-relationships/relationship.model.ts +++ b/src/app/core/shared/item-relationships/relationship.model.ts @@ -33,7 +33,7 @@ export class Relationship implements CacheableObject { */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; /** * The universally unique identifier of this Relationship @@ -47,37 +47,37 @@ export class Relationship implements CacheableObject { * The identifier of this Relationship */ @autoserialize - id: string; + id: string; /** * The place of the Item to the left side of this Relationship */ @autoserialize - leftPlace: number; + leftPlace: number; /** * The place of the Item to the right side of this Relationship */ @autoserialize - rightPlace: number; + rightPlace: number; /** * The name variant of the Item to the left side of this Relationship */ @autoserialize - leftwardValue: string; + leftwardValue: string; /** * The name variant of the Item to the right side of this Relationship */ @autoserialize - rightwardValue: string; + rightwardValue: string; /** * The {@link HALLink}s for this Relationship */ @deserialize - _links: { + _links: { self: HALLink; leftItem: HALLink; rightItem: HALLink; @@ -89,20 +89,20 @@ export class Relationship implements CacheableObject { * Will be undefined unless the leftItem {@link HALLink} has been resolved. */ @link(ITEM) - leftItem?: Observable>; + leftItem?: Observable>; /** * The item on the right side of this relationship * Will be undefined unless the rightItem {@link HALLink} has been resolved. */ @link(ITEM) - rightItem?: Observable>; + rightItem?: Observable>; /** * The RelationshipType for this Relationship * Will be undefined unless the relationshipType {@link HALLink} has been resolved. */ @link(RELATIONSHIP_TYPE) - relationshipType?: Observable>; + relationshipType?: Observable>; } diff --git a/src/app/core/shared/item-request.model.ts b/src/app/core/shared/item-request.model.ts index 8b1ef94512e..5a4f912363b 100644 --- a/src/app/core/shared/item-request.model.ts +++ b/src/app/core/shared/item-request.model.ts @@ -22,70 +22,70 @@ export class ItemRequest implements CacheableObject { */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; /** * opaque string which uniquely identifies this request */ @autoserialize - token: string; + token: string; /** * true if the request is for all bitstreams of the item. */ @autoserialize - allfiles: boolean; + allfiles: boolean; /** * email address of the person requesting the files. */ @autoserialize - requestEmail: string; + requestEmail: string; /** * Human-readable name of the person requesting the files. */ @autoserialize - requestName: string; + requestName: string; /** * arbitrary message provided by the person requesting the files. */ @autoserialize - requestMessage: string; + requestMessage: string; /** * date that the request was recorded. */ @autoserialize - requestDate: string; + requestDate: string; /** * true if the request has been granted. */ @autoserialize - acceptRequest: boolean; + acceptRequest: boolean; /** * date that the request was granted or denied. */ @autoserialize - decisionDate: string; + decisionDate: string; /** * date on which the request is considered expired. */ @autoserialize - expires: string; + expires: string; /** * UUID of the requested Item. */ @autoserialize - itemId: string; + itemId: string; /** * UUID of the requested bitstream. */ @autoserialize - bitstreamId: string; + bitstreamId: string; /** * The {@link HALLink}s for this ItemRequest */ @deserialize - _links: { + _links: { self: HALLink; item: HALLink; bitstream: HALLink; diff --git a/src/app/core/shared/item.model.ts b/src/app/core/shared/item.model.ts index 33a9f3bb387..b13cf25f033 100644 --- a/src/app/core/shared/item.model.ts +++ b/src/app/core/shared/item.model.ts @@ -48,37 +48,37 @@ export class Item extends DSpaceObject implements ChildHALResource, HandleObject * A string representing the unique handle of this Item */ @autoserialize - handle: string; + handle: string; /** * The Date of the last modification of this Item */ @deserializeAs(Date) - lastModified: Date; + lastModified: Date; /** * A boolean representing if this Item is currently archived or not */ @autoserializeAs(Boolean, 'inArchive') - isArchived: boolean; + isArchived: boolean; /** * A boolean representing if this Item is currently discoverable or not */ @autoserializeAs(Boolean, 'discoverable') - isDiscoverable: boolean; + isDiscoverable: boolean; /** * A boolean representing if this Item is currently withdrawn or not */ @autoserializeAs(Boolean, 'withdrawn') - isWithdrawn: boolean; + isWithdrawn: boolean; /** * The {@link HALLink}s for this Item */ @deserialize - _links: { + _links: { mappedCollections: HALLink; relationships: HALLink; bundles: HALLink; @@ -96,35 +96,35 @@ export class Item extends DSpaceObject implements ChildHALResource, HandleObject * Will be undefined unless the owningCollection {@link HALLink} has been resolved. */ @link(COLLECTION) - owningCollection?: Observable>; + owningCollection?: Observable>; /** * The version this item represents in its history * Will be undefined unless the version {@link HALLink} has been resolved. */ @link(VERSION) - version?: Observable>; + version?: Observable>; /** * The list of Bundles inside this Item * Will be undefined unless the bundles {@link HALLink} has been resolved. */ @link(BUNDLE, true) - bundles?: Observable>>; + bundles?: Observable>>; /** * The list of Relationships this Item has with others * Will be undefined unless the relationships {@link HALLink} has been resolved. */ @link(RELATIONSHIP, true) - relationships?: Observable>>; + relationships?: Observable>>; /** * The thumbnail for this Item * Will be undefined unless the thumbnail {@link HALLink} has been resolved. */ @link(BITSTREAM, false, 'thumbnail') - thumbnail?: Observable>; + thumbnail?: Observable>; /** * The access status for this Item @@ -138,7 +138,7 @@ export class Item extends DSpaceObject implements ChildHALResource, HandleObject * Will be undefined unless the identifiers {@link HALLink} has been resolved. */ @link(IDENTIFIERS, false, 'identifiers') - identifiers?: Observable>; + identifiers?: Observable>; /** * Method that returns as which type of object this object should be rendered diff --git a/src/app/core/shared/license.model.ts b/src/app/core/shared/license.model.ts index af85c31eeae..0cb1e70b6b8 100644 --- a/src/app/core/shared/license.model.ts +++ b/src/app/core/shared/license.model.ts @@ -16,11 +16,11 @@ export class License extends DSpaceObject { * Is the license custom? */ @autoserialize - custom: boolean; + custom: boolean; /** * The text of the license */ @autoserialize - text: string; + text: string; } diff --git a/src/app/core/shared/metadata.models.ts b/src/app/core/shared/metadata.models.ts index 4ba78e39f75..0f26d7ff598 100644 --- a/src/app/core/shared/metadata.models.ts +++ b/src/app/core/shared/metadata.models.ts @@ -37,26 +37,26 @@ export class MetadataValue implements MetadataValueInterface { /** The language. */ @autoserialize - language: string; + language: string; /** The string value. */ @autoserialize - value: string; + value: string; /** * The place of this MetadataValue within its list of metadata * This is used to render metadata in a specific custom order */ @autoserialize - place: number; + place: number; /** The authority key used for authority-controlled metadata */ @autoserialize - authority: string; + authority: string; /** The authority confidence value */ @autoserialize - confidence: number; + confidence: number; /** * Returns true if this Metadatum's authority key starts with 'virtual::' diff --git a/src/app/core/shared/non-hierarchical-browse-definition.ts b/src/app/core/shared/non-hierarchical-browse-definition.ts index 769d70629de..7f8c6d0e5f0 100644 --- a/src/app/core/shared/non-hierarchical-browse-definition.ts +++ b/src/app/core/shared/non-hierarchical-browse-definition.ts @@ -16,14 +16,14 @@ import { SortOption } from './sort-option.model'; export abstract class NonHierarchicalBrowseDefinition extends BrowseDefinition { @autoserialize - sortOptions: SortOption[]; + sortOptions: SortOption[]; @autoserializeAs('order') - defaultSortOrder: string; + defaultSortOrder: string; @autoserializeAs('metadata') - metadataKeys: string[]; + metadataKeys: string[]; @autoserialize - dataType: BrowseByDataType; + dataType: BrowseByDataType; } diff --git a/src/app/core/shared/page-info.model.ts b/src/app/core/shared/page-info.model.ts index 5594e58309e..c9557abcb62 100644 --- a/src/app/core/shared/page-info.model.ts +++ b/src/app/core/shared/page-info.model.ts @@ -17,31 +17,31 @@ export class PageInfo implements HALResource { * The number of elements on a page */ @autoserializeAs(Number, 'size') - elementsPerPage: number; + elementsPerPage: number; /** * The total number of elements in the entire set */ @autoserialize - totalElements: number; + totalElements: number; /** * The total number of pages */ @autoserialize - totalPages: number; + totalPages: number; /** * The number of the current page, zero-based */ @autoserializeAs(Number, 'number') - currentPage: number; + currentPage: number; /** * The {@link HALLink}s for this PageInfo */ @deserialize - _links: { + _links: { first: HALLink; prev: HALLink; next: HALLink; diff --git a/src/app/core/shared/search/search-filters/search-config.model.ts b/src/app/core/shared/search/search-filters/search-config.model.ts index ccc9827e599..2ebe5e84555 100644 --- a/src/app/core/shared/search/search-filters/search-config.model.ts +++ b/src/app/core/shared/search/search-filters/search-config.model.ts @@ -3,6 +3,7 @@ import { deserialize, } from 'cerialize'; +import { FilterType } from '../../../../shared/search/models/filter-type.model'; import { typedObject } from '../../../cache/builders/build-decorators'; import { CacheableObject } from '../../../cache/cacheable-object.model'; import { HALLink } from '../../hal-link.model'; @@ -20,31 +21,31 @@ export class SearchConfig implements CacheableObject { * The id of this search configuration. */ @autoserialize - id: string; + id: string; /** * The configured filters. */ @autoserialize - filters: FilterConfig[]; + filters: FilterConfig[]; /** * The configured sort options. */ @autoserialize - sortOptions: SortConfig[]; + sortOptions: SortConfig[]; /** * The object type. */ @autoserialize - type: ResourceType; + type: ResourceType; /** * The {@link HALLink}s for this Item */ @deserialize - _links: { + _links: { facets: HALLink; objects: HALLink; self: HALLink; @@ -60,7 +61,7 @@ export interface FilterConfig { operators: OperatorConfig[]; openByDefault: boolean; pageSize: number; - type: string; + type: FilterType; } /** diff --git a/src/app/core/shared/sort-option.model.ts b/src/app/core/shared/sort-option.model.ts index b179d159b68..c735e87b9af 100644 --- a/src/app/core/shared/sort-option.model.ts +++ b/src/app/core/shared/sort-option.model.ts @@ -2,8 +2,8 @@ import { autoserialize } from 'cerialize'; export class SortOption { @autoserialize - name: string; + name: string; @autoserialize - metadata: string; + metadata: string; } diff --git a/src/app/core/shared/template-item.model.ts b/src/app/core/shared/template-item.model.ts index 4c33a2bd92f..a536dea49e9 100644 --- a/src/app/core/shared/template-item.model.ts +++ b/src/app/core/shared/template-item.model.ts @@ -23,6 +23,6 @@ export class TemplateItem extends Item { * The Collection that this item is a template for */ @link(COLLECTION) - templateItemOf: Observable>; + templateItemOf: Observable>; } diff --git a/src/app/core/shared/value-list-browse-definition.model.ts b/src/app/core/shared/value-list-browse-definition.model.ts index 80ad73e7612..ad9fc60d1cb 100644 --- a/src/app/core/shared/value-list-browse-definition.model.ts +++ b/src/app/core/shared/value-list-browse-definition.model.ts @@ -23,14 +23,14 @@ export class ValueListBrowseDefinition extends NonHierarchicalBrowseDefinition { * The object type */ @excludeFromEquals - type: ResourceType = VALUE_LIST_BROWSE_DEFINITION; + type: ResourceType = VALUE_LIST_BROWSE_DEFINITION; get self(): string { return this._links.self.href; } @deserialize - _links: { + _links: { self: HALLink; entries: HALLink; }; diff --git a/src/app/core/shared/version-history.model.ts b/src/app/core/shared/version-history.model.ts index 9792a20ff31..58d9259a047 100644 --- a/src/app/core/shared/version-history.model.ts +++ b/src/app/core/shared/version-history.model.ts @@ -27,7 +27,7 @@ export class VersionHistory extends DSpaceObject { static type = VERSION_HISTORY; @deserialize - _links: { + _links: { self: HALLink; versions: HALLink; draftVersion: HALLink; @@ -37,30 +37,30 @@ export class VersionHistory extends DSpaceObject { * The identifier of this Version History */ @autoserialize - id: string; + id: string; /** * The summary of this Version History */ @autoserialize - summary: string; + summary: string; /** * The name of the submitter of this Version History */ @autoserialize - submitterName: string; + submitterName: string; /** * Whether exist a workspace item */ @autoserialize - draftVersion: boolean; + draftVersion: boolean; /** * The list of versions within this history */ @excludeFromEquals @link(VERSION, true) - versions: Observable>>; + versions: Observable>>; } diff --git a/src/app/core/shared/version.model.ts b/src/app/core/shared/version.model.ts index f66bc8938bb..105ba744167 100644 --- a/src/app/core/shared/version.model.ts +++ b/src/app/core/shared/version.model.ts @@ -30,7 +30,7 @@ export class Version extends DSpaceObject { static type = VERSION; @deserialize - _links: { + _links: { self: HALLink; item: HALLink; versionhistory: HALLink; @@ -41,50 +41,50 @@ export class Version extends DSpaceObject { * The identifier of this Version */ @autoserialize - id: string; + id: string; /** * The version number of the version's history this version represents */ @autoserialize - version: number; + version: number; /** * The summary for the changes made in this version */ @autoserialize - summary: string; + summary: string; /** * The name of the submitter of this version */ @autoserialize - submitterName: string; + submitterName: string; /** * The Date this version was created */ @deserialize - created: Date; + created: Date; /** * The full version history this version is apart of */ @excludeFromEquals @link(VERSION_HISTORY) - versionhistory: Observable>; + versionhistory: Observable>; /** * The item this version represents */ @excludeFromEquals @link(ITEM) - item: Observable>; + item: Observable>; /** * The e-person who created this version */ @excludeFromEquals @link(EPERSON) - eperson: Observable>; + eperson: Observable>; } diff --git a/src/app/core/statistics/models/usage-report.model.ts b/src/app/core/statistics/models/usage-report.model.ts index b8a415667dd..a4924f3a3db 100644 --- a/src/app/core/statistics/models/usage-report.model.ts +++ b/src/app/core/statistics/models/usage-report.model.ts @@ -26,19 +26,19 @@ export class UsageReport extends HALResource { */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; @autoserialize - id: string; + id: string; @autoserializeAs('report-type') reportType: string; @autoserialize - points: Point[]; + points: Point[]; @deserialize - _links: { + _links: { self: HALLink; }; } diff --git a/src/app/core/submission/models/correctiontype.model.ts b/src/app/core/submission/models/correctiontype.model.ts index 0b9dd755457..4b5bd1ddd68 100644 --- a/src/app/core/submission/models/correctiontype.model.ts +++ b/src/app/core/submission/models/correctiontype.model.ts @@ -22,7 +22,7 @@ export class CorrectionType extends CacheableObject { */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; @autoserialize /** * The unique identifier for the correction type mode. diff --git a/src/app/core/submission/models/submission-cc-license-url.model.ts b/src/app/core/submission/models/submission-cc-license-url.model.ts index 85fa1d0896e..b1e53aa206e 100644 --- a/src/app/core/submission/models/submission-cc-license-url.model.ts +++ b/src/app/core/submission/models/submission-cc-license-url.model.ts @@ -20,8 +20,8 @@ export class SubmissionCcLicenceUrl extends HALResource { */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; @autoserialize - url: string; + url: string; } diff --git a/src/app/core/submission/models/submission-cc-license.model.ts b/src/app/core/submission/models/submission-cc-license.model.ts index c730aa44fc0..8ab235941fc 100644 --- a/src/app/core/submission/models/submission-cc-license.model.ts +++ b/src/app/core/submission/models/submission-cc-license.model.ts @@ -20,16 +20,16 @@ export class SubmissionCcLicence extends HALResource { */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; @autoserialize - id: string; + id: string; @autoserialize - name: string; + name: string; @autoserialize - fields: Field[]; + fields: Field[]; } export interface Field { diff --git a/src/app/core/submission/models/submission-object.model.ts b/src/app/core/submission/models/submission-object.model.ts index 882fafb4674..d4836f6dcf1 100644 --- a/src/app/core/submission/models/submission-object.model.ts +++ b/src/app/core/submission/models/submission-object.model.ts @@ -35,38 +35,38 @@ export abstract class SubmissionObject extends DSpaceObject implements Cacheable @excludeFromEquals @autoserialize - id: string; + id: string; /** * The SubmissionObject last modified date */ @autoserialize - lastModified: Date; + lastModified: Date; /** * The collection this submission applies to * Will be undefined unless the collection {@link HALLink} has been resolved. */ @link(COLLECTION) - collection?: Observable> | Collection; + collection?: Observable> | Collection; /** * The SubmissionObject's last section's data */ @autoserialize - sections: WorkspaceitemSectionsObject; + sections: WorkspaceitemSectionsObject; /** * The SubmissionObject's last section's errors */ @autoserialize - errors: SubmissionObjectError[]; + errors: SubmissionObjectError[]; /** * The {@link HALLink}s for this SubmissionObject */ @deserialize - _links: { + _links: { self: HALLink; collection: HALLink; item: HALLink; @@ -92,14 +92,14 @@ export abstract class SubmissionObject extends DSpaceObject implements Cacheable * Will be undefined unless the submissionDefinition {@link HALLink} has been resolved. */ @link(SubmissionDefinitionsModel.type) - submissionDefinition?: Observable> | SubmissionDefinitionsModel; + submissionDefinition?: Observable> | SubmissionDefinitionsModel; /** * The submitter for this SubmissionObject * Will be undefined unless the submitter {@link HALLink} has been resolved. */ @link(EPERSON) - submitter?: Observable> | EPerson; + submitter?: Observable> | EPerson; /** * The submission supervision order diff --git a/src/app/core/submission/vocabularies/models/vocabulary-entry-detail.model.ts b/src/app/core/submission/vocabularies/models/vocabulary-entry-detail.model.ts index 3dcb0d374a7..f7dff16a405 100644 --- a/src/app/core/submission/vocabularies/models/vocabulary-entry-detail.model.ts +++ b/src/app/core/submission/vocabularies/models/vocabulary-entry-detail.model.ts @@ -21,19 +21,19 @@ export class VocabularyEntryDetail extends VocabularyEntry { * The unique id of the entry */ @autoserialize - id: string; + id: string; /** * In an hierarchical vocabulary representing if entry is selectable as value */ @autoserialize - selectable: boolean; + selectable: boolean; /** * The {@link HALLink}s for this ExternalSourceEntry */ @deserialize - _links: { + _links: { self: HALLink; vocabulary: HALLink; parent: HALLink; diff --git a/src/app/core/submission/vocabularies/models/vocabulary-entry.model.ts b/src/app/core/submission/vocabularies/models/vocabulary-entry.model.ts index 323db57de14..85b310bad88 100644 --- a/src/app/core/submission/vocabularies/models/vocabulary-entry.model.ts +++ b/src/app/core/submission/vocabularies/models/vocabulary-entry.model.ts @@ -24,25 +24,25 @@ export class VocabularyEntry extends ListableObject { * The identifier of this vocabulary entry */ @autoserialize - authority: string; + authority: string; /** * The display value of this vocabulary entry */ @autoserialize - display: string; + display: string; /** * The value of this vocabulary entry */ @autoserialize - value: string; + value: string; /** * An object containing additional information related to this vocabulary entry */ @autoserialize - otherInformation: OtherInformation; + otherInformation: OtherInformation; /** * A string representing the kind of vocabulary entry @@ -55,7 +55,7 @@ export class VocabularyEntry extends ListableObject { * The {@link HALLink}s for this ExternalSourceEntry */ @deserialize - _links: { + _links: { self: HALLink; vocabularyEntryDetail?: HALLink; }; diff --git a/src/app/core/submission/vocabularies/models/vocabulary.model.ts b/src/app/core/submission/vocabularies/models/vocabulary.model.ts index 9026ce677af..9da5ade3267 100644 --- a/src/app/core/submission/vocabularies/models/vocabulary.model.ts +++ b/src/app/core/submission/vocabularies/models/vocabulary.model.ts @@ -29,32 +29,32 @@ export class Vocabulary implements CacheableObject { * The identifier of this Vocabulary */ @autoserialize - id: string; + id: string; /** * The name of this Vocabulary */ @autoserialize - name: string; + name: string; /** * True if it is possible to scroll all the entries in the vocabulary without providing a filter parameter */ @autoserialize - scrollable: boolean; + scrollable: boolean; /** * True if the vocabulary exposes a tree structure where some entries are parent of others */ @autoserialize - hierarchical: boolean; + hierarchical: boolean; /** * For hierarchical vocabularies express the preference to preload the tree at a specific * level of depth (0 only the top nodes are shown, 1 also their children are preloaded and so on) */ @autoserialize - preloadLevel: any; + preloadLevel: any; /** * A string representing the kind of Vocabulary model @@ -64,13 +64,13 @@ export class Vocabulary implements CacheableObject { public type: any; @link(VOCABULARY_ENTRY, true) - entries?: Observable>>; + entries?: Observable>>; /** * The {@link HALLink}s for this Vocabulary */ @deserialize - _links: { + _links: { self: HALLink, entries: HALLink }; diff --git a/src/app/core/supervision-order/models/supervision-order.model.ts b/src/app/core/supervision-order/models/supervision-order.model.ts index 64087c8a219..6426f62aeca 100644 --- a/src/app/core/supervision-order/models/supervision-order.model.ts +++ b/src/app/core/supervision-order/models/supervision-order.model.ts @@ -32,21 +32,21 @@ export class SupervisionOrder implements CacheableObject { * The identifier for this Supervision Order */ @autoserialize - id: string; + id: string; /** * The object type */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; /** * The object type */ @excludeFromEquals @autoserialize - ordertype: string; + ordertype: string; /** * The universally unique identifier for this Supervision Order @@ -60,7 +60,7 @@ export class SupervisionOrder implements CacheableObject { * The {@link HALLink}s for this SupervisionOrder */ @deserialize - _links: { + _links: { item: HALLink, group: HALLink, self: HALLink, @@ -71,12 +71,12 @@ export class SupervisionOrder implements CacheableObject { * Will be undefined unless the item {@link HALLink} has been resolved. */ @link(ITEM) - item?: Observable>; + item?: Observable>; /** * The group linked by this supervision order * Will be undefined unless the version {@link HALLink} has been resolved. */ @link(GROUP) - group?: Observable>; + group?: Observable>; } diff --git a/src/app/core/tasks/models/advanced-workflow-info.model.ts b/src/app/core/tasks/models/advanced-workflow-info.model.ts index 6e5feec357e..87991a375c8 100644 --- a/src/app/core/tasks/models/advanced-workflow-info.model.ts +++ b/src/app/core/tasks/models/advanced-workflow-info.model.ts @@ -6,6 +6,6 @@ import { autoserialize } from 'cerialize'; export abstract class AdvancedWorkflowInfo { @autoserialize - id: string; + id: string; } diff --git a/src/app/core/tasks/models/rating-advanced-workflow-info.model.ts b/src/app/core/tasks/models/rating-advanced-workflow-info.model.ts index 892806f7d16..6ecb0e6dbfe 100644 --- a/src/app/core/tasks/models/rating-advanced-workflow-info.model.ts +++ b/src/app/core/tasks/models/rating-advanced-workflow-info.model.ts @@ -21,12 +21,12 @@ export class RatingAdvancedWorkflowInfo extends AdvancedWorkflowInfo { * Whether the description is required. */ @autoserialize - descriptionRequired: boolean; + descriptionRequired: boolean; /** * The maximum value. */ @autoserialize - maxValue: number; + maxValue: number; } diff --git a/src/app/core/tasks/models/select-reviewer-advanced-workflow-info.model.ts b/src/app/core/tasks/models/select-reviewer-advanced-workflow-info.model.ts index d202593efb8..307caeaa1fe 100644 --- a/src/app/core/tasks/models/select-reviewer-advanced-workflow-info.model.ts +++ b/src/app/core/tasks/models/select-reviewer-advanced-workflow-info.model.ts @@ -18,6 +18,6 @@ export class SelectReviewerAdvancedWorkflowInfo extends AdvancedWorkflowInfo { static type: ResourceType = SELECT_REVIEWER_ADVANCED_WORKFLOW_INFO; @autoserialize - group: string; + group: string; } diff --git a/src/app/core/tasks/models/task-object.model.ts b/src/app/core/tasks/models/task-object.model.ts index cea886a1c6a..0e5022d5797 100644 --- a/src/app/core/tasks/models/task-object.model.ts +++ b/src/app/core/tasks/models/task-object.model.ts @@ -34,19 +34,19 @@ export class TaskObject extends DSpaceObject implements CacheableObject { * The task identifier */ @autoserialize - id: string; + id: string; /** * The workflow step */ @autoserialize - step: string; + step: string; /** * The {@link HALLink}s for this TaskObject */ @deserialize - _links: { + _links: { self: HALLink; owner: HALLink; group: HALLink; @@ -59,14 +59,14 @@ export class TaskObject extends DSpaceObject implements CacheableObject { * Will be undefined unless the eperson {@link HALLink} has been resolved. */ @link(EPERSON, false, 'owner') - eperson?: Observable>; + eperson?: Observable>; /** * The Group for this task * Will be undefined unless the group {@link HALLink} has been resolved. */ @link(GROUP) - group?: Observable>; + group?: Observable>; /** * The WorkflowItem for this task @@ -81,6 +81,6 @@ export class TaskObject extends DSpaceObject implements CacheableObject { * Will be undefined unless the group {@link HALLink} has been resolved. */ @link(WORKFLOW_ACTION, false, 'action') - action: Observable>; + action: Observable>; } diff --git a/src/app/core/tasks/models/workflow-action-object.model.ts b/src/app/core/tasks/models/workflow-action-object.model.ts index 53ae4249c87..a1010008851 100644 --- a/src/app/core/tasks/models/workflow-action-object.model.ts +++ b/src/app/core/tasks/models/workflow-action-object.model.ts @@ -20,30 +20,30 @@ export class WorkflowAction extends DSpaceObject { * The workflow action's identifier */ @autoserialize - id: string; + id: string; /** * The options available for this workflow action */ @autoserialize - options: string[]; + options: string[]; /** * Whether this action has advanced options */ @autoserialize - advanced: boolean; + advanced: boolean; /** * The advanced options that the user can select at this action */ @autoserialize - advancedOptions: string[]; + advancedOptions: string[]; /** * The advanced info required by the advanced options */ @autoserialize - advancedInfo: AdvancedWorkflowInfo[]; + advancedInfo: AdvancedWorkflowInfo[]; } diff --git a/src/app/core/utilities/equatable.spec.ts b/src/app/core/utilities/equatable.spec.ts index 808c21b39fc..cea3c35b3d0 100644 --- a/src/app/core/utilities/equatable.spec.ts +++ b/src/app/core/utilities/equatable.spec.ts @@ -21,7 +21,7 @@ class Dog extends EquatableObject { class Owner extends EquatableObject { @excludeFromEquals - favouriteFood: string; + favouriteFood: string; constructor( public name: string, diff --git a/src/app/curation-form/curation-form.component.ts b/src/app/curation-form/curation-form.component.ts index 0580193418f..8e1c1b26c8f 100644 --- a/src/app/curation-form/curation-form.component.ts +++ b/src/app/curation-form/curation-form.component.ts @@ -62,7 +62,7 @@ export class CurationFormComponent implements OnDestroy, OnInit { form: UntypedFormGroup; @Input() - dsoHandle: string; + dsoHandle: string; subs: Subscription[] = []; diff --git a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.html b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.html index b79b185b40d..0c1088e3fd8 100644 --- a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.html +++ b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.html @@ -55,7 +55,7 @@
diff --git a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.spec.ts b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.spec.ts index ccfcfca93c4..fbbfe982aac 100644 --- a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.spec.ts +++ b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata-value/dso-edit-metadata-value.component.spec.ts @@ -221,7 +221,7 @@ describe('DsoEditMetadataValueComponent', () => { it('should not show a badge', () => { expect( - fixture.debugElement.query(By.css('ds-themed-type-badge')), + fixture.debugElement.query(By.css('ds-type-badge')), ).toBeNull(); }); @@ -289,7 +289,7 @@ describe('DsoEditMetadataValueComponent', () => { it('should show a badge', () => { expect( - fixture.debugElement.query(By.css('ds-themed-type-badge')), + fixture.debugElement.query(By.css('ds-type-badge')), ).toBeTruthy(); }); diff --git a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata.component.spec.ts b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata.component.spec.ts index 32822f18320..32e57e003d2 100644 --- a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata.component.spec.ts +++ b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata.component.spec.ts @@ -22,7 +22,7 @@ import { Item } from '../../core/shared/item.model'; import { ITEM } from '../../core/shared/item.resource-type'; import { MetadataValue } from '../../core/shared/metadata.models'; import { AlertComponent } from '../../shared/alert/alert.component'; -import { LoadingComponent } from '../../shared/loading/loading.component'; +import { ThemedLoadingComponent } from '../../shared/loading/themed-loading.component'; import { NotificationsService } from '../../shared/notifications/notifications.service'; import { TestDataService } from '../../shared/testing/test-data-service.mock'; import { VarDirective } from '../../shared/utils/var.directive'; @@ -112,7 +112,7 @@ describe('DsoEditMetadataComponent', () => { DsoEditMetadataValueHeadersComponent, DsoEditMetadataFieldValuesComponent, AlertComponent, - LoadingComponent, + ThemedLoadingComponent, ], }, }) diff --git a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata.component.ts b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata.component.ts index 7704abc4ea0..677a601b9df 100644 --- a/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata.component.ts +++ b/src/app/dso-shared/dso-edit-metadata/dso-edit-metadata.component.ts @@ -52,7 +52,7 @@ import { hasValue, isNotEmpty, } from '../../shared/empty.util'; -import { LoadingComponent } from '../../shared/loading/loading.component'; +import { ThemedLoadingComponent } from '../../shared/loading/themed-loading.component'; import { NotificationsService } from '../../shared/notifications/notifications.service'; import { DsoEditMetadataFieldValuesComponent } from './dso-edit-metadata-field-values/dso-edit-metadata-field-values.component'; import { DsoEditMetadataForm } from './dso-edit-metadata-form'; @@ -62,11 +62,11 @@ import { DsoEditMetadataValueHeadersComponent } from './dso-edit-metadata-value- import { MetadataFieldSelectorComponent } from './metadata-field-selector/metadata-field-selector.component'; @Component({ - selector: 'ds-dso-edit-metadata', + selector: 'ds-base-dso-edit-metadata', styleUrls: ['./dso-edit-metadata.component.scss'], templateUrl: './dso-edit-metadata.component.html', standalone: true, - imports: [NgIf, DsoEditMetadataHeadersComponent, MetadataFieldSelectorComponent, DsoEditMetadataValueHeadersComponent, DsoEditMetadataValueComponent, NgFor, DsoEditMetadataFieldValuesComponent, AlertComponent, LoadingComponent, AsyncPipe, TranslateModule], + imports: [NgIf, DsoEditMetadataHeadersComponent, MetadataFieldSelectorComponent, DsoEditMetadataValueHeadersComponent, DsoEditMetadataValueComponent, NgFor, DsoEditMetadataFieldValuesComponent, AlertComponent, ThemedLoadingComponent, AsyncPipe, TranslateModule], }) /** * Component showing a table of all metadata on a DSpaceObject and options to modify them diff --git a/src/app/dso-shared/dso-edit-metadata/themed-dso-edit-metadata.component.ts b/src/app/dso-shared/dso-edit-metadata/themed-dso-edit-metadata.component.ts index 9de9c539a29..063263b6701 100644 --- a/src/app/dso-shared/dso-edit-metadata/themed-dso-edit-metadata.component.ts +++ b/src/app/dso-shared/dso-edit-metadata/themed-dso-edit-metadata.component.ts @@ -9,10 +9,11 @@ import { ThemedComponent } from '../../shared/theme-support/themed.component'; import { DsoEditMetadataComponent } from './dso-edit-metadata.component'; @Component({ - selector: 'ds-themed-dso-edit-metadata', + selector: 'ds-dso-edit-metadata', styleUrls: [], templateUrl: './../../shared/theme-support/themed.component.html', standalone: true, + imports: [DsoEditMetadataComponent], }) export class ThemedDsoEditMetadataComponent extends ThemedComponent { diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.html b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.html index 33ce615305c..bca1a1b3b34 100644 --- a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.html +++ b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-issue/journal-issue-search-result-grid-element.component.html @@ -8,18 +8,18 @@ [attr.rel]="(linkType === linkTypes.ExternalLink) ? 'noopener noreferrer' : null" [routerLink]="[itemPageRoute]" class="card-img-top full-width" [attr.title]="'search.results.view-result' | translate">
- - + +
- - + +
- +

diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.html b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.html index de80448e8db..3b14a1d8b0f 100644 --- a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.html +++ b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal-volume/journal-volume-search-result-grid-element.component.html @@ -8,18 +8,18 @@ [attr.rel]="(linkType === linkTypes.ExternalLink) ? 'noopener noreferrer' : null" [routerLink]="[itemPageRoute]" class="card-img-top full-width" [attr.title]="'search.results.view-result' | translate">
- - + +
- - + +
- +

diff --git a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.html b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.html index b537fb60d92..20084f21ba3 100644 --- a/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.html +++ b/src/app/entity-groups/journal-entities/item-grid-elements/search-result-grid-elements/journal/journal-search-result-grid-element.component.html @@ -8,18 +8,18 @@ [attr.rel]="(linkType === linkTypes.ExternalLink) ? 'noopener noreferrer' : null" [routerLink]="[itemPageRoute]" class="card-img-top full-width" [attr.title]="'search.results.view-result' | translate">
- - + +
- - + +
- +

diff --git a/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-issue/journal-issue-search-result-list-element.component.html b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-issue/journal-issue-search-result-list-element.component.html index 545e8c67a6b..59d2ea4dc9d 100644 --- a/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-issue/journal-issue-search-result-list-element.component.html +++ b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-issue/journal-issue-search-result-list-element.component.html @@ -12,7 +12,7 @@
- + { }).overrideComponent(JournalIssueSearchResultListElementComponent, { add: { changeDetection: ChangeDetectionStrategy.Default } , remove: { - imports: [ThumbnailComponent, ThemedBadgesComponent, TruncatableComponent, TruncatablePartComponent], + imports: [ThemedThumbnailComponent, ThemedBadgesComponent, TruncatableComponent, TruncatablePartComponent], } }, ).compileComponents(); })); diff --git a/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-issue/journal-issue-search-result-list-element.component.ts b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-issue/journal-issue-search-result-list-element.component.ts index ca12acaa10e..f3f8d79809c 100644 --- a/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-issue/journal-issue-search-result-list-element.component.ts +++ b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-issue/journal-issue-search-result-list-element.component.ts @@ -13,7 +13,7 @@ import { listableObjectComponent } from '../../../../../shared/object-collection import { ItemSearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component'; import { TruncatableComponent } from '../../../../../shared/truncatable/truncatable.component'; import { TruncatablePartComponent } from '../../../../../shared/truncatable/truncatable-part/truncatable-part.component'; -import { ThumbnailComponent } from '../../../../../thumbnail/thumbnail.component'; +import { ThemedThumbnailComponent } from '../../../../../thumbnail/themed-thumbnail.component'; @listableObjectComponent('JournalIssueSearchResult', ViewMode.ListElement) @Component({ @@ -21,7 +21,7 @@ import { ThumbnailComponent } from '../../../../../thumbnail/thumbnail.component styleUrls: ['./journal-issue-search-result-list-element.component.scss'], templateUrl: './journal-issue-search-result-list-element.component.html', standalone: true, - imports: [NgIf, RouterLink, ThumbnailComponent, NgClass, ThemedBadgesComponent, TruncatableComponent, TruncatablePartComponent, NgFor, AsyncPipe], + imports: [NgIf, RouterLink, ThemedThumbnailComponent, NgClass, ThemedBadgesComponent, TruncatableComponent, TruncatablePartComponent, NgFor, AsyncPipe], }) /** * The component for displaying a list element for an item search result of the type Journal Issue diff --git a/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-volume/journal-volume-search-result-list-element.component.html b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-volume/journal-volume-search-result-list-element.component.html index 2ccbbe10953..4a6ffb412da 100644 --- a/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-volume/journal-volume-search-result-list-element.component.html +++ b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-volume/journal-volume-search-result-list-element.component.html @@ -12,7 +12,7 @@
- + { add: { changeDetection: ChangeDetectionStrategy.Default }, remove: { imports: [ - ThumbnailComponent, NgClass, ThemedBadgesComponent, TruncatableComponent, TruncatablePartComponent, + ThemedThumbnailComponent, NgClass, ThemedBadgesComponent, TruncatableComponent, TruncatablePartComponent, ], }, }).compileComponents(); @@ -196,7 +196,7 @@ describe('JournalVolumeSearchResultListElementComponent', () => { add: { changeDetection: ChangeDetectionStrategy.Default }, remove: { imports: [ - ThumbnailComponent, + ThemedThumbnailComponent, ThemedBadgesComponent, TruncatableComponent, TruncatablePartComponent, diff --git a/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-volume/journal-volume-search-result-list-element.component.ts b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-volume/journal-volume-search-result-list-element.component.ts index b44a4896b7c..4aee64c4f5a 100644 --- a/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-volume/journal-volume-search-result-list-element.component.ts +++ b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal-volume/journal-volume-search-result-list-element.component.ts @@ -13,7 +13,7 @@ import { listableObjectComponent } from '../../../../../shared/object-collection import { ItemSearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component'; import { TruncatableComponent } from '../../../../../shared/truncatable/truncatable.component'; import { TruncatablePartComponent } from '../../../../../shared/truncatable/truncatable-part/truncatable-part.component'; -import { ThumbnailComponent } from '../../../../../thumbnail/thumbnail.component'; +import { ThemedThumbnailComponent } from '../../../../../thumbnail/themed-thumbnail.component'; @listableObjectComponent('JournalVolumeSearchResult', ViewMode.ListElement) @Component({ @@ -21,7 +21,7 @@ import { ThumbnailComponent } from '../../../../../thumbnail/thumbnail.component styleUrls: ['./journal-volume-search-result-list-element.component.scss'], templateUrl: './journal-volume-search-result-list-element.component.html', standalone: true, - imports: [NgIf, RouterLink, ThumbnailComponent, NgClass, ThemedBadgesComponent, TruncatableComponent, TruncatablePartComponent, NgFor, AsyncPipe], + imports: [NgIf, RouterLink, ThemedThumbnailComponent, NgClass, ThemedBadgesComponent, TruncatableComponent, TruncatablePartComponent, NgFor, AsyncPipe], }) /** * The component for displaying a list element for an item search result of the type Journal Volume diff --git a/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal/journal-search-result-list-element.component.html b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal/journal-search-result-list-element.component.html index 3074d53df6f..bd119493d36 100644 --- a/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal/journal-search-result-list-element.component.html +++ b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal/journal-search-result-list-element.component.html @@ -11,7 +11,7 @@
- + { add: { changeDetection: ChangeDetectionStrategy.Default }, remove: { imports: [ - ThumbnailComponent, + ThemedThumbnailComponent, ThemedBadgesComponent, TruncatableComponent, TruncatablePartComponent, diff --git a/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal/journal-search-result-list-element.component.ts b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal/journal-search-result-list-element.component.ts index d931feece7c..8ef14120e0f 100644 --- a/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal/journal-search-result-list-element.component.ts +++ b/src/app/entity-groups/journal-entities/item-list-elements/search-result-list-elements/journal/journal-search-result-list-element.component.ts @@ -13,7 +13,7 @@ import { listableObjectComponent } from '../../../../../shared/object-collection import { ItemSearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component'; import { TruncatableComponent } from '../../../../../shared/truncatable/truncatable.component'; import { TruncatablePartComponent } from '../../../../../shared/truncatable/truncatable-part/truncatable-part.component'; -import { ThumbnailComponent } from '../../../../../thumbnail/thumbnail.component'; +import { ThemedThumbnailComponent } from '../../../../../thumbnail/themed-thumbnail.component'; @listableObjectComponent('JournalSearchResult', ViewMode.ListElement) @Component({ @@ -21,7 +21,7 @@ import { ThumbnailComponent } from '../../../../../thumbnail/thumbnail.component styleUrls: ['./journal-search-result-list-element.component.scss'], templateUrl: './journal-search-result-list-element.component.html', standalone: true, - imports: [NgIf, RouterLink, ThumbnailComponent, NgClass, ThemedBadgesComponent, TruncatableComponent, TruncatablePartComponent, NgFor, AsyncPipe], + imports: [NgIf, RouterLink, ThemedThumbnailComponent, NgClass, ThemedBadgesComponent, TruncatableComponent, TruncatablePartComponent, NgFor, AsyncPipe], }) /** * The component for displaying a list element for an item search result of the type Journal diff --git a/src/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.html b/src/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.html index 3648b53b51f..e3dec92c52e 100644 --- a/src/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.html +++ b/src/app/entity-groups/journal-entities/item-pages/journal-issue/journal-issue.component.html @@ -1,13 +1,13 @@ - +
- - + +
- + +
- - + +
- + +
- - + +
- +
- - + +
- - + +
- +

diff --git a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.html b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.html index 976d2c55e50..7b444d261c7 100644 --- a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.html +++ b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/person/person-search-result-grid-element.component.html @@ -8,18 +8,18 @@ [attr.rel]="(linkType === linkTypes.ExternalLink) ? 'noopener noreferrer' : null" [routerLink]="[itemPageRoute]" class="card-img-top full-width" [attr.title]="'search.results.view-result' | translate">
- - + +
- - + +
- +

diff --git a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.html b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.html index 1025b4c35d5..2181a4eb07d 100644 --- a/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.html +++ b/src/app/entity-groups/research-entities/item-grid-elements/search-result-grid-elements/project/project-search-result-grid-element.component.html @@ -8,18 +8,18 @@ [attr.rel]="(linkType === linkTypes.ExternalLink) ? 'noopener noreferrer' : null" [routerLink]="[itemPageRoute]" class="card-img-top full-width" [attr.title]="'search.results.view-result' | translate">
- - + +
- - + +
- +

diff --git a/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/org-unit/org-unit-search-result-list-element.component.html b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/org-unit/org-unit-search-result-list-element.component.html index 60251c15b84..ed1181a4077 100644 --- a/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/org-unit/org-unit-search-result-list-element.component.html +++ b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/org-unit/org-unit-search-result-list-element.component.html @@ -18,7 +18,7 @@
- +
- +
- + { schemas: [NO_ERRORS_SCHEMA], }).overrideComponent(ProjectSearchResultListElementComponent, { add: { changeDetection: ChangeDetectionStrategy.Default }, - remove: { imports: [ThumbnailComponent, TruncatableComponent, ThemedBadgesComponent] }, + remove: { imports: [ThemedThumbnailComponent, TruncatableComponent, ThemedBadgesComponent] }, }).compileComponents(); })); diff --git a/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/project/project-search-result-list-element.component.ts b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/project/project-search-result-list-element.component.ts index fc6e031f401..825f7be3875 100644 --- a/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/project/project-search-result-list-element.component.ts +++ b/src/app/entity-groups/research-entities/item-list-elements/search-result-list-elements/project/project-search-result-list-element.component.ts @@ -11,7 +11,7 @@ import { ThemedBadgesComponent } from '../../../../../shared/object-collection/s import { listableObjectComponent } from '../../../../../shared/object-collection/shared/listable-object/listable-object.decorator'; import { ItemSearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component'; import { TruncatableComponent } from '../../../../../shared/truncatable/truncatable.component'; -import { ThumbnailComponent } from '../../../../../thumbnail/thumbnail.component'; +import { ThemedThumbnailComponent } from '../../../../../thumbnail/themed-thumbnail.component'; @listableObjectComponent('ProjectSearchResult', ViewMode.ListElement) @Component({ @@ -19,7 +19,7 @@ import { ThumbnailComponent } from '../../../../../thumbnail/thumbnail.component styleUrls: ['./project-search-result-list-element.component.scss'], templateUrl: './project-search-result-list-element.component.html', standalone: true, - imports: [NgIf, RouterLink, ThumbnailComponent, NgClass, TruncatableComponent, ThemedBadgesComponent, AsyncPipe], + imports: [NgIf, RouterLink, ThemedThumbnailComponent, NgClass, TruncatableComponent, ThemedBadgesComponent, AsyncPipe], }) /** * The component for displaying a list element for an item search result of the type Project diff --git a/src/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.html b/src/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.html index f28550a4e0d..126845e36f9 100644 --- a/src/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.html +++ b/src/app/entity-groups/research-entities/item-pages/org-unit/org-unit.component.html @@ -1,18 +1,18 @@ - +
- - + +
- - + +
- - + +
- - + +
- - + +
- - + - - + diff --git a/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.ts b/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.ts index 49d6ecb59c8..1145fb78e32 100644 --- a/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.ts +++ b/src/app/entity-groups/research-entities/submission/item-list-elements/person/person-search-result-list-submission-element.component.ts @@ -29,7 +29,7 @@ import { listableObjectComponent } from '../../../../../shared/object-collection import { SearchResultListElementComponent } from '../../../../../shared/object-list/search-result-list-element/search-result-list-element.component'; import { SelectableListService } from '../../../../../shared/object-list/selectable-list/selectable-list.service'; import { TruncatableService } from '../../../../../shared/truncatable/truncatable.service'; -import { ThumbnailComponent } from '../../../../../thumbnail/thumbnail.component'; +import { ThemedThumbnailComponent } from '../../../../../thumbnail/themed-thumbnail.component'; import { NameVariantModalComponent } from '../../name-variant-modal/name-variant-modal.component'; import { PersonInputSuggestionsComponent } from './person-suggestions/person-input-suggestions.component'; @@ -39,7 +39,7 @@ import { PersonInputSuggestionsComponent } from './person-suggestions/person-inp styleUrls: ['./person-search-result-list-submission-element.component.scss'], templateUrl: './person-search-result-list-submission-element.component.html', standalone: true, - imports: [NgIf, ThumbnailComponent, NgClass, PersonInputSuggestionsComponent, FormsModule, NgFor, AsyncPipe], + imports: [NgIf, ThemedThumbnailComponent, NgClass, PersonInputSuggestionsComponent, FormsModule, NgFor, AsyncPipe], }) /** diff --git a/src/app/footer/footer.component.ts b/src/app/footer/footer.component.ts index f9fdde78346..99e74ed4aa1 100644 --- a/src/app/footer/footer.component.ts +++ b/src/app/footer/footer.component.ts @@ -27,7 +27,7 @@ import { KlaroService } from '../shared/cookies/klaro.service'; import { hasValue } from '../shared/empty.util'; @Component({ - selector: 'ds-footer', + selector: 'ds-base-footer', styleUrls: ['footer.component.scss'], templateUrl: 'footer.component.html', standalone: true, diff --git a/src/app/footer/themed-footer.component.ts b/src/app/footer/themed-footer.component.ts index 1c3ae830261..a09484ebca5 100644 --- a/src/app/footer/themed-footer.component.ts +++ b/src/app/footer/themed-footer.component.ts @@ -7,10 +7,11 @@ import { FooterComponent } from './footer.component'; * Themed wrapper for FooterComponent */ @Component({ - selector: 'ds-themed-footer', + selector: 'ds-footer', styleUrls: [], templateUrl: '../shared/theme-support/themed.component.html', standalone: true, + imports: [FooterComponent], }) export class ThemedFooterComponent extends ThemedComponent { protected getComponentName(): string { diff --git a/src/app/forbidden/forbidden.component.ts b/src/app/forbidden/forbidden.component.ts index 03441f1bffb..74cfdf31ceb 100644 --- a/src/app/forbidden/forbidden.component.ts +++ b/src/app/forbidden/forbidden.component.ts @@ -12,7 +12,7 @@ import { ServerResponseService } from '../core/services/server-response.service' * This component representing the `Forbidden` DSpace page. */ @Component({ - selector: 'ds-forbidden', + selector: 'ds-base-forbidden', templateUrl: './forbidden.component.html', styleUrls: ['./forbidden.component.scss'], standalone: true, diff --git a/src/app/forbidden/themed-forbidden.component.ts b/src/app/forbidden/themed-forbidden.component.ts index 85efec18ee4..4d1b6d6fb74 100644 --- a/src/app/forbidden/themed-forbidden.component.ts +++ b/src/app/forbidden/themed-forbidden.component.ts @@ -7,10 +7,11 @@ import { ForbiddenComponent } from './forbidden.component'; * Themed wrapper for ForbiddenComponent */ @Component({ - selector: 'ds-themed-forbidden', + selector: 'ds-forbidden', styleUrls: [], templateUrl: '../shared/theme-support/themed.component.html', standalone: true, + imports: [ForbiddenComponent], }) export class ThemedForbiddenComponent extends ThemedComponent { protected getComponentName(): string { diff --git a/src/app/forgot-password/forgot-password-email/forgot-email.component.html b/src/app/forgot-password/forgot-password-email/forgot-email.component.html index aaa0c27b466..995108cdbc3 100644 --- a/src/app/forgot-password/forgot-password-email/forgot-email.component.html +++ b/src/app/forgot-password/forgot-password-email/forgot-email.component.html @@ -1,3 +1,3 @@ - - + diff --git a/src/app/forgot-password/forgot-password-email/forgot-email.component.spec.ts b/src/app/forgot-password/forgot-password-email/forgot-email.component.spec.ts index 5ddeae80519..b9e625caac7 100644 --- a/src/app/forgot-password/forgot-password-email/forgot-email.component.spec.ts +++ b/src/app/forgot-password/forgot-password-email/forgot-email.component.spec.ts @@ -8,7 +8,6 @@ import { import { ReactiveFormsModule } from '@angular/forms'; import { TranslateModule } from '@ngx-translate/core'; -import { RegisterEmailFormComponent } from '../../register-email-form/register-email-form.component'; import { ThemedRegisterEmailFormComponent } from '../../register-email-form/themed-registry-email-form.component'; import { ForgotEmailComponent } from './forgot-email.component'; @@ -23,7 +22,7 @@ describe('ForgotEmailComponent', () => { }) .overrideComponent(ForgotEmailComponent, { remove: { - imports: [RegisterEmailFormComponent, ThemedRegisterEmailFormComponent], + imports: [ThemedRegisterEmailFormComponent], }, }) .compileComponents(); diff --git a/src/app/forgot-password/forgot-password-email/forgot-email.component.ts b/src/app/forgot-password/forgot-password-email/forgot-email.component.ts index a7455c4ca9f..2ab05e6518a 100644 --- a/src/app/forgot-password/forgot-password-email/forgot-email.component.ts +++ b/src/app/forgot-password/forgot-password-email/forgot-email.component.ts @@ -1,17 +1,14 @@ import { Component } from '@angular/core'; import { ThemedRegisterEmailFormComponent } from 'src/app/register-email-form/themed-registry-email-form.component'; -import { - RegisterEmailFormComponent, - TYPE_REQUEST_FORGOT, -} from '../../register-email-form/register-email-form.component'; +import { TYPE_REQUEST_FORGOT } from '../../register-email-form/register-email-form.component'; @Component({ - selector: 'ds-forgot-email', + selector: 'ds-base-forgot-email', styleUrls: ['./forgot-email.component.scss'], templateUrl: './forgot-email.component.html', imports: [ - RegisterEmailFormComponent, ThemedRegisterEmailFormComponent, + ThemedRegisterEmailFormComponent, ], standalone: true, }) diff --git a/src/app/forgot-password/forgot-password-email/themed-forgot-email.component.ts b/src/app/forgot-password/forgot-password-email/themed-forgot-email.component.ts index 936815a49cc..af9f557fbb7 100644 --- a/src/app/forgot-password/forgot-password-email/themed-forgot-email.component.ts +++ b/src/app/forgot-password/forgot-password-email/themed-forgot-email.component.ts @@ -7,10 +7,11 @@ import { ForgotEmailComponent } from './forgot-email.component'; * Themed wrapper for ForgotEmailComponent */ @Component({ - selector: 'ds-themed-forgot-email', + selector: 'ds-forgot-email', styleUrls: [], templateUrl: './../../shared/theme-support/themed.component.html', standalone: true, + imports: [ForgotEmailComponent], }) export class ThemedForgotEmailComponent extends ThemedComponent { protected getComponentName(): string { diff --git a/src/app/forgot-password/forgot-password-form/forgot-password-form.component.ts b/src/app/forgot-password/forgot-password-form/forgot-password-form.component.ts index 3d8d6e3cd7e..442e4bf9fa2 100644 --- a/src/app/forgot-password/forgot-password-form/forgot-password-form.component.ts +++ b/src/app/forgot-password/forgot-password-form/forgot-password-form.component.ts @@ -30,7 +30,7 @@ import { NotificationsService } from '../../shared/notifications/notifications.s import { BrowserOnlyPipe } from '../../shared/utils/browser-only.pipe'; @Component({ - selector: 'ds-forgot-password-form', + selector: 'ds-base-forgot-password-form', styleUrls: ['./forgot-password-form.component.scss'], templateUrl: './forgot-password-form.component.html', imports: [ diff --git a/src/app/forgot-password/forgot-password-form/themed-forgot-password-form.component.ts b/src/app/forgot-password/forgot-password-form/themed-forgot-password-form.component.ts index e74fed2f368..956568e2bfe 100644 --- a/src/app/forgot-password/forgot-password-form/themed-forgot-password-form.component.ts +++ b/src/app/forgot-password/forgot-password-form/themed-forgot-password-form.component.ts @@ -7,10 +7,11 @@ import { ForgotPasswordFormComponent } from './forgot-password-form.component'; * Themed wrapper for ForgotPasswordFormComponent */ @Component({ - selector: 'ds-themed-forgot-password-form', + selector: 'ds-forgot-password-form', styleUrls: [], templateUrl: './../../shared/theme-support/themed.component.html', standalone: true, + imports: [ForgotPasswordFormComponent], }) export class ThemedForgotPasswordFormComponent extends ThemedComponent { protected getComponentName(): string { diff --git a/src/app/header-nav-wrapper/header-navbar-wrapper.component.html b/src/app/header-nav-wrapper/header-navbar-wrapper.component.html index ba3060ff698..60b38dcabf7 100644 --- a/src/app/header-nav-wrapper/header-navbar-wrapper.component.html +++ b/src/app/header-nav-wrapper/header-navbar-wrapper.component.html @@ -1,4 +1,4 @@
- - + +
diff --git a/src/app/header-nav-wrapper/header-navbar-wrapper.component.ts b/src/app/header-nav-wrapper/header-navbar-wrapper.component.ts index 862173b9bb0..53f10575315 100644 --- a/src/app/header-nav-wrapper/header-navbar-wrapper.component.ts +++ b/src/app/header-nav-wrapper/header-navbar-wrapper.component.ts @@ -21,7 +21,7 @@ import { MenuID } from '../shared/menu/menu-id.model'; * This component represents a wrapper for the horizontal navbar and the header */ @Component({ - selector: 'ds-header-navbar-wrapper', + selector: 'ds-base-header-navbar-wrapper', styleUrls: ['header-navbar-wrapper.component.scss'], templateUrl: 'header-navbar-wrapper.component.html', standalone: true, diff --git a/src/app/header-nav-wrapper/themed-header-navbar-wrapper.component.ts b/src/app/header-nav-wrapper/themed-header-navbar-wrapper.component.ts index 5895530e8aa..64d36edae35 100644 --- a/src/app/header-nav-wrapper/themed-header-navbar-wrapper.component.ts +++ b/src/app/header-nav-wrapper/themed-header-navbar-wrapper.component.ts @@ -7,10 +7,11 @@ import { HeaderNavbarWrapperComponent } from './header-navbar-wrapper.component' * Themed wrapper for {@link HeaderNavbarWrapperComponent} */ @Component({ - selector: 'ds-themed-header-navbar-wrapper', + selector: 'ds-header-navbar-wrapper', styleUrls: [], templateUrl: '../shared/theme-support/themed.component.html', standalone: true, + imports: [HeaderNavbarWrapperComponent], }) export class ThemedHeaderNavbarWrapperComponent extends ThemedComponent { protected getComponentName(): string { diff --git a/src/app/header/header.component.html b/src/app/header/header.component.html index e98959d1626..e59086134a7 100644 --- a/src/app/header/header.component.html +++ b/src/app/header/header.component.html @@ -6,10 +6,10 @@
- +
diff --git a/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/paginated-drag-and-drop-bitstream-list/paginated-drag-and-drop-bitstream-list.component.html b/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/paginated-drag-and-drop-bitstream-list/paginated-drag-and-drop-bitstream-list.component.html index 20b5dc708fa..c3d6ebc8239 100644 --- a/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/paginated-drag-and-drop-bitstream-list/paginated-drag-and-drop-bitstream-list.component.html +++ b/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream-bundle/paginated-drag-and-drop-bitstream-list/paginated-drag-and-drop-bitstream-list.component.html @@ -28,5 +28,5 @@
- + diff --git a/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.ts b/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.ts index 5706805661b..81950d33211 100644 --- a/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.ts +++ b/src/app/item-page/edit-item-page/item-bitstreams/item-edit-bitstream/item-edit-bitstream.component.ts @@ -145,7 +145,7 @@ export class ItemEditBitstreamComponent implements OnChanges, OnDestroy, OnInit * Check if a user should be allowed to cancel the update to this field */ canUndo(): boolean { - return this.fieldUpdate.changeType >= 0; + return this.fieldUpdate.changeType?.valueOf() >= 0; } } diff --git a/src/app/item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.html b/src/app/item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.html index 57287fdfe2e..9e298edcc61 100644 --- a/src/app/item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.html +++ b/src/app/item-page/edit-item-page/item-collection-mapper/item-collection-mapper.component.html @@ -27,13 +27,13 @@

{{'item.edit.item-mapper.head' | translate}}

- - +
diff --git a/src/app/item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.html b/src/app/item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.html index 5015c8e1e5e..0a99a5820f8 100644 --- a/src/app/item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.html +++ b/src/app/item-page/edit-item-page/item-relationships/edit-relationship-list/edit-relationship-list.component.html @@ -30,5 +30,5 @@

{{"item.edit.relationships.no-relationships" | translate}}
- + diff --git a/src/app/item-page/edit-item-page/item-relationships/edit-relationship/edit-relationship.component.ts b/src/app/item-page/edit-item-page/item-relationships/edit-relationship/edit-relationship.component.ts index 8341070537e..5f213327e30 100644 --- a/src/app/item-page/edit-item-page/item-relationships/edit-relationship/edit-relationship.component.ts +++ b/src/app/item-page/edit-item-page/item-relationships/edit-relationship/edit-relationship.component.ts @@ -199,6 +199,6 @@ export class EditRelationshipComponent implements OnChanges { * Check if a user should be allowed to cancel the update to this field */ canUndo(): boolean { - return this.fieldUpdate.changeType >= 0; + return this.fieldUpdate.changeType?.valueOf() >= 0; } } diff --git a/src/app/item-page/edit-item-page/item-relationships/item-relationships.component.html b/src/app/item-page/edit-item-page/item-relationships/item-relationships.component.html index 3a0a33d1a05..c3556962d4d 100644 --- a/src/app/item-page/edit-item-page/item-relationships/item-relationships.component.html +++ b/src/app/item-page/edit-item-page/item-relationships/item-relationships.component.html @@ -32,7 +32,7 @@ >

- +
diff --git a/src/app/item-page/edit-item-page/item-status/item-status.component.ts b/src/app/item-page/edit-item-page/item-status/item-status.component.ts index f330c2e457c..bbd7b99a977 100644 --- a/src/app/item-page/edit-item-page/item-status/item-status.component.ts +++ b/src/app/item-page/edit-item-page/item-status/item-status.component.ts @@ -58,7 +58,7 @@ import { ItemOperationComponent } from '../item-operation/item-operation.compone import { ItemOperation } from '../item-operation/itemOperation.model'; @Component({ - selector: 'ds-item-status', + selector: 'ds-base-item-status', templateUrl: './item-status.component.html', changeDetection: ChangeDetectionStrategy.Default, animations: [ diff --git a/src/app/item-page/edit-item-page/item-status/themed-item-status.component.ts b/src/app/item-page/edit-item-page/item-status/themed-item-status.component.ts index 705ef6d8adc..c3ba17a4b51 100644 --- a/src/app/item-page/edit-item-page/item-status/themed-item-status.component.ts +++ b/src/app/item-page/edit-item-page/item-status/themed-item-status.component.ts @@ -4,10 +4,11 @@ import { ThemedComponent } from '../../../shared/theme-support/themed.component' import { ItemStatusComponent } from './item-status.component'; @Component({ - selector: 'ds-themed-item-status', + selector: 'ds-item-status', styleUrls: [], templateUrl: '../../../shared/theme-support/themed.component.html', standalone: true, + imports: [ItemStatusComponent], }) export class ThemedItemStatusComponent extends ThemedComponent { protected getComponentName(): string { diff --git a/src/app/item-page/field-components/metadata-values/metadata-values.component.ts b/src/app/item-page/field-components/metadata-values/metadata-values.component.ts index abc26c0d82b..1a73d692ebf 100644 --- a/src/app/item-page/field-components/metadata-values/metadata-values.component.ts +++ b/src/app/item-page/field-components/metadata-values/metadata-values.component.ts @@ -117,6 +117,8 @@ export class MetadataValuesComponent implements OnChanges { */ getQueryParams(value) { const queryParams = { startsWith: value }; + // todo: should compare with type instead? + // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison if (this.browseDefinition.getRenderType() === VALUE_LIST_BROWSE_DEFINITION.value) { return { value: value }; } diff --git a/src/app/item-page/full/field-components/file-section/full-file-section.component.html b/src/app/item-page/full/field-components/file-section/full-file-section.component.html index d4b58742c4f..8c534e66309 100644 --- a/src/app/item-page/full/field-components/file-section/full-file-section.component.html +++ b/src/app/item-page/full/field-components/file-section/full-file-section.component.html @@ -12,7 +12,7 @@

{{"item.page.filesection.original.bund
- +
@@ -33,9 +33,9 @@

{{"item.page.filesection.original.bund

- + {{"item.page.filesection.download" | translate}} - +
@@ -54,7 +54,7 @@

{{"item.page.filesection.license.bundl
- +
@@ -73,9 +73,9 @@

{{"item.page.filesection.license.bundl

- + {{"item.page.filesection.download" | translate}} - +
diff --git a/src/app/item-page/full/field-components/file-section/full-file-section.component.ts b/src/app/item-page/full/field-components/file-section/full-file-section.component.ts index 8f8b01eb267..f038b18bfc7 100644 --- a/src/app/item-page/full/field-components/file-section/full-file-section.component.ts +++ b/src/app/item-page/full/field-components/file-section/full-file-section.component.ts @@ -52,7 +52,7 @@ import { FileSectionComponent } from '../../../simple/field-components/file-sect */ @Component({ - selector: 'ds-item-page-full-file-section', + selector: 'ds-base-item-page-full-file-section', styleUrls: ['./full-file-section.component.scss'], templateUrl: './full-file-section.component.html', imports: [ diff --git a/src/app/item-page/full/field-components/file-section/themed-full-file-section.component.ts b/src/app/item-page/full/field-components/file-section/themed-full-file-section.component.ts index 38a4879715e..425b0cffd8e 100644 --- a/src/app/item-page/full/field-components/file-section/themed-full-file-section.component.ts +++ b/src/app/item-page/full/field-components/file-section/themed-full-file-section.component.ts @@ -11,10 +11,11 @@ import { FullFileSectionComponent } from './full-file-section.component'; * Themed wrapper for {@link FullFileSectionComponent} */ @Component({ - selector: 'ds-themed-item-page-full-file-section', + selector: 'ds-item-page-full-file-section', styleUrls: [], templateUrl: './../../../../shared/theme-support/themed.component.html', standalone: true, + imports: [FullFileSectionComponent], }) export class ThemedFullFileSectionComponent extends ThemedComponent { diff --git a/src/app/item-page/full/full-item-page.component.html b/src/app/item-page/full/full-item-page.component.html index 1d831813956..b6e1d1e6edb 100644 --- a/src/app/item-page/full/full-item-page.component.html +++ b/src/app/item-page/full/full-item-page.component.html @@ -1,12 +1,12 @@
- +
- +
- +
@@ -40,5 +40,5 @@
- +
diff --git a/src/app/item-page/full/full-item-page.component.ts b/src/app/item-page/full/full-item-page.component.ts index fba1d00e9bf..c041d80d1c0 100644 --- a/src/app/item-page/full/full-item-page.component.ts +++ b/src/app/item-page/full/full-item-page.component.ts @@ -60,7 +60,7 @@ import { ThemedFullFileSectionComponent } from './field-components/file-section/ */ @Component({ - selector: 'ds-full-item-page', + selector: 'ds-base-full-item-page', styleUrls: ['./full-item-page.component.scss'], templateUrl: './full-item-page.component.html', changeDetection: ChangeDetectionStrategy.OnPush, diff --git a/src/app/item-page/full/themed-full-item-page.component.ts b/src/app/item-page/full/themed-full-item-page.component.ts index f29947b075e..f5034d3042d 100644 --- a/src/app/item-page/full/themed-full-item-page.component.ts +++ b/src/app/item-page/full/themed-full-item-page.component.ts @@ -7,10 +7,11 @@ import { FullItemPageComponent } from './full-item-page.component'; * Themed wrapper for FullItemPageComponent */ @Component({ - selector: 'ds-themed-full-item-page', + selector: 'ds-full-item-page', styleUrls: [], templateUrl: './../../shared/theme-support/themed.component.html', standalone: true, + imports: [FullItemPageComponent], }) export class ThemedFullItemPageComponent extends ThemedComponent { protected getComponentName(): string { diff --git a/src/app/item-page/media-viewer/media-viewer-image/media-viewer-image.component.ts b/src/app/item-page/media-viewer/media-viewer-image/media-viewer-image.component.ts index 4523068118c..f2191f074da 100644 --- a/src/app/item-page/media-viewer/media-viewer-image/media-viewer-image.component.ts +++ b/src/app/item-page/media-viewer/media-viewer-image/media-viewer-image.component.ts @@ -20,7 +20,7 @@ import { MediaViewerItem } from '../../../core/shared/media-viewer-item.model'; * This componenet render an image gallery for the image viewer */ @Component({ - selector: 'ds-media-viewer-image', + selector: 'ds-base-media-viewer-image', templateUrl: './media-viewer-image.component.html', styleUrls: ['./media-viewer-image.component.scss'], imports: [ diff --git a/src/app/item-page/media-viewer/media-viewer-image/themed-media-viewer-image.component.ts b/src/app/item-page/media-viewer/media-viewer-image/themed-media-viewer-image.component.ts index 84ffeaca5c9..d7df6da6294 100644 --- a/src/app/item-page/media-viewer/media-viewer-image/themed-media-viewer-image.component.ts +++ b/src/app/item-page/media-viewer/media-viewer-image/themed-media-viewer-image.component.ts @@ -11,10 +11,11 @@ import { MediaViewerImageComponent } from './media-viewer-image.component'; * Themed wrapper for {@link MediaViewerImageComponent}. */ @Component({ - selector: 'ds-themed-media-viewer-image', + selector: 'ds-media-viewer-image', styleUrls: [], templateUrl: '../../../shared/theme-support/themed.component.html', standalone: true, + imports: [MediaViewerImageComponent], }) export class ThemedMediaViewerImageComponent extends ThemedComponent { diff --git a/src/app/item-page/media-viewer/media-viewer-video/media-viewer-video.component.ts b/src/app/item-page/media-viewer/media-viewer-video/media-viewer-video.component.ts index 7523e0109fd..700431ff3f6 100644 --- a/src/app/item-page/media-viewer/media-viewer-video/media-viewer-video.component.ts +++ b/src/app/item-page/media-viewer/media-viewer-video/media-viewer-video.component.ts @@ -19,7 +19,7 @@ import { languageHelper } from './language-helper'; * This component renders a video viewer and playlist for the media viewer */ @Component({ - selector: 'ds-media-viewer-video', + selector: 'ds-base-media-viewer-video', templateUrl: './media-viewer-video.component.html', styleUrls: ['./media-viewer-video.component.scss'], imports: [ diff --git a/src/app/item-page/media-viewer/media-viewer-video/themed-media-viewer-video.component.ts b/src/app/item-page/media-viewer/media-viewer-video/themed-media-viewer-video.component.ts index 797780d3b81..800034835c0 100644 --- a/src/app/item-page/media-viewer/media-viewer-video/themed-media-viewer-video.component.ts +++ b/src/app/item-page/media-viewer/media-viewer-video/themed-media-viewer-video.component.ts @@ -12,10 +12,11 @@ import { MediaViewerVideoComponent } from './media-viewer-video.component'; * Themed wrapper for {@link MediaViewerVideoComponent}. */ @Component({ - selector: 'ds-themed-media-viewer-video', + selector: 'ds-media-viewer-video', styleUrls: [], templateUrl: '../../../shared/theme-support/themed.component.html', standalone: true, + imports: [MediaViewerVideoComponent], }) export class ThemedMediaViewerVideoComponent extends ThemedComponent { diff --git a/src/app/item-page/media-viewer/media-viewer.component.html b/src/app/item-page/media-viewer/media-viewer.component.html index c8a02e039c7..a76ee739638 100644 --- a/src/app/item-page/media-viewer/media-viewer.component.html +++ b/src/app/item-page/media-viewer/media-viewer.component.html @@ -1,25 +1,25 @@ - + >
- - + +
- + > diff --git a/src/app/item-page/media-viewer/media-viewer.component.spec.ts b/src/app/item-page/media-viewer/media-viewer.component.spec.ts index 4d023074525..7649e17b71e 100644 --- a/src/app/item-page/media-viewer/media-viewer.component.spec.ts +++ b/src/app/item-page/media-viewer/media-viewer.component.spec.ts @@ -124,7 +124,7 @@ describe('MediaViewerComponent', () => { }); it('should display a loading component', () => { - const loading = fixture.debugElement.query(By.css('ds-themed-loading')); + const loading = fixture.debugElement.query(By.css('ds-loading')); expect(loading.nativeElement).toBeDefined(); }); }); @@ -152,7 +152,7 @@ describe('MediaViewerComponent', () => { it('should display a default, thumbnail', () => { const defaultThumbnail = fixture.debugElement.query( - By.css('ds-themed-media-viewer-image'), + By.css('ds-media-viewer-image'), ); expect(defaultThumbnail.nativeElement).toBeDefined(); }); diff --git a/src/app/item-page/media-viewer/media-viewer.component.ts b/src/app/item-page/media-viewer/media-viewer.component.ts index fbeadee905f..7513f5dada3 100644 --- a/src/app/item-page/media-viewer/media-viewer.component.ts +++ b/src/app/item-page/media-viewer/media-viewer.component.ts @@ -34,7 +34,7 @@ import { hasValue } from '../../shared/empty.util'; import { ThemedLoadingComponent } from '../../shared/loading/themed-loading.component'; import { followLink } from '../../shared/utils/follow-link-config.model'; import { VarDirective } from '../../shared/utils/var.directive'; -import { ThumbnailComponent } from '../../thumbnail/thumbnail.component'; +import { ThemedThumbnailComponent } from '../../thumbnail/themed-thumbnail.component'; import { ThemedMediaViewerImageComponent } from './media-viewer-image/themed-media-viewer-image.component'; import { ThemedMediaViewerVideoComponent } from './media-viewer-video/themed-media-viewer-video.component'; @@ -42,12 +42,12 @@ import { ThemedMediaViewerVideoComponent } from './media-viewer-video/themed-med * This component renders the media viewers */ @Component({ - selector: 'ds-media-viewer', + selector: 'ds-base-media-viewer', templateUrl: './media-viewer.component.html', styleUrls: ['./media-viewer.component.scss'], imports: [ ThemedMediaViewerImageComponent, - ThumbnailComponent, + ThemedThumbnailComponent, AsyncPipe, NgIf, ThemedMediaViewerVideoComponent, diff --git a/src/app/item-page/media-viewer/themed-media-viewer.component.ts b/src/app/item-page/media-viewer/themed-media-viewer.component.ts index da790fbd4ad..0fa5657094a 100644 --- a/src/app/item-page/media-viewer/themed-media-viewer.component.ts +++ b/src/app/item-page/media-viewer/themed-media-viewer.component.ts @@ -12,10 +12,11 @@ import { MediaViewerComponent } from './media-viewer.component'; * Themed wrapper for {@link MediaViewerComponent}. */ @Component({ - selector: 'ds-themed-media-viewer', + selector: 'ds-media-viewer', styleUrls: [], templateUrl: '../../shared/theme-support/themed.component.html', standalone: true, + imports: [MediaViewerComponent], }) export class ThemedMediaViewerComponent extends ThemedComponent { diff --git a/src/app/item-page/orcid-page/orcid-page.component.ts b/src/app/item-page/orcid-page/orcid-page.component.ts index 1277d0d3411..a3c31e791d4 100644 --- a/src/app/item-page/orcid-page/orcid-page.component.ts +++ b/src/app/item-page/orcid-page/orcid-page.component.ts @@ -38,7 +38,7 @@ import { import { AlertComponent } from '../../shared/alert/alert.component'; import { AlertType } from '../../shared/alert/alert-type'; import { isNotEmpty } from '../../shared/empty.util'; -import { LoadingComponent } from '../../shared/loading/loading.component'; +import { ThemedLoadingComponent } from '../../shared/loading/themed-loading.component'; import { getItemPageRoute } from '../item-page-routing-paths'; import { OrcidAuthComponent } from './orcid-auth/orcid-auth.component'; import { OrcidQueueComponent } from './orcid-queue/orcid-queue.component'; @@ -53,7 +53,7 @@ import { OrcidSyncSettingsComponent } from './orcid-sync-settings/orcid-sync-set styleUrls: ['./orcid-page.component.scss'], imports: [ CommonModule, - LoadingComponent, + ThemedLoadingComponent, AlertComponent, OrcidAuthComponent, OrcidSyncSettingsComponent, diff --git a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts index c783e592c6b..0f02d7083c2 100644 --- a/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts +++ b/src/app/item-page/orcid-page/orcid-queue/orcid-queue.component.ts @@ -37,7 +37,7 @@ import { getFirstCompletedRemoteData } from '../../../core/shared/operators'; import { AlertComponent } from '../../../shared/alert/alert.component'; import { AlertType } from '../../../shared/alert/alert-type'; import { hasValue } from '../../../shared/empty.util'; -import { LoadingComponent } from '../../../shared/loading/loading.component'; +import { ThemedLoadingComponent } from '../../../shared/loading/themed-loading.component'; import { NotificationsService } from '../../../shared/notifications/notifications.service'; import { PaginationComponent } from '../../../shared/pagination/pagination.component'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; @@ -50,7 +50,7 @@ import { PaginationComponentOptions } from '../../../shared/pagination/paginatio CommonModule, NgbTooltipModule, TranslateModule, - LoadingComponent, + ThemedLoadingComponent, AlertComponent, PaginationComponent, ], diff --git a/src/app/item-page/simple/field-components/file-section/file-section.component.html b/src/app/item-page/simple/field-components/file-section/file-section.component.html index e1748e8bcf6..44c83b86267 100644 --- a/src/app/item-page/simple/field-components/file-section/file-section.component.html +++ b/src/app/item-page/simple/field-components/file-section/file-section.component.html @@ -1,15 +1,15 @@
- + {{ 'item.page.bitstreams.primary' | translate }} {{ dsoNameService.getName(file) }} ({{(file?.sizeBytes) | dsFileSize }}) - - + +
diff --git a/src/app/item-page/simple/field-components/file-section/file-section.component.spec.ts b/src/app/item-page/simple/field-components/file-section/file-section.component.spec.ts index b2fb2bf29f0..9ead81c3373 100644 --- a/src/app/item-page/simple/field-components/file-section/file-section.component.spec.ts +++ b/src/app/item-page/simple/field-components/file-section/file-section.component.spec.ts @@ -132,7 +132,7 @@ describe('FileSectionComponent', () => { }); it('should display a loading component', () => { - const loading = fixture.debugElement.query(By.css('ds-themed-loading')); + const loading = fixture.debugElement.query(By.css('ds-loading')); expect(loading.nativeElement).toBeDefined(); }); }); @@ -155,7 +155,7 @@ describe('FileSectionComponent', () => { it('one bitstream should be on the page', () => { const viewMore = fixture.debugElement.query(By.css('.bitstream-view-more')); viewMore.triggerEventHandler('click', null); - const fileDownloadLink = fixture.debugElement.queryAll(By.css('ds-themed-file-download-link')); + const fileDownloadLink = fixture.debugElement.queryAll(By.css('ds-file-download-link')); expect(fileDownloadLink.length).toEqual(1); }); @@ -168,7 +168,7 @@ describe('FileSectionComponent', () => { }); it('should contain another bitstream', () => { - const fileDownloadLink = fixture.debugElement.queryAll(By.css('ds-themed-file-download-link')); + const fileDownloadLink = fixture.debugElement.queryAll(By.css('ds-file-download-link')); expect(fileDownloadLink.length).toEqual(2); }); }); diff --git a/src/app/item-page/simple/field-components/file-section/file-section.component.ts b/src/app/item-page/simple/field-components/file-section/file-section.component.ts index 8a88989a055..9df34e0d133 100644 --- a/src/app/item-page/simple/field-components/file-section/file-section.component.ts +++ b/src/app/item-page/simple/field-components/file-section/file-section.component.ts @@ -35,7 +35,7 @@ import { VarDirective } from '../../../../shared/utils/var.directive'; * inside a 'ds-metadata-field-wrapper' component. */ @Component({ - selector: 'ds-item-page-file-section', + selector: 'ds-base-item-page-file-section', templateUrl: './file-section.component.html', imports: [ CommonModule, diff --git a/src/app/item-page/simple/field-components/file-section/themed-file-section.component.ts b/src/app/item-page/simple/field-components/file-section/themed-file-section.component.ts index 7a7229715d7..2dd8a1df73e 100644 --- a/src/app/item-page/simple/field-components/file-section/themed-file-section.component.ts +++ b/src/app/item-page/simple/field-components/file-section/themed-file-section.component.ts @@ -8,9 +8,10 @@ import { ThemedComponent } from '../../../../shared/theme-support/themed.compone import { FileSectionComponent } from './file-section.component'; @Component({ - selector: 'ds-themed-item-page-file-section', + selector: 'ds-item-page-file-section', templateUrl: '../../../../shared/theme-support/themed.component.html', standalone: true, + imports: [FileSectionComponent], }) export class ThemedFileSectionComponent extends ThemedComponent { diff --git a/src/app/item-page/simple/field-components/specific-field/title/item-page-title-field.component.ts b/src/app/item-page/simple/field-components/specific-field/title/item-page-title-field.component.ts index 79238054627..27d7fc585e7 100644 --- a/src/app/item-page/simple/field-components/specific-field/title/item-page-title-field.component.ts +++ b/src/app/item-page/simple/field-components/specific-field/title/item-page-title-field.component.ts @@ -9,7 +9,7 @@ import { DSONameService } from '../../../../../core/breadcrumbs/dso-name.service import { Item } from '../../../../../core/shared/item.model'; @Component({ - selector: 'ds-item-page-title-field', + selector: 'ds-base-item-page-title-field', templateUrl: './item-page-title-field.component.html', standalone: true, imports: [NgIf, TranslateModule], diff --git a/src/app/item-page/simple/field-components/specific-field/title/themed-item-page-field.component.ts b/src/app/item-page/simple/field-components/specific-field/title/themed-item-page-field.component.ts index 8e4eb532fcc..385a98d47f6 100644 --- a/src/app/item-page/simple/field-components/specific-field/title/themed-item-page-field.component.ts +++ b/src/app/item-page/simple/field-components/specific-field/title/themed-item-page-field.component.ts @@ -11,10 +11,11 @@ import { ItemPageTitleFieldComponent } from './item-page-title-field.component'; * Themed wrapper for {@link ItemPageTitleFieldComponent} */ @Component({ - selector: 'ds-themed-item-page-title-field', + selector: 'ds-item-page-title-field', styleUrls: [], templateUrl: '../../../../../shared/theme-support/themed.component.html', standalone: true, + imports: [ItemPageTitleFieldComponent], }) export class ThemedItemPageTitleFieldComponent extends ThemedComponent { diff --git a/src/app/item-page/simple/item-page.component.html b/src/app/item-page/simple/item-page.component.html index dc8ed87a86a..912115c9612 100644 --- a/src/app/item-page/simple/item-page.component.html +++ b/src/app/item-page/simple/item-page.component.html @@ -1,7 +1,7 @@
- + @@ -11,5 +11,5 @@
- +
diff --git a/src/app/item-page/simple/item-page.component.spec.ts b/src/app/item-page/simple/item-page.component.spec.ts index 2766bee3a5d..827af05b651 100644 --- a/src/app/item-page/simple/item-page.component.spec.ts +++ b/src/app/item-page/simple/item-page.component.spec.ts @@ -182,7 +182,7 @@ describe('ItemPageComponent', () => { }); it('should display a loading component', () => { - const loading = fixture.debugElement.query(By.css('ds-themed-loading')); + const loading = fixture.debugElement.query(By.css('ds-loading')); expect(loading.nativeElement).toBeDefined(); }); }); diff --git a/src/app/item-page/simple/item-page.component.ts b/src/app/item-page/simple/item-page.component.ts index cb6da792a13..f1155fd10fe 100644 --- a/src/app/item-page/simple/item-page.component.ts +++ b/src/app/item-page/simple/item-page.component.ts @@ -64,7 +64,7 @@ import { QaEventNotificationComponent } from './qa-event-notification/qa-event-n * All fields of the item that should be displayed, are defined in its template. */ @Component({ - selector: 'ds-item-page', + selector: 'ds-base-item-page', styleUrls: ['./item-page.component.scss'], templateUrl: './item-page.component.html', changeDetection: ChangeDetectionStrategy.OnPush, diff --git a/src/app/item-page/simple/item-types/publication/publication.component.html b/src/app/item-page/simple/item-types/publication/publication.component.html index d09b560042b..5f96682be26 100644 --- a/src/app/item-page/simple/item-types/publication/publication.component.html +++ b/src/app/item-page/simple/item-types/publication/publication.component.html @@ -1,4 +1,4 @@ - +
- - + +
- +
- +
- + - - + diff --git a/src/app/item-page/simple/item-types/untyped-item/untyped-item.component.html b/src/app/item-page/simple/item-types/untyped-item/untyped-item.component.html index 35a00dc7b7f..5ab42556e2c 100644 --- a/src/app/item-page/simple/item-types/untyped-item/untyped-item.component.html +++ b/src/app/item-page/simple/item-types/untyped-item/untyped-item.component.html @@ -1,4 +1,4 @@ - +
- - + +
- +
- +
- + - - + diff --git a/src/app/item-page/simple/metadata-representation-list/metadata-representation-list.component.html b/src/app/item-page/simple/metadata-representation-list/metadata-representation-list.component.html index efbe9206d18..424c2324fa3 100644 --- a/src/app/item-page/simple/metadata-representation-list/metadata-representation-list.component.html +++ b/src/app/item-page/simple/metadata-representation-list/metadata-representation-list.component.html @@ -4,7 +4,7 @@ - +
diff --git a/src/app/login-page/login-page.component.ts b/src/app/login-page/login-page.component.ts index 286de604244..fad35b84b65 100644 --- a/src/app/login-page/login-page.component.ts +++ b/src/app/login-page/login-page.component.ts @@ -28,18 +28,17 @@ import { hasValue, isNotEmpty, } from '../shared/empty.util'; -import { LogInComponent } from '../shared/log-in/log-in.component'; import { ThemedLogInComponent } from '../shared/log-in/themed-log-in.component'; /** * This component represents the login page */ @Component({ - selector: 'ds-login-page', + selector: 'ds-base-login-page', styleUrls: ['./login-page.component.scss'], templateUrl: './login-page.component.html', standalone: true, - imports: [LogInComponent, ThemedLogInComponent, TranslateModule], + imports: [ThemedLogInComponent, TranslateModule], }) export class LoginPageComponent implements OnDestroy, OnInit { diff --git a/src/app/login-page/themed-login-page.component.ts b/src/app/login-page/themed-login-page.component.ts index a9956751b4d..1584c479d5a 100644 --- a/src/app/login-page/themed-login-page.component.ts +++ b/src/app/login-page/themed-login-page.component.ts @@ -7,10 +7,11 @@ import { LoginPageComponent } from './login-page.component'; * Themed wrapper for LoginPageComponent */ @Component({ - selector: 'ds-themed-login-page', + selector: 'ds-login-page', styleUrls: [], templateUrl: './../shared/theme-support/themed.component.html', standalone: true, + imports: [LoginPageComponent], }) export class ThemedLoginPageComponent extends ThemedComponent { protected getComponentName(): string { diff --git a/src/app/logout-page/logout-page.component.ts b/src/app/logout-page/logout-page.component.ts index b4623ee215a..8859a92a8bd 100644 --- a/src/app/logout-page/logout-page.component.ts +++ b/src/app/logout-page/logout-page.component.ts @@ -4,7 +4,7 @@ import { TranslateModule } from '@ngx-translate/core'; import { LogOutComponent } from '../shared/log-out/log-out.component'; @Component({ - selector: 'ds-logout-page', + selector: 'ds-base-logout-page', styleUrls: ['./logout-page.component.scss'], templateUrl: './logout-page.component.html', standalone: true, diff --git a/src/app/logout-page/themed-logout-page.component.ts b/src/app/logout-page/themed-logout-page.component.ts index 3c89cb0165e..72be4a053be 100644 --- a/src/app/logout-page/themed-logout-page.component.ts +++ b/src/app/logout-page/themed-logout-page.component.ts @@ -7,10 +7,11 @@ import { LogoutPageComponent } from './logout-page.component'; * Themed wrapper for LogoutPageComponent */ @Component({ - selector: 'ds-themed-logout-page', + selector: 'ds-logout-page', styleUrls: [], templateUrl: './../shared/theme-support/themed.component.html', standalone: true, + imports: [LogoutPageComponent], }) export class ThemedLogoutPageComponent extends ThemedComponent { protected getComponentName(): string { diff --git a/src/app/lookup-by-id/objectnotfound/objectnotfound.component.ts b/src/app/lookup-by-id/objectnotfound/objectnotfound.component.ts index 4e67f6e8bf4..e8ab615e9ea 100644 --- a/src/app/lookup-by-id/objectnotfound/objectnotfound.component.ts +++ b/src/app/lookup-by-id/objectnotfound/objectnotfound.component.ts @@ -15,7 +15,7 @@ import { ServerResponseService } from 'src/app/core/services/server-response.ser * This component representing the `PageNotFound` DSpace page. */ @Component({ - selector: 'ds-objnotfound', + selector: 'ds-base-objnotfound', styleUrls: ['./objectnotfound.component.scss'], templateUrl: './objectnotfound.component.html', changeDetection: ChangeDetectionStrategy.Default, diff --git a/src/app/lookup-by-id/objectnotfound/themed-objectnotfound.component.ts b/src/app/lookup-by-id/objectnotfound/themed-objectnotfound.component.ts index 4474a9724ff..9b46f0efd2b 100644 --- a/src/app/lookup-by-id/objectnotfound/themed-objectnotfound.component.ts +++ b/src/app/lookup-by-id/objectnotfound/themed-objectnotfound.component.ts @@ -7,10 +7,11 @@ import { ObjectNotFoundComponent } from './objectnotfound.component'; * Themed wrapper for ObjectNotFoundComponent */ @Component({ - selector: 'ds-themed-objnotfound', + selector: 'ds-objnotfound', styleUrls: [], templateUrl: '../../shared/theme-support/themed.component.html', standalone: true, + imports: [ObjectNotFoundComponent], }) export class ThemedObjectNotFoundComponent extends ThemedComponent { protected getComponentName(): string { diff --git a/src/app/my-dspace-page/collection-selector/collection-selector.component.html b/src/app/my-dspace-page/collection-selector/collection-selector.component.html index 6e2a1925c55..a87118fc4e1 100644 --- a/src/app/my-dspace-page/collection-selector/collection-selector.component.html +++ b/src/app/my-dspace-page/collection-selector/collection-selector.component.html @@ -5,7 +5,7 @@
diff --git a/src/app/my-dspace-page/collection-selector/collection-selector.component.spec.ts b/src/app/my-dspace-page/collection-selector/collection-selector.component.spec.ts index 76a61aa3f91..3740e6fa57f 100644 --- a/src/app/my-dspace-page/collection-selector/collection-selector.component.spec.ts +++ b/src/app/my-dspace-page/collection-selector/collection-selector.component.spec.ts @@ -2,7 +2,6 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, - Component, ElementRef, NO_ERRORS_SCHEMA, } from '@angular/core'; @@ -129,14 +128,13 @@ describe('CollectionSelectorComponent', () => { }, }), CollectionSelectorComponent, - // CollectionDropdownComponent, + CollectionDropdownComponent, ], providers: [ { provide: CollectionDataService, useValue: collectionDataServiceMock }, { provide: ElementRef, useClass: MockElementRef }, { provide: NgbActiveModal, useValue: modal }, { provide: ActivatedRoute, useValue: {} }, - { provide: CollectionDropdownComponent, useClass: CollectionDropdownStubComponent }, ChangeDetectorRef, ], schemas: [NO_ERRORS_SCHEMA], @@ -153,7 +151,7 @@ describe('CollectionSelectorComponent', () => { scheduler = getTestScheduler(); fixture = TestBed.overrideComponent(CollectionSelectorComponent, { set: { - template: '', + template: '', }, }).createComponent(CollectionSelectorComponent); component = fixture.componentInstance; @@ -180,19 +178,3 @@ describe('CollectionSelectorComponent', () => { expect((component as any).activeModal.close).toHaveBeenCalled(); }); }); - -@Component({ - selector: 'ds-collection-dropdown', - template: ` - `, - standalone: true, -}) -export class CollectionDropdownStubComponent { - test() { - return 'test'; - } -} diff --git a/src/app/my-dspace-page/my-dspace-new-submission/my-dspace-new-submission-dropdown/my-dspace-new-submission-dropdown.component.ts b/src/app/my-dspace-page/my-dspace-new-submission/my-dspace-new-submission-dropdown/my-dspace-new-submission-dropdown.component.ts index c816a3aa2c3..8604c3322ce 100644 --- a/src/app/my-dspace-page/my-dspace-new-submission/my-dspace-new-submission-dropdown/my-dspace-new-submission-dropdown.component.ts +++ b/src/app/my-dspace-page/my-dspace-new-submission/my-dspace-new-submission-dropdown/my-dspace-new-submission-dropdown.component.ts @@ -28,7 +28,7 @@ import { FindListOptions } from '../../../core/data/find-list-options.model'; import { PaginatedList } from '../../../core/data/paginated-list.model'; import { RemoteData } from '../../../core/data/remote-data'; import { ItemType } from '../../../core/shared/item-relationships/item-type.model'; -import { CreateItemParentSelectorComponent } from '../../../shared/dso-selector/modal-wrappers/create-item-parent-selector/create-item-parent-selector.component'; +import { ThemedCreateItemParentSelectorComponent } from '../../../shared/dso-selector/modal-wrappers/create-item-parent-selector/themed-create-item-parent-selector.component'; import { hasValue } from '../../../shared/empty.util'; import { EntityDropdownComponent } from '../../../shared/entity-dropdown/entity-dropdown.component'; import { BrowserOnlyPipe } from '../../../shared/utils/browser-only.pipe'; @@ -124,7 +124,7 @@ export class MyDSpaceNewSubmissionDropdownComponent implements OnInit, OnDestroy * select a collection. */ openDialog(entity: ItemType) { - const modalRef = this.modalService.open(CreateItemParentSelectorComponent); + const modalRef = this.modalService.open(ThemedCreateItemParentSelectorComponent); modalRef.componentInstance.entityType = entity.label; } diff --git a/src/app/my-dspace-page/my-dspace-page.component.html b/src/app/my-dspace-page/my-dspace-page.component.html index cfae8e07a86..9e5cadc12b1 100644 --- a/src/app/my-dspace-page/my-dspace-page.component.html +++ b/src/app/my-dspace-page/my-dspace-page.component.html @@ -4,9 +4,9 @@
- +> diff --git a/src/app/my-dspace-page/my-dspace-page.component.ts b/src/app/my-dspace-page/my-dspace-page.component.ts index dceb1c31d35..0607b27fef5 100644 --- a/src/app/my-dspace-page/my-dspace-page.component.ts +++ b/src/app/my-dspace-page/my-dspace-page.component.ts @@ -34,7 +34,7 @@ export const MYDSPACE_ROUTE = '/mydspace'; * This component represents the whole mydspace page */ @Component({ - selector: 'ds-my-dspace-page', + selector: 'ds-base-my-dspace-page', styleUrls: ['./my-dspace-page.component.scss'], templateUrl: './my-dspace-page.component.html', changeDetection: ChangeDetectionStrategy.OnPush, diff --git a/src/app/my-dspace-page/themed-my-dspace-page.component.ts b/src/app/my-dspace-page/themed-my-dspace-page.component.ts index 1198360fbd3..d6979b39569 100644 --- a/src/app/my-dspace-page/themed-my-dspace-page.component.ts +++ b/src/app/my-dspace-page/themed-my-dspace-page.component.ts @@ -7,10 +7,11 @@ import { MyDSpacePageComponent } from './my-dspace-page.component'; * Themed wrapper for MyDSpacePageComponent */ @Component({ - selector: 'ds-themed-my-dspace-page', + selector: 'ds-my-dspace-page', styleUrls: [], templateUrl: './../shared/theme-support/themed.component.html', standalone: true, + imports: [MyDSpacePageComponent], }) export class ThemedMyDSpacePageComponent extends ThemedComponent { diff --git a/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.ts b/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.ts index 1ddc5198698..92da978af7d 100644 --- a/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.ts +++ b/src/app/navbar/expandable-navbar-section/expandable-navbar-section.component.ts @@ -26,7 +26,7 @@ import { NavbarSectionComponent } from '../navbar-section/navbar-section.compone * Represents an expandable section in the navbar */ @Component({ - selector: 'ds-expandable-navbar-section', + selector: 'ds-base-expandable-navbar-section', templateUrl: './expandable-navbar-section.component.html', styleUrls: ['./expandable-navbar-section.component.scss'], animations: [slide], diff --git a/src/app/navbar/expandable-navbar-section/themed-expandable-navbar-section.component.ts b/src/app/navbar/expandable-navbar-section/themed-expandable-navbar-section.component.ts index 2345ef7ab3d..7b0efb81231 100644 --- a/src/app/navbar/expandable-navbar-section/themed-expandable-navbar-section.component.ts +++ b/src/app/navbar/expandable-navbar-section/themed-expandable-navbar-section.component.ts @@ -7,10 +7,11 @@ import { ExpandableNavbarSectionComponent } from './expandable-navbar-section.co * Themed wrapper for ExpandableNavbarSectionComponent */ @Component({ - selector: 'ds-themed-expandable-navbar-section', + selector: 'ds-expandable-navbar-section', styleUrls: [], templateUrl: '../../shared/theme-support/themed.component.html', standalone: true, + imports: [ExpandableNavbarSectionComponent], }) export class ThemedExpandableNavbarSectionComponent extends ThemedComponent { protected getComponentName(): string { diff --git a/src/app/navbar/navbar.component.html b/src/app/navbar/navbar.component.html index 63938617f57..90cf07caa42 100644 --- a/src/app/navbar/navbar.component.html +++ b/src/app/navbar/navbar.component.html @@ -7,7 +7,7 @@
- + - {{ (labelPrefix + label + '.select' | translate) }}

[context]="context" (deselectObject)="deselectEntity()" (selectObject)="selectEntity($event)"> - +
diff --git a/src/app/notifications/qa/project-entry-import-modal/project-entry-import-modal.component.spec.ts b/src/app/notifications/qa/project-entry-import-modal/project-entry-import-modal.component.spec.ts index 8b098a89ee8..dada55a4234 100644 --- a/src/app/notifications/qa/project-entry-import-modal/project-entry-import-modal.component.spec.ts +++ b/src/app/notifications/qa/project-entry-import-modal/project-entry-import-modal.component.spec.ts @@ -19,7 +19,7 @@ import { Item } from '../../../core/shared/item.model'; import { PageInfo } from '../../../core/shared/page-info.model'; import { SearchService } from '../../../core/shared/search/search.service'; import { AlertComponent } from '../../../shared/alert/alert.component'; -import { LoadingComponent } from '../../../shared/loading/loading.component'; +import { ThemedLoadingComponent } from '../../../shared/loading/themed-loading.component'; import { ItemMockPid10, NotificationsMockDspaceObject, @@ -106,7 +106,7 @@ describe('ProjectEntryImportModalComponent test suite', () => { .overrideComponent(ProjectEntryImportModalComponent, { remove: { imports: [ - LoadingComponent, + ThemedLoadingComponent, ThemedSearchResultsComponent, AlertComponent, ], diff --git a/src/app/notifications/qa/project-entry-import-modal/project-entry-import-modal.component.ts b/src/app/notifications/qa/project-entry-import-modal/project-entry-import-modal.component.ts index 08e89fec05c..4b31e2316a9 100644 --- a/src/app/notifications/qa/project-entry-import-modal/project-entry-import-modal.component.ts +++ b/src/app/notifications/qa/project-entry-import-modal/project-entry-import-modal.component.ts @@ -33,7 +33,7 @@ import { hasValue, isNotEmpty, } from '../../../shared/empty.util'; -import { LoadingComponent } from '../../../shared/loading/loading.component'; +import { ThemedLoadingComponent } from '../../../shared/loading/themed-loading.component'; import { CollectionElementLinkType } from '../../../shared/object-collection/collection-element-link.type'; import { ListableObject } from '../../../shared/object-collection/shared/listable-object.model'; import { SelectableListService } from '../../../shared/object-list/selectable-list/selectable-list.service'; @@ -104,7 +104,7 @@ export interface QualityAssuranceEventData { styleUrls: ['./project-entry-import-modal.component.scss'], templateUrl: './project-entry-import-modal.component.html', standalone: true, - imports: [RouterLink, NgIf, FormsModule, LoadingComponent, ThemedSearchResultsComponent, AlertComponent, AsyncPipe, TranslateModule], + imports: [RouterLink, NgIf, FormsModule, ThemedLoadingComponent, ThemedSearchResultsComponent, AlertComponent, AsyncPipe, TranslateModule], }) /** * Component to display a modal window for linking a project to an Quality Assurance event diff --git a/src/app/notifications/qa/source/quality-assurance-source.component.spec.ts b/src/app/notifications/qa/source/quality-assurance-source.component.spec.ts index 220bf3f74ab..36309fd937a 100644 --- a/src/app/notifications/qa/source/quality-assurance-source.component.spec.ts +++ b/src/app/notifications/qa/source/quality-assurance-source.component.spec.ts @@ -16,7 +16,7 @@ import { of as observableOf } from 'rxjs'; import { PaginationService } from '../../../core/pagination/pagination.service'; import { AlertComponent } from '../../../shared/alert/alert.component'; -import { LoadingComponent } from '../../../shared/loading/loading.component'; +import { ThemedLoadingComponent } from '../../../shared/loading/themed-loading.component'; import { getMockNotificationsStateService, qualityAssuranceSourceObjectMoreAbstract, @@ -61,7 +61,7 @@ describe('QualityAssuranceSourceComponent test suite', () => { remove: { imports: [ AlertComponent, - LoadingComponent, + ThemedLoadingComponent, PaginationComponent, ], }, diff --git a/src/app/notifications/qa/source/quality-assurance-source.component.ts b/src/app/notifications/qa/source/quality-assurance-source.component.ts index b43fd597d5a..a918b8c3b66 100644 --- a/src/app/notifications/qa/source/quality-assurance-source.component.ts +++ b/src/app/notifications/qa/source/quality-assurance-source.component.ts @@ -25,7 +25,7 @@ import { PaginationService } from '../../../core/pagination/pagination.service'; import { QualityAssuranceSourcePageParams } from '../../../quality-assurance-notifications-pages/quality-assurance-source-page-component/quality-assurance-source-page-resolver.service'; import { AlertComponent } from '../../../shared/alert/alert.component'; import { hasValue } from '../../../shared/empty.util'; -import { LoadingComponent } from '../../../shared/loading/loading.component'; +import { ThemedLoadingComponent } from '../../../shared/loading/themed-loading.component'; import { PaginationComponent } from '../../../shared/pagination/pagination.component'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; import { NotificationsStateService } from '../../notifications-state.service'; @@ -38,7 +38,7 @@ import { NotificationsStateService } from '../../notifications-state.service'; templateUrl: './quality-assurance-source.component.html', styleUrls: ['./quality-assurance-source.component.scss'], standalone: true, - imports: [AlertComponent, NgIf, LoadingComponent, PaginationComponent, NgFor, RouterLink, AsyncPipe, TranslateModule, DatePipe], + imports: [AlertComponent, NgIf, ThemedLoadingComponent, PaginationComponent, NgFor, RouterLink, AsyncPipe, TranslateModule, DatePipe], }) export class QualityAssuranceSourceComponent implements OnInit { diff --git a/src/app/notifications/qa/topics/quality-assurance-topics.component.spec.ts b/src/app/notifications/qa/topics/quality-assurance-topics.component.spec.ts index a08e970a29e..c764128e467 100644 --- a/src/app/notifications/qa/topics/quality-assurance-topics.component.spec.ts +++ b/src/app/notifications/qa/topics/quality-assurance-topics.component.spec.ts @@ -18,7 +18,7 @@ import { ItemDataService } from 'src/app/core/data/item-data.service'; import { PaginationService } from '../../../core/pagination/pagination.service'; import { AlertComponent } from '../../../shared/alert/alert.component'; -import { LoadingComponent } from '../../../shared/loading/loading.component'; +import { ThemedLoadingComponent } from '../../../shared/loading/themed-loading.component'; import { getMockNotificationsStateService, qualityAssuranceTopicObjectMoreAbstract, @@ -69,7 +69,7 @@ describe('QualityAssuranceTopicsComponent test suite', () => { remove: { imports: [ AlertComponent, - LoadingComponent, + ThemedLoadingComponent, PaginationComponent, ], }, diff --git a/src/app/notifications/qa/topics/quality-assurance-topics.component.ts b/src/app/notifications/qa/topics/quality-assurance-topics.component.ts index dbf2e472014..0fcaa93805c 100644 --- a/src/app/notifications/qa/topics/quality-assurance-topics.component.ts +++ b/src/app/notifications/qa/topics/quality-assurance-topics.component.ts @@ -41,7 +41,7 @@ import { getItemPageRoute } from '../../../item-page/item-page-routing-paths'; import { QualityAssuranceTopicsPageParams } from '../../../quality-assurance-notifications-pages/quality-assurance-topics-page/quality-assurance-topics-page-resolver.service'; import { AlertComponent } from '../../../shared/alert/alert.component'; import { hasValue } from '../../../shared/empty.util'; -import { LoadingComponent } from '../../../shared/loading/loading.component'; +import { ThemedLoadingComponent } from '../../../shared/loading/themed-loading.component'; import { PaginationComponent } from '../../../shared/pagination/pagination.component'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; import { NotificationsStateService } from '../../notifications-state.service'; @@ -54,7 +54,7 @@ import { NotificationsStateService } from '../../notifications-state.service'; templateUrl: './quality-assurance-topics.component.html', styleUrls: ['./quality-assurance-topics.component.scss'], standalone: true, - imports: [AlertComponent, NgIf, LoadingComponent, PaginationComponent, NgFor, RouterLink, AsyncPipe, TranslateModule, DatePipe], + imports: [AlertComponent, NgIf, ThemedLoadingComponent, PaginationComponent, NgFor, RouterLink, AsyncPipe, TranslateModule, DatePipe], }) export class QualityAssuranceTopicsComponent implements OnInit, OnDestroy, AfterViewInit { /** diff --git a/src/app/notifications/suggestion-actions/suggestion-actions.component.ts b/src/app/notifications/suggestion-actions/suggestion-actions.component.ts index 666d22d57ff..02eaf103219 100644 --- a/src/app/notifications/suggestion-actions/suggestion-actions.component.ts +++ b/src/app/notifications/suggestion-actions/suggestion-actions.component.ts @@ -15,7 +15,7 @@ import { take } from 'rxjs/operators'; import { Suggestion } from '../../core/notifications/models/suggestion.model'; import { Collection } from '../../core/shared/collection.model'; import { ItemType } from '../../core/shared/item-relationships/item-type.model'; -import { CreateItemParentSelectorComponent } from '../../shared/dso-selector/modal-wrappers/create-item-parent-selector/create-item-parent-selector.component'; +import { ThemedCreateItemParentSelectorComponent } from '../../shared/dso-selector/modal-wrappers/create-item-parent-selector/themed-create-item-parent-selector.component'; import { EntityDropdownComponent } from '../../shared/entity-dropdown/entity-dropdown.component'; import { SuggestionApproveAndImport } from '../suggestion-list-element/suggestion-approve-and-import'; @@ -69,7 +69,7 @@ export class SuggestionActionsComponent { */ openDialog(entity: ItemType) { - const modalRef = this.modalService.open(CreateItemParentSelectorComponent); + const modalRef = this.modalService.open(ThemedCreateItemParentSelectorComponent); modalRef.componentInstance.emitOnly = true; modalRef.componentInstance.entityType = entity.label; diff --git a/src/app/notifications/suggestion-targets/publication-claim/publication-claim.component.ts b/src/app/notifications/suggestion-targets/publication-claim/publication-claim.component.ts index 95788bf4bad..136466b4acd 100644 --- a/src/app/notifications/suggestion-targets/publication-claim/publication-claim.component.ts +++ b/src/app/notifications/suggestion-targets/publication-claim/publication-claim.component.ts @@ -25,7 +25,7 @@ import { import { SuggestionTarget } from '../../../core/notifications/models/suggestion-target.model'; import { PaginationService } from '../../../core/pagination/pagination.service'; import { hasValue } from '../../../shared/empty.util'; -import { LoadingComponent } from '../../../shared/loading/loading.component'; +import { ThemedLoadingComponent } from '../../../shared/loading/themed-loading.component'; import { PaginationComponent } from '../../../shared/pagination/pagination.component'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; import { getSuggestionPageRoute } from '../../../suggestions-page/suggestions-page-routing-paths'; @@ -40,7 +40,7 @@ import { SuggestionTargetsStateService } from '../suggestion-targets.state.servi templateUrl: './publication-claim.component.html', styleUrls: ['./publication-claim.component.scss'], imports: [ - LoadingComponent, + ThemedLoadingComponent, AsyncPipe, TranslateModule, PaginationComponent, diff --git a/src/app/page-error/page-error.component.ts b/src/app/page-error/page-error.component.ts index f53e4ed2b4f..5a8f87ed591 100644 --- a/src/app/page-error/page-error.component.ts +++ b/src/app/page-error/page-error.component.ts @@ -9,7 +9,7 @@ import { TranslateModule } from '@ngx-translate/core'; * This component representing the `PageError` DSpace page. */ @Component({ - selector: 'ds-page-error', + selector: 'ds-base-page-error', styleUrls: ['./page-error.component.scss'], templateUrl: './page-error.component.html', changeDetection: ChangeDetectionStrategy.Default, diff --git a/src/app/page-error/themed-page-error.component.ts b/src/app/page-error/themed-page-error.component.ts index 2e0e94d898f..a3ee38fd601 100644 --- a/src/app/page-error/themed-page-error.component.ts +++ b/src/app/page-error/themed-page-error.component.ts @@ -7,10 +7,11 @@ import { PageErrorComponent } from './page-error.component'; * Themed wrapper for PageErrorComponent */ @Component({ - selector: 'ds-themed-page-error', + selector: 'ds-page-error', styleUrls: [], templateUrl: '../shared/theme-support/themed.component.html', standalone: true, + imports: [PageErrorComponent], }) export class ThemedPageErrorComponent extends ThemedComponent { diff --git a/src/app/page-internal-server-error/page-internal-server-error.component.ts b/src/app/page-internal-server-error/page-internal-server-error.component.ts index 72d424fd20a..c51757c4e1f 100644 --- a/src/app/page-internal-server-error/page-internal-server-error.component.ts +++ b/src/app/page-internal-server-error/page-internal-server-error.component.ts @@ -10,7 +10,7 @@ import { ServerResponseService } from '../core/services/server-response.service' * This component representing the `PageInternalServer` DSpace page. */ @Component({ - selector: 'ds-page-internal-server-error', + selector: 'ds-base-page-internal-server-error', styleUrls: ['./page-internal-server-error.component.scss'], templateUrl: './page-internal-server-error.component.html', changeDetection: ChangeDetectionStrategy.Default, diff --git a/src/app/page-internal-server-error/themed-page-internal-server-error.component.ts b/src/app/page-internal-server-error/themed-page-internal-server-error.component.ts index 41be907e19c..01146b2a888 100644 --- a/src/app/page-internal-server-error/themed-page-internal-server-error.component.ts +++ b/src/app/page-internal-server-error/themed-page-internal-server-error.component.ts @@ -7,10 +7,11 @@ import { PageInternalServerErrorComponent } from './page-internal-server-error.c * Themed wrapper for PageInternalServerErrorComponent */ @Component({ - selector: 'ds-themed-page-internal-server-error', + selector: 'ds-page-internal-server-error', styleUrls: [], templateUrl: '../shared/theme-support/themed.component.html', standalone: true, + imports: [PageInternalServerErrorComponent], }) export class ThemedPageInternalServerErrorComponent extends ThemedComponent { diff --git a/src/app/pagenotfound/pagenotfound.component.ts b/src/app/pagenotfound/pagenotfound.component.ts index e28f7992b2d..8fd738c8821 100644 --- a/src/app/pagenotfound/pagenotfound.component.ts +++ b/src/app/pagenotfound/pagenotfound.component.ts @@ -13,7 +13,7 @@ import { ServerResponseService } from '../core/services/server-response.service' * This component representing the `PageNotFound` DSpace page. */ @Component({ - selector: 'ds-pagenotfound', + selector: 'ds-base-pagenotfound', styleUrls: ['./pagenotfound.component.scss'], templateUrl: './pagenotfound.component.html', changeDetection: ChangeDetectionStrategy.Default, diff --git a/src/app/pagenotfound/themed-pagenotfound.component.ts b/src/app/pagenotfound/themed-pagenotfound.component.ts index 114ad27f813..d7308908ceb 100644 --- a/src/app/pagenotfound/themed-pagenotfound.component.ts +++ b/src/app/pagenotfound/themed-pagenotfound.component.ts @@ -7,10 +7,11 @@ import { PageNotFoundComponent } from './pagenotfound.component'; * Themed wrapper for PageNotFoundComponent */ @Component({ - selector: 'ds-themed-pagenotfound', + selector: 'ds-pagenotfound', styleUrls: [], templateUrl: '../shared/theme-support/themed.component.html', standalone: true, + imports: [PageNotFoundComponent], }) export class ThemedPageNotFoundComponent extends ThemedComponent { diff --git a/src/app/process-page/detail/process-detail.component.html b/src/app/process-page/detail/process-detail.component.html index 521aec12c2a..7558939ef36 100644 --- a/src/app/process-page/detail/process-detail.component.html +++ b/src/app/process-page/detail/process-detail.component.html @@ -23,10 +23,10 @@

- + {{getFileName(file)}} ({{(file?.sizeBytes) | dsFileSize }}) - +

@@ -51,8 +51,8 @@

class="btn btn-primary" (click)="showProcessOutputLogs()"> {{ 'process.detail.logs.button' | translate }} - +
{{ (outputLogs$ | async) }}

- + >; + script?: Observable>; /** * The output logs created by this Process * Will be undefined unless the output {@link HALLink} has been resolved. */ @link(PROCESS_OUTPUT_TYPE) - output?: Observable>; + output?: Observable>; /** * The files created by this Process * Will be undefined unless the output {@link HALLink} has been resolved. */ @link(BITSTREAM, true) - files?: Observable>>; + files?: Observable>>; /** * The filetypes present in this Process * Will be undefined unless the output {@link HALLink} has been resolved. */ @link(FILETYPES) - filetypes?: Observable>; + filetypes?: Observable>; } diff --git a/src/app/process-page/scripts/script.model.ts b/src/app/process-page/scripts/script.model.ts index 7907695b100..3cd934336af 100644 --- a/src/app/process-page/scripts/script.model.ts +++ b/src/app/process-page/scripts/script.model.ts @@ -23,37 +23,37 @@ export class Script implements CacheableObject { */ @excludeFromEquals @autoserialize - type: ResourceType; + type: ResourceType; /** * The identifier of this script */ @autoserialize - id: string; + id: string; /** * The name of this script */ @autoserialize - name: string; + name: string; /** * A short description of this script */ @autoserialize - description: string; + description: string; /** * The available parameters for this script */ @autoserialize - parameters: ScriptParameter[]; + parameters: ScriptParameter[]; /** * The {@link HALLink}s for this Script */ @deserialize - _links: { + _links: { self: HALLink, }; } diff --git a/src/app/profile-page/profile-page-security-form/profile-page-security-form.component.ts b/src/app/profile-page/profile-page-security-form/profile-page-security-form.component.ts index 929ff280c52..7c0bf9ea2de 100644 --- a/src/app/profile-page/profile-page-security-form/profile-page-security-form.component.ts +++ b/src/app/profile-page/profile-page-security-form/profile-page-security-form.component.ts @@ -86,13 +86,13 @@ export class ProfilePageSecurityFormComponent implements OnInit { * Indicates whether the "checkPasswordEmpty" needs to be added or not */ @Input() - passwordCanBeEmpty = true; + passwordCanBeEmpty = true; /** * Prefix for the form's label messages of this component */ @Input() - FORM_PREFIX: string; + FORM_PREFIX: string; private subs: Subscription[] = []; diff --git a/src/app/profile-page/profile-page.component.ts b/src/app/profile-page/profile-page.component.ts index e62faacc979..bee4c2d0233 100644 --- a/src/app/profile-page/profile-page.component.ts +++ b/src/app/profile-page/profile-page.component.ts @@ -52,7 +52,7 @@ import { ProfilePageResearcherFormComponent } from './profile-page-researcher-fo import { ProfilePageSecurityFormComponent } from './profile-page-security-form/profile-page-security-form.component'; @Component({ - selector: 'ds-profile-page', + selector: 'ds-base-profile-page', styleUrls: ['./profile-page.component.scss'], templateUrl: './profile-page.component.html', imports: [ diff --git a/src/app/profile-page/themed-profile-page.component.ts b/src/app/profile-page/themed-profile-page.component.ts index 8288c7b8dc3..83149ff9f12 100644 --- a/src/app/profile-page/themed-profile-page.component.ts +++ b/src/app/profile-page/themed-profile-page.component.ts @@ -7,10 +7,11 @@ import { ProfilePageComponent } from './profile-page.component'; * Themed wrapper for ProfilePageComponent */ @Component({ - selector: 'ds-themed-profile-page', + selector: 'ds-profile-page', styleUrls: [], templateUrl: './../shared/theme-support/themed.component.html', standalone: true, + imports: [ProfilePageComponent], }) export class ThemedProfilePageComponent extends ThemedComponent { protected getComponentName(): string { diff --git a/src/app/register-email-form/register-email-form.component.ts b/src/app/register-email-form/register-email-form.component.ts index 25916fd87ee..ac13abb865e 100644 --- a/src/app/register-email-form/register-email-form.component.ts +++ b/src/app/register-email-form/register-email-form.component.ts @@ -63,7 +63,7 @@ export const TYPE_REQUEST_FORGOT = 'forgot'; export const TYPE_REQUEST_REGISTER = 'register'; @Component({ - selector: 'ds-register-email-form', + selector: 'ds-base-register-email-form', templateUrl: './register-email-form.component.html', standalone: true, imports: [NgIf, FormsModule, ReactiveFormsModule, AlertComponent, GoogleRecaptchaComponent, AsyncPipe, TranslateModule], @@ -82,13 +82,13 @@ export class RegisterEmailFormComponent implements OnDestroy, OnInit { * The message prefix */ @Input() - MESSAGE_PREFIX: string; + MESSAGE_PREFIX: string; /** * Type of register request to be done, register new email or forgot password (same endpoint) */ @Input() - typeRequest: string = null; + typeRequest: string = null; public AlertTypeEnum = AlertType; diff --git a/src/app/register-email-form/themed-registry-email-form.component.ts b/src/app/register-email-form/themed-registry-email-form.component.ts index 679e0c9a0f2..8f95d3d707e 100644 --- a/src/app/register-email-form/themed-registry-email-form.component.ts +++ b/src/app/register-email-form/themed-registry-email-form.component.ts @@ -10,10 +10,11 @@ import { RegisterEmailFormComponent } from './register-email-form.component'; * Themed wrapper for {@link RegisterEmailFormComponent} */ @Component({ - selector: 'ds-themed-register-email-form', + selector: 'ds-register-email-form', styleUrls: [], templateUrl: '../shared/theme-support/themed.component.html', standalone: true, + imports: [RegisterEmailFormComponent], }) export class ThemedRegisterEmailFormComponent extends ThemedComponent { diff --git a/src/app/register-page/create-profile/create-profile.component.ts b/src/app/register-page/create-profile/create-profile.component.ts index 21e88edfcca..7e88c5a1c01 100644 --- a/src/app/register-page/create-profile/create-profile.component.ts +++ b/src/app/register-page/create-profile/create-profile.component.ts @@ -50,7 +50,7 @@ import { NotificationsService } from '../../shared/notifications/notifications.s * Component that renders the create profile page to be used by a user registering through a token */ @Component({ - selector: 'ds-create-profile', + selector: 'ds-base-create-profile', styleUrls: ['./create-profile.component.scss'], templateUrl: './create-profile.component.html', imports: [ diff --git a/src/app/register-page/create-profile/themed-create-profile.component.ts b/src/app/register-page/create-profile/themed-create-profile.component.ts index cf5d6d2def6..54f12a9d163 100644 --- a/src/app/register-page/create-profile/themed-create-profile.component.ts +++ b/src/app/register-page/create-profile/themed-create-profile.component.ts @@ -7,10 +7,11 @@ import { CreateProfileComponent } from './create-profile.component'; * Themed wrapper for CreateProfileComponent */ @Component({ - selector: 'ds-themed-create-profile', + selector: 'ds-create-profile', styleUrls: [], templateUrl: './../../shared/theme-support/themed.component.html', standalone: true, + imports: [CreateProfileComponent], }) export class ThemedCreateProfileComponent extends ThemedComponent { protected getComponentName(): string { diff --git a/src/app/register-page/register-email/register-email.component.html b/src/app/register-page/register-email/register-email.component.html index 6a87a4e9e08..1829bb2914c 100644 --- a/src/app/register-page/register-email/register-email.component.html +++ b/src/app/register-page/register-email/register-email.component.html @@ -1,3 +1,3 @@ - - + diff --git a/src/app/register-page/register-email/register-email.component.spec.ts b/src/app/register-page/register-email/register-email.component.spec.ts index 8696c2fed51..3694c6088ad 100644 --- a/src/app/register-page/register-email/register-email.component.spec.ts +++ b/src/app/register-page/register-email/register-email.component.spec.ts @@ -8,7 +8,6 @@ import { import { ReactiveFormsModule } from '@angular/forms'; import { TranslateModule } from '@ngx-translate/core'; -import { RegisterEmailFormComponent } from '../../register-email-form/register-email-form.component'; import { ThemedRegisterEmailFormComponent } from '../../register-email-form/themed-registry-email-form.component'; import { RegisterEmailComponent } from './register-email.component'; @@ -24,7 +23,7 @@ describe('RegisterEmailComponent', () => { }) .overrideComponent(RegisterEmailComponent, { remove: { - imports: [RegisterEmailFormComponent, ThemedRegisterEmailFormComponent], + imports: [ThemedRegisterEmailFormComponent], }, }) .compileComponents(); diff --git a/src/app/register-page/register-email/register-email.component.ts b/src/app/register-page/register-email/register-email.component.ts index 6164cb30d27..130a2c85187 100644 --- a/src/app/register-page/register-email/register-email.component.ts +++ b/src/app/register-page/register-email/register-email.component.ts @@ -1,17 +1,14 @@ import { Component } from '@angular/core'; import { ThemedRegisterEmailFormComponent } from 'src/app/register-email-form/themed-registry-email-form.component'; -import { - RegisterEmailFormComponent, - TYPE_REQUEST_REGISTER, -} from '../../register-email-form/register-email-form.component'; +import { TYPE_REQUEST_REGISTER } from '../../register-email-form/register-email-form.component'; @Component({ - selector: 'ds-register-email', + selector: 'ds-base-register-email', styleUrls: ['./register-email.component.scss'], templateUrl: './register-email.component.html', imports: [ - RegisterEmailFormComponent, ThemedRegisterEmailFormComponent, + ThemedRegisterEmailFormComponent, ], standalone: true, }) diff --git a/src/app/register-page/register-email/themed-register-email.component.ts b/src/app/register-page/register-email/themed-register-email.component.ts index 987191d2184..3f557f564ca 100644 --- a/src/app/register-page/register-email/themed-register-email.component.ts +++ b/src/app/register-page/register-email/themed-register-email.component.ts @@ -7,10 +7,11 @@ import { RegisterEmailComponent } from './register-email.component'; * Themed wrapper for RegisterEmailComponent */ @Component({ - selector: 'ds-themed-register-email', + selector: 'ds-register-email', styleUrls: [], templateUrl: '../../shared/theme-support/themed.component.html', standalone: true, + imports: [RegisterEmailComponent], }) export class ThemedRegisterEmailComponent extends ThemedComponent { protected getComponentName(): string { diff --git a/src/app/request-copy/deny-request-copy/deny-request-copy.component.html b/src/app/request-copy/deny-request-copy/deny-request-copy.component.html index e513212f94f..b00bc079dd5 100644 --- a/src/app/request-copy/deny-request-copy/deny-request-copy.component.html +++ b/src/app/request-copy/deny-request-copy/deny-request-copy.component.html @@ -3,7 +3,7 @@

{{'deny-request-copy.header' | translate}}

{{'deny-request-copy.intro' | translate}}

- +
- +
diff --git a/src/app/request-copy/deny-request-copy/deny-request-copy.component.ts b/src/app/request-copy/deny-request-copy/deny-request-copy.component.ts index e2cc5293ccf..7d87755f9ec 100644 --- a/src/app/request-copy/deny-request-copy/deny-request-copy.component.ts +++ b/src/app/request-copy/deny-request-copy/deny-request-copy.component.ts @@ -44,7 +44,7 @@ import { RequestCopyEmail } from '../email-request-copy/request-copy-email.model import { ThemedEmailRequestCopyComponent } from '../email-request-copy/themed-email-request-copy.component'; @Component({ - selector: 'ds-deny-request-copy', + selector: 'ds-base-deny-request-copy', styleUrls: ['./deny-request-copy.component.scss'], templateUrl: './deny-request-copy.component.html', standalone: true, diff --git a/src/app/request-copy/deny-request-copy/themed-deny-request-copy.component.ts b/src/app/request-copy/deny-request-copy/themed-deny-request-copy.component.ts index 45141d10dd4..aebcdd2b063 100644 --- a/src/app/request-copy/deny-request-copy/themed-deny-request-copy.component.ts +++ b/src/app/request-copy/deny-request-copy/themed-deny-request-copy.component.ts @@ -7,10 +7,11 @@ import { DenyRequestCopyComponent } from './deny-request-copy.component'; * Themed wrapper for deny-request-copy.component */ @Component({ - selector: 'ds-themed-deny-request-copy', + selector: 'ds-deny-request-copy', styleUrls: [], templateUrl: './../../shared/theme-support/themed.component.html', standalone: true, + imports: [DenyRequestCopyComponent], }) export class ThemedDenyRequestCopyComponent extends ThemedComponent { protected getComponentName(): string { diff --git a/src/app/request-copy/email-request-copy/email-request-copy.component.ts b/src/app/request-copy/email-request-copy/email-request-copy.component.ts index 3f44a6ed1fc..66a9e0b17f2 100644 --- a/src/app/request-copy/email-request-copy/email-request-copy.component.ts +++ b/src/app/request-copy/email-request-copy/email-request-copy.component.ts @@ -16,7 +16,7 @@ import { RequestCopyEmail } from './request-copy-email.model'; @Component({ - selector: 'ds-email-request-copy', + selector: 'ds-base-email-request-copy', styleUrls: ['./email-request-copy.component.scss'], templateUrl: './email-request-copy.component.html', standalone: true, diff --git a/src/app/request-copy/email-request-copy/themed-email-request-copy.component.ts b/src/app/request-copy/email-request-copy/themed-email-request-copy.component.ts index 2512485f81c..f641045ef24 100644 --- a/src/app/request-copy/email-request-copy/themed-email-request-copy.component.ts +++ b/src/app/request-copy/email-request-copy/themed-email-request-copy.component.ts @@ -13,10 +13,11 @@ import { RequestCopyEmail } from './request-copy-email.model'; * Themed wrapper for email-request-copy.component */ @Component({ - selector: 'ds-themed-email-request-copy', + selector: 'ds-email-request-copy', styleUrls: [], templateUrl: './../../shared/theme-support/themed.component.html', standalone: true, + imports: [EmailRequestCopyComponent], }) export class ThemedEmailRequestCopyComponent extends ThemedComponent { /** diff --git a/src/app/request-copy/grant-deny-request-copy/grant-deny-request-copy.component.html b/src/app/request-copy/grant-deny-request-copy/grant-deny-request-copy.component.html index 4837e0dcda1..37b275d8f84 100644 --- a/src/app/request-copy/grant-deny-request-copy/grant-deny-request-copy.component.html +++ b/src/app/request-copy/grant-deny-request-copy/grant-deny-request-copy.component.html @@ -26,5 +26,5 @@

{{'grant-deny-request-copy.header' | translate}}

- +
diff --git a/src/app/request-copy/grant-request-copy/grant-request-copy.component.html b/src/app/request-copy/grant-request-copy/grant-request-copy.component.html index 179206566ed..d2c2cfc3c8e 100644 --- a/src/app/request-copy/grant-request-copy/grant-request-copy.component.html +++ b/src/app/request-copy/grant-request-copy/grant-request-copy.component.html @@ -3,7 +3,7 @@

{{'grant-request-copy.header' | translate}}

{{'grant-request-copy.intro' | translate}}

- +

{{ 'grant-deny-request-copy.email.permissions.info' | translate }}

@@ -11,7 +11,7 @@

{{'grant-request-copy.header' | translate}}

-
+
- +
diff --git a/src/app/request-copy/grant-request-copy/grant-request-copy.component.ts b/src/app/request-copy/grant-request-copy/grant-request-copy.component.ts index e2e2fe88432..b14f15f34b8 100644 --- a/src/app/request-copy/grant-request-copy/grant-request-copy.component.ts +++ b/src/app/request-copy/grant-request-copy/grant-request-copy.component.ts @@ -37,7 +37,7 @@ import { RequestCopyEmail } from '../email-request-copy/request-copy-email.model import { ThemedEmailRequestCopyComponent } from '../email-request-copy/themed-email-request-copy.component'; @Component({ - selector: 'ds-grant-request-copy', + selector: 'ds-base-grant-request-copy', styleUrls: ['./grant-request-copy.component.scss'], templateUrl: './grant-request-copy.component.html', standalone: true, diff --git a/src/app/request-copy/grant-request-copy/themed-grant-request-copy.component.ts b/src/app/request-copy/grant-request-copy/themed-grant-request-copy.component.ts index 7c6f9f61a6e..654f7588bb9 100644 --- a/src/app/request-copy/grant-request-copy/themed-grant-request-copy.component.ts +++ b/src/app/request-copy/grant-request-copy/themed-grant-request-copy.component.ts @@ -7,10 +7,11 @@ import { GrantRequestCopyComponent } from './grant-request-copy.component'; * Themed wrapper for grant-request-copy.component */ @Component({ - selector: 'ds-themed-grant-request-copy', + selector: 'ds-grant-request-copy', styleUrls: [], templateUrl: './../../shared/theme-support/themed.component.html', standalone: true, + imports: [GrantRequestCopyComponent], }) export class ThemedGrantRequestCopyComponent extends ThemedComponent { diff --git a/src/app/root/root.component.html b/src/app/root/root.component.html index 533efea9d18..b5b753cdb9d 100644 --- a/src/app/root/root.component.html +++ b/src/app/root/root.component.html @@ -2,26 +2,26 @@ {{ 'root.skip-to-content' | translate }} -
- +
- - + +
- +
- +
@@ -29,5 +29,5 @@
- +
diff --git a/src/app/root/root.component.ts b/src/app/root/root.component.ts index d98fd85b0a7..e93a7b5c527 100644 --- a/src/app/root/root.component.ts +++ b/src/app/root/root.component.ts @@ -1,9 +1,11 @@ import { AsyncPipe, + NgClass, NgIf, } from '@angular/common'; import { Component, + Inject, Input, OnInit, } from '@angular/core'; @@ -13,6 +15,7 @@ import { } from '@angular/router'; import { TranslateModule } from '@ngx-translate/core'; import { + BehaviorSubject, combineLatest as combineLatestObservable, Observable, of, @@ -30,6 +33,10 @@ import { environment } from '../../environments/environment'; import { ThemedAdminSidebarComponent } from '../admin/admin-sidebar/themed-admin-sidebar.component'; import { getPageInternalServerErrorRoute } from '../app-routing-paths'; import { ThemedBreadcrumbsComponent } from '../breadcrumbs/themed-breadcrumbs.component'; +import { + NativeWindowRef, + NativeWindowService, +} from '../core/services/window.service'; import { ThemedFooterComponent } from '../footer/themed-footer.component'; import { ThemedHeaderNavbarWrapperComponent } from '../header-nav-wrapper/themed-header-navbar-wrapper.component'; import { slideSidebarPadding } from '../shared/animations/slide'; @@ -42,12 +49,25 @@ import { CSSVariableService } from '../shared/sass-helper/css-variable.service'; import { SystemWideAlertBannerComponent } from '../system-wide-alert/alert-banner/system-wide-alert-banner.component'; @Component({ - selector: 'ds-root', + selector: 'ds-base-root', templateUrl: './root.component.html', styleUrls: ['./root.component.scss'], animations: [slideSidebarPadding], standalone: true, - imports: [TranslateModule, ThemedAdminSidebarComponent, SystemWideAlertBannerComponent, ThemedHeaderNavbarWrapperComponent, ThemedBreadcrumbsComponent, NgIf, ThemedLoadingComponent, RouterOutlet, ThemedFooterComponent, NotificationsBoardComponent, AsyncPipe], + imports: [ + TranslateModule, + ThemedAdminSidebarComponent, + SystemWideAlertBannerComponent, + ThemedHeaderNavbarWrapperComponent, + ThemedBreadcrumbsComponent, + NgIf, + NgClass, + ThemedLoadingComponent, + RouterOutlet, + ThemedFooterComponent, + NotificationsBoardComponent, + AsyncPipe, + ], }) export class RootComponent implements OnInit { theme: Observable = of({} as any); @@ -58,6 +78,8 @@ export class RootComponent implements OnInit { notificationOptions: INotificationBoardOptions; models: any; + browserOsClasses = new BehaviorSubject([]); + /** * Whether or not to show a full screen loader */ @@ -73,11 +95,23 @@ export class RootComponent implements OnInit { private cssService: CSSVariableService, private menuService: MenuService, private windowService: HostWindowService, + @Inject(NativeWindowService) private _window: NativeWindowRef, ) { this.notificationOptions = environment.notifications; } ngOnInit() { + const browserName = this.getBrowserName(); + if (browserName) { + const browserOsClasses = new Array(); + browserOsClasses.push(`browser-${browserName}`); + const osName = this.getOSName(); + if (osName) { + browserOsClasses.push(`browser-${browserName}-${osName}`); + } + this.browserOsClasses.next(browserOsClasses); + } + this.isSidebarVisible$ = this.menuService.isMenuVisibleWithVisibleSections(MenuID.ADMIN); this.expandedSidebarWidth$ = this.cssService.getVariable('--ds-admin-sidebar-total-width').pipe( @@ -108,4 +142,23 @@ export class RootComponent implements OnInit { mainContent.focus(); } } + + getBrowserName(): string { + const userAgent = this._window.nativeWindow.navigator.userAgent; + if (/Firefox/.test(userAgent)) { + return 'firefox'; + } + if (/Safari/.test(userAgent)) { + return 'safari'; + } + return undefined; + } + + getOSName(): string { + const userAgent = this._window.nativeWindow.navigator.userAgent; + if (/Windows/.test(userAgent)) { + return 'windows'; + } + return undefined; + } } diff --git a/src/app/root/themed-root.component.ts b/src/app/root/themed-root.component.ts index b2ea91c75da..fe88efa546d 100644 --- a/src/app/root/themed-root.component.ts +++ b/src/app/root/themed-root.component.ts @@ -7,10 +7,11 @@ import { ThemedComponent } from '../shared/theme-support/themed.component'; import { RootComponent } from './root.component'; @Component({ - selector: 'ds-themed-root', + selector: 'ds-root', styleUrls: [], templateUrl: '../shared/theme-support/themed.component.html', standalone: true, + imports: [RootComponent], }) export class ThemedRootComponent extends ThemedComponent { /** diff --git a/src/app/search-navbar/search-navbar.component.ts b/src/app/search-navbar/search-navbar.component.ts index 006a217d57e..28971a26444 100644 --- a/src/app/search-navbar/search-navbar.component.ts +++ b/src/app/search-navbar/search-navbar.component.ts @@ -20,7 +20,7 @@ import { ClickOutsideDirective } from '../shared/utils/click-outside.directive'; * The search box in the header that expands on focus and collapses on focus out */ @Component({ - selector: 'ds-search-navbar', + selector: 'ds-base-search-navbar', templateUrl: './search-navbar.component.html', styleUrls: ['./search-navbar.component.scss'], animations: [expandSearchInput], diff --git a/src/app/search-navbar/themed-search-navbar.component.ts b/src/app/search-navbar/themed-search-navbar.component.ts index 240b39314b8..82348f79430 100644 --- a/src/app/search-navbar/themed-search-navbar.component.ts +++ b/src/app/search-navbar/themed-search-navbar.component.ts @@ -4,10 +4,11 @@ import { ThemedComponent } from '../shared/theme-support/themed.component'; import { SearchNavbarComponent } from './search-navbar.component'; @Component({ - selector: 'ds-themed-search-navbar', + selector: 'ds-search-navbar', styleUrls: [], templateUrl: '../shared/theme-support/themed.component.html', standalone: true, + imports: [SearchNavbarComponent], }) export class ThemedSearchNavbarComponent extends ThemedComponent { diff --git a/src/app/search-page/configuration-search-page.component.spec.ts b/src/app/search-page/configuration-search-page.component.spec.ts index 417e6598992..f3931a2016f 100644 --- a/src/app/search-page/configuration-search-page.component.spec.ts +++ b/src/app/search-page/configuration-search-page.component.spec.ts @@ -8,23 +8,23 @@ import { waitForAsync, } from '@angular/core/testing'; import { Router } from '@angular/router'; +import { of } from 'rxjs'; import { RouteService } from '../core/services/route.service'; import { SearchConfigurationService } from '../core/shared/search/search-configuration.service'; import { configureSearchComponentTestingModule } from '../shared/search/search.component.spec'; import { ConfigurationSearchPageComponent } from './configuration-search-page.component'; import createSpy = jasmine.createSpy; -import { of } from 'rxjs'; const CONFIGURATION = 'test-configuration'; const QUERY = 'test query'; @Component({ template: ` - - + `, imports: [ ConfigurationSearchPageComponent, diff --git a/src/app/search-page/configuration-search-page.component.ts b/src/app/search-page/configuration-search-page.component.ts index 3b28ed447a0..afbe34d550c 100644 --- a/src/app/search-page/configuration-search-page.component.ts +++ b/src/app/search-page/configuration-search-page.component.ts @@ -34,7 +34,7 @@ import { ViewModeSwitchComponent } from '../shared/view-mode-switch/view-mode-sw * This component renders a search page using a configuration as input. */ @Component({ - selector: 'ds-configuration-search-page', + selector: 'ds-base-configuration-search-page', styleUrls: ['../shared/search/search.component.scss'], templateUrl: '../shared/search/search.component.html', changeDetection: ChangeDetectionStrategy.OnPush, diff --git a/src/app/search-page/search-page.component.html b/src/app/search-page/search-page.component.html index 36ba53a885e..8d310607833 100644 --- a/src/app/search-page/search-page.component.html +++ b/src/app/search-page/search-page.component.html @@ -1 +1 @@ - + diff --git a/src/app/search-page/search-page.component.ts b/src/app/search-page/search-page.component.ts index 272987a795c..817cc6818e1 100644 --- a/src/app/search-page/search-page.component.ts +++ b/src/app/search-page/search-page.component.ts @@ -5,7 +5,7 @@ import { SEARCH_CONFIG_SERVICE } from '../my-dspace-page/my-dspace-configuration import { ThemedSearchComponent } from '../shared/search/themed-search.component'; @Component({ - selector: 'ds-search-page', + selector: 'ds-base-search-page', templateUrl: './search-page.component.html', providers: [ { diff --git a/src/app/search-page/themed-configuration-search-page.component.ts b/src/app/search-page/themed-configuration-search-page.component.ts index 0d39dca4303..cf84c9c9d4a 100644 --- a/src/app/search-page/themed-configuration-search-page.component.ts +++ b/src/app/search-page/themed-configuration-search-page.component.ts @@ -15,58 +15,134 @@ import { ConfigurationSearchPageComponent } from './configuration-search-page.co * Themed wrapper for ConfigurationSearchPageComponent */ @Component({ - selector: 'ds-themed-configuration-search-page', + selector: 'ds-configuration-search-page', templateUrl: '../shared/theme-support/themed.component.html', standalone: true, + imports: [ConfigurationSearchPageComponent], }) export class ThemedConfigurationSearchPageComponent extends ThemedComponent { - - @Input() configurationList: SearchConfigurationOption[] = []; - + /** + * The list of available configuration options + */ + @Input() configurationList: SearchConfigurationOption[]; + + /** + * The current context + * If empty, 'search' is used + */ @Input() context: Context; + /** + * The configuration to use for the search options + * If empty, 'default' is used + */ @Input() configuration: string; + /** + * The actual query for the fixed filter. + * If empty, the query will be determined by the route parameter called 'filter' + */ @Input() fixedFilterQuery: string; + /** + * If this is true, the request will only be sent if there's + * no valid cached version. Defaults to true + */ @Input() useCachedVersionIfAvailable: boolean; + /** + * True when the search component should show results on the current page + */ @Input() inPlaceSearch: boolean; + /** + * The link type of the listed search results + */ @Input() linkType: CollectionElementLinkType; + /** + * The pagination id used in the search + */ @Input() paginationId: string; + /** + * Whether or not the search bar should be visible + */ @Input() searchEnabled: boolean; + /** + * The width of the sidebar (bootstrap columns) + */ @Input() sideBarWidth: number; + /** + * The placeholder of the search form input + */ @Input() searchFormPlaceholder: string; + /** + * A boolean representing if result entries are selectable + */ @Input() selectable: boolean; + /** + * The config option used for selection functionality + */ @Input() selectionConfig: SelectionConfig; + /** + * A boolean representing if show csv export button + */ @Input() showCsvExport: boolean; + /** + * A boolean representing if show search sidebar button + */ @Input() showSidebar: boolean; + /** + * Whether to show the thumbnail preview + */ @Input() showThumbnails: boolean; + /** + * Whether to show the view mode switch + */ @Input() showViewModes: boolean; + /** + * List of available view mode + */ @Input() useUniquePageId: boolean; + /** + * List of available view mode + */ @Input() viewModeList: ViewMode[]; + /** + * Defines whether or not to show the scope selector + */ @Input() showScopeSelector: boolean; + /** + * Whether or not to track search statistics by sending updates to the rest api + */ @Input() trackStatistics: boolean; + /** + * The default value for the search query when none is already defined in the {@link SearchConfigurationService} + */ @Input() query: string; + /** + * The fallback scope when no scope is defined in the url, if this is also undefined no scope will be set + */ @Input() scope: string; + /** + * Hides the scope in the url, this can be useful when you hardcode the scope in another way + */ @Input() hideScopeInUrl: boolean; protected inAndOutputNames: (keyof ConfigurationSearchPageComponent & keyof this)[] = [ diff --git a/src/app/search-page/themed-search-page.component.ts b/src/app/search-page/themed-search-page.component.ts index 30e6e6db11d..649ad8a2466 100644 --- a/src/app/search-page/themed-search-page.component.ts +++ b/src/app/search-page/themed-search-page.component.ts @@ -7,10 +7,11 @@ import { SearchPageComponent } from './search-page.component'; * Themed wrapper for SearchPageComponent */ @Component({ - selector: 'ds-themed-search-page', + selector: 'ds-search-page', styleUrls: [], templateUrl: '../shared/theme-support/themed.component.html', standalone: true, + imports: [SearchPageComponent], }) export class ThemedSearchPageComponent extends ThemedComponent { diff --git a/src/app/shared/auth-nav-menu/auth-nav-menu.component.html b/src/app/shared/auth-nav-menu/auth-nav-menu.component.html index 98749da7b54..74ae8216349 100644 --- a/src/app/shared/auth-nav-menu/auth-nav-menu.component.html +++ b/src/app/shared/auth-nav-menu/auth-nav-menu.component.html @@ -13,8 +13,8 @@
@@ -30,7 +30,7 @@ ngbDropdownToggle>
- +
diff --git a/src/app/shared/auth-nav-menu/auth-nav-menu.component.spec.ts b/src/app/shared/auth-nav-menu/auth-nav-menu.component.spec.ts index a969b6f49bc..539de03b09b 100644 --- a/src/app/shared/auth-nav-menu/auth-nav-menu.component.spec.ts +++ b/src/app/shared/auth-nav-menu/auth-nav-menu.component.spec.ts @@ -267,7 +267,7 @@ describe('AuthNavMenuComponent', () => { component = null; }); it('should render UserMenuComponent component', () => { - const logoutDropdownMenu = deNavMenuItem.query(By.css('ds-themed-user-menu')); + const logoutDropdownMenu = deNavMenuItem.query(By.css('ds-user-menu')); expect(logoutDropdownMenu.nativeElement).toBeDefined(); }); }); diff --git a/src/app/shared/auth-nav-menu/auth-nav-menu.component.ts b/src/app/shared/auth-nav-menu/auth-nav-menu.component.ts index d24b1db8530..16899cf73e8 100644 --- a/src/app/shared/auth-nav-menu/auth-nav-menu.component.ts +++ b/src/app/shared/auth-nav-menu/auth-nav-menu.component.ts @@ -48,19 +48,17 @@ import { } from '../animations/fade'; import { isNotUndefined } from '../empty.util'; import { HostWindowService } from '../host-window.service'; -import { LogInComponent } from '../log-in/log-in.component'; import { ThemedLogInComponent } from '../log-in/themed-log-in.component'; import { BrowserOnlyPipe } from '../utils/browser-only.pipe'; import { ThemedUserMenuComponent } from './user-menu/themed-user-menu.component'; -import { UserMenuComponent } from './user-menu/user-menu.component'; @Component({ - selector: 'ds-auth-nav-menu', + selector: 'ds-base-auth-nav-menu', templateUrl: './auth-nav-menu.component.html', styleUrls: ['./auth-nav-menu.component.scss'], animations: [fadeInOut, fadeOut], standalone: true, - imports: [NgClass, NgIf, NgbDropdownModule, LogInComponent, ThemedLogInComponent, RouterLink, RouterLinkActive, UserMenuComponent, ThemedUserMenuComponent, AsyncPipe, TranslateModule, BrowserOnlyPipe], + imports: [NgClass, NgIf, NgbDropdownModule, ThemedLogInComponent, RouterLink, RouterLinkActive, ThemedUserMenuComponent, AsyncPipe, TranslateModule, BrowserOnlyPipe], }) export class AuthNavMenuComponent implements OnInit { /** diff --git a/src/app/shared/auth-nav-menu/themed-auth-nav-menu.component.ts b/src/app/shared/auth-nav-menu/themed-auth-nav-menu.component.ts index d15a10d9cee..9ed244a929f 100644 --- a/src/app/shared/auth-nav-menu/themed-auth-nav-menu.component.ts +++ b/src/app/shared/auth-nav-menu/themed-auth-nav-menu.component.ts @@ -7,10 +7,11 @@ import { AuthNavMenuComponent } from './auth-nav-menu.component'; * Themed wrapper for {@link AuthNavMenuComponent} */ @Component({ - selector: 'ds-themed-auth-nav-menu', + selector: 'ds-auth-nav-menu', styleUrls: [], templateUrl: '../theme-support/themed.component.html', standalone: true, + imports: [AuthNavMenuComponent], }) export class ThemedAuthNavMenuComponent extends ThemedComponent { protected getComponentName(): string { diff --git a/src/app/shared/auth-nav-menu/user-menu/themed-user-menu.component.ts b/src/app/shared/auth-nav-menu/user-menu/themed-user-menu.component.ts index feb3f90b351..38112cfa7c8 100644 --- a/src/app/shared/auth-nav-menu/user-menu/themed-user-menu.component.ts +++ b/src/app/shared/auth-nav-menu/user-menu/themed-user-menu.component.ts @@ -10,10 +10,11 @@ import { UserMenuComponent } from './user-menu.component'; * This component represents the user nav menu. */ @Component({ - selector: 'ds-themed-user-menu', + selector: 'ds-user-menu', templateUrl: './../../theme-support/themed.component.html', styleUrls: [], standalone: true, + imports: [UserMenuComponent], }) export class ThemedUserMenuComponent extends ThemedComponent{ diff --git a/src/app/shared/auth-nav-menu/user-menu/user-menu.component.html b/src/app/shared/auth-nav-menu/user-menu/user-menu.component.html index a6d4188f923..4c36cc2f24b 100644 --- a/src/app/shared/auth-nav-menu/user-menu/user-menu.component.html +++ b/src/app/shared/auth-nav-menu/user-menu/user-menu.component.html @@ -1,4 +1,4 @@ - + diff --git a/src/app/shared/collection-dropdown/collection-dropdown.component.ts b/src/app/shared/collection-dropdown/collection-dropdown.component.ts index d330c0b6fff..0fef74b3896 100644 --- a/src/app/shared/collection-dropdown/collection-dropdown.component.ts +++ b/src/app/shared/collection-dropdown/collection-dropdown.component.ts @@ -72,7 +72,7 @@ export interface CollectionListEntry { } @Component({ - selector: 'ds-collection-dropdown', + selector: 'ds-base-collection-dropdown', templateUrl: './collection-dropdown.component.html', styleUrls: ['./collection-dropdown.component.scss'], standalone: true, diff --git a/src/app/shared/collection-dropdown/themed-collection-dropdown.component.ts b/src/app/shared/collection-dropdown/themed-collection-dropdown.component.ts index 2f7055d4e79..643cd1f7115 100644 --- a/src/app/shared/collection-dropdown/themed-collection-dropdown.component.ts +++ b/src/app/shared/collection-dropdown/themed-collection-dropdown.component.ts @@ -12,10 +12,11 @@ import { } from './collection-dropdown.component'; @Component({ - selector: 'ds-themed-collection-dropdown', + selector: 'ds-collection-dropdown', styleUrls: [], templateUrl: '../../shared/theme-support/themed.component.html', standalone: true, + imports: [CollectionDropdownComponent], }) export class ThemedCollectionDropdownComponent extends ThemedComponent { diff --git a/src/app/shared/comcol/comcol-forms/create-comcol-page/create-comcol-page.component.ts b/src/app/shared/comcol/comcol-forms/create-comcol-page/create-comcol-page.component.ts index 398ffeb6ba9..d4c311bd1be 100644 --- a/src/app/shared/comcol/comcol-forms/create-comcol-page/create-comcol-page.component.ts +++ b/src/app/shared/comcol/comcol-forms/create-comcol-page/create-comcol-page.component.ts @@ -4,7 +4,10 @@ import { } from '@angular/core'; import { Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; -import { Observable } from 'rxjs'; +import { + BehaviorSubject, + Observable, +} from 'rxjs'; import { mergeMap, take, @@ -62,6 +65,11 @@ export class CreateComColPageComponent i */ protected type: ResourceType; + /** + * The + */ + isLoading$: BehaviorSubject = new BehaviorSubject(false); + public constructor( protected dsoDataService: ComColDataService, public dsoNameService: DSONameService, @@ -89,6 +97,7 @@ export class CreateComColPageComponent i * @param event The event returned by the community/collection form. Contains the new dso and logo uploader */ onSubmit(event) { + this.isLoading$.next(true); const dso = event.dso; const uploader = event.uploader; @@ -101,6 +110,7 @@ export class CreateComColPageComponent i ); })) .subscribe((dsoRD: TDomain) => { + this.isLoading$.next(false); if (isNotUndefined(dsoRD)) { this.newUUID = dsoRD.uuid; if (uploader.queue.length > 0) { diff --git a/src/app/shared/comcol/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.html b/src/app/shared/comcol/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.html index fa9dd5da099..2639a4c099f 100644 --- a/src/app/shared/comcol/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.html +++ b/src/app/shared/comcol/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.html @@ -13,7 +13,7 @@

- +
{{'comcol-role.edit.no-group' | translate}}
diff --git a/src/app/shared/comcol/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.ts b/src/app/shared/comcol/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.ts index 8fa11331787..22c4ed49f3a 100644 --- a/src/app/shared/comcol/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.ts +++ b/src/app/shared/comcol/comcol-forms/edit-comcol-page/comcol-role/comcol-role.component.ts @@ -71,7 +71,7 @@ export class ComcolRoleComponent implements OnInit { * The community or collection to manage. */ @Input() - dso: Community | Collection; + dso: Community | Collection; /** * The role to manage diff --git a/src/app/shared/comcol/comcol-page-browse-by/comcol-page-browse-by.component.ts b/src/app/shared/comcol/comcol-page-browse-by/comcol-page-browse-by.component.ts index bcfb04a4438..a7730ee7dda 100644 --- a/src/app/shared/comcol/comcol-page-browse-by/comcol-page-browse-by.component.ts +++ b/src/app/shared/comcol/comcol-page-browse-by/comcol-page-browse-by.component.ts @@ -54,7 +54,7 @@ export interface ComColPageNavOption { * It expects the ID of the Community or Collection as input to be passed on as a scope */ @Component({ - selector: 'ds-comcol-page-browse-by', + selector: 'ds-base-comcol-page-browse-by', styleUrls: ['./comcol-page-browse-by.component.scss'], templateUrl: './comcol-page-browse-by.component.html', imports: [ diff --git a/src/app/shared/comcol/comcol-page-browse-by/themed-comcol-page-browse-by.component.ts b/src/app/shared/comcol/comcol-page-browse-by/themed-comcol-page-browse-by.component.ts index 2133bbe312d..148e0466b4b 100644 --- a/src/app/shared/comcol/comcol-page-browse-by/themed-comcol-page-browse-by.component.ts +++ b/src/app/shared/comcol/comcol-page-browse-by/themed-comcol-page-browse-by.component.ts @@ -10,10 +10,11 @@ import { ComcolPageBrowseByComponent } from './comcol-page-browse-by.component'; * Themed wrapper for ComcolPageBrowseByComponent */ @Component({ - selector: 'ds-themed-comcol-page-browse-by', + selector: 'ds-comcol-page-browse-by', styleUrls: [], templateUrl: '../../theme-support/themed.component.html', standalone: true, + imports: [ComcolPageBrowseByComponent], }) export class ThemedComcolPageBrowseByComponent extends ThemedComponent { /** diff --git a/src/app/shared/comcol/comcol-page-handle/comcol-page-handle.component.ts b/src/app/shared/comcol/comcol-page-handle/comcol-page-handle.component.ts index 4487c20982c..e7023fd28b5 100644 --- a/src/app/shared/comcol/comcol-page-handle/comcol-page-handle.component.ts +++ b/src/app/shared/comcol/comcol-page-handle/comcol-page-handle.component.ts @@ -11,7 +11,7 @@ import { TranslateModule } from '@ngx-translate/core'; */ @Component({ - selector: 'ds-comcol-page-handle', + selector: 'ds-base-comcol-page-handle', styleUrls: ['./comcol-page-handle.component.scss'], templateUrl: './comcol-page-handle.component.html', imports: [NgIf, TranslateModule], diff --git a/src/app/shared/comcol/comcol-page-handle/themed-comcol-page-handle.component.ts b/src/app/shared/comcol/comcol-page-handle/themed-comcol-page-handle.component.ts index 590a7136bd6..98f137f9349 100644 --- a/src/app/shared/comcol/comcol-page-handle/themed-comcol-page-handle.component.ts +++ b/src/app/shared/comcol/comcol-page-handle/themed-comcol-page-handle.component.ts @@ -10,10 +10,11 @@ import { ComcolPageHandleComponent } from './comcol-page-handle.component'; * Themed wrapper for BreadcrumbsComponent */ @Component({ - selector: 'ds-themed-comcol-page-handle', + selector: 'ds-comcol-page-handle', styleUrls: [], templateUrl: '../../theme-support/themed.component.html', standalone: true, + imports: [ComcolPageHandleComponent], }) diff --git a/src/app/shared/comcol/sections/comcol-search-section/comcol-search-section.component.html b/src/app/shared/comcol/sections/comcol-search-section/comcol-search-section.component.html index 7c97dabf43a..efaef0a5b71 100644 --- a/src/app/shared/comcol/sections/comcol-search-section/comcol-search-section.component.html +++ b/src/app/shared/comcol/sections/comcol-search-section/comcol-search-section.component.html @@ -1,7 +1,7 @@ - - + diff --git a/src/app/shared/confirmation-modal/confirmation-modal.component.ts b/src/app/shared/confirmation-modal/confirmation-modal.component.ts index aedbf55a3a5..7618706ab48 100644 --- a/src/app/shared/confirmation-modal/confirmation-modal.component.ts +++ b/src/app/shared/confirmation-modal/confirmation-modal.component.ts @@ -31,7 +31,7 @@ export class ConfirmationModalComponent { * An event fired when the cancel or confirm button is clicked, with respectively false or true */ @Output() - response = new EventEmitter(); + response = new EventEmitter(); constructor( protected activeModal: NgbActiveModal, diff --git a/src/app/shared/correction-suggestion/item-withdrawn-reinstate-modal.component.ts b/src/app/shared/correction-suggestion/item-withdrawn-reinstate-modal.component.ts index ab8cb689e81..decd7c8d38c 100644 --- a/src/app/shared/correction-suggestion/item-withdrawn-reinstate-modal.component.ts +++ b/src/app/shared/correction-suggestion/item-withdrawn-reinstate-modal.component.ts @@ -14,7 +14,7 @@ import { BehaviorSubject } from 'rxjs'; import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service'; import { ModalBeforeDismiss } from '../interfaces/modal-before-dismiss.interface'; -import { LoadingComponent } from '../loading/loading.component'; +import { ThemedLoadingComponent } from '../loading/themed-loading.component'; @Component({ selector: 'ds-item-withdrawn-reinstate-modal', @@ -23,7 +23,7 @@ import { LoadingComponent } from '../loading/loading.component'; imports: [ NgIf, TranslateModule, - LoadingComponent, + ThemedLoadingComponent, FormsModule, AsyncPipe, ], diff --git a/src/app/shared/ds-select/ds-select.component.ts b/src/app/shared/ds-select/ds-select.component.ts index d018ffa29e7..d82378d4e5d 100644 --- a/src/app/shared/ds-select/ds-select.component.ts +++ b/src/app/shared/ds-select/ds-select.component.ts @@ -24,23 +24,23 @@ export class DsSelectComponent { * An optional label for the dropdown selector. */ @Input() - label: string; + label: string; /** * Whether the dropdown selector is disabled. */ @Input() - disabled: boolean; + disabled: boolean; /** * Emits an event when the dropdown selector is opened or closed. */ @Output() - toggled = new EventEmitter(); + toggled = new EventEmitter(); /** * Emits an event when the dropdown selector or closed. */ @Output() - close = new EventEmitter(); + close = new EventEmitter(); } diff --git a/src/app/shared/dso-selector/dso-selector/dso-selector.component.html b/src/app/shared/dso-selector/dso-selector/dso-selector.component.html index 71625066fa7..c30bc389ccb 100644 --- a/src/app/shared/dso-selector/dso-selector/dso-selector.component.html +++ b/src/app/shared/dso-selector/dso-selector/dso-selector.component.html @@ -32,7 +32,7 @@
diff --git a/src/app/shared/dso-selector/modal-wrappers/create-collection-parent-selector/create-collection-parent-selector.component.ts b/src/app/shared/dso-selector/modal-wrappers/create-collection-parent-selector/create-collection-parent-selector.component.ts index 5c552323186..05efb987a33 100644 --- a/src/app/shared/dso-selector/modal-wrappers/create-collection-parent-selector/create-collection-parent-selector.component.ts +++ b/src/app/shared/dso-selector/modal-wrappers/create-collection-parent-selector/create-collection-parent-selector.component.ts @@ -33,7 +33,7 @@ import { */ @Component({ - selector: 'ds-create-collection-parent-selector', + selector: 'ds-base-create-collection-parent-selector', templateUrl: '../dso-selector-modal-wrapper.component.html', standalone: true, imports: [NgIf, DSOSelectorComponent, TranslateModule], diff --git a/src/app/shared/dso-selector/modal-wrappers/create-collection-parent-selector/themed-create-collection-parent-selector.component.ts b/src/app/shared/dso-selector/modal-wrappers/create-collection-parent-selector/themed-create-collection-parent-selector.component.ts index 5ecd017f5c8..d521d981ca8 100644 --- a/src/app/shared/dso-selector/modal-wrappers/create-collection-parent-selector/themed-create-collection-parent-selector.component.ts +++ b/src/app/shared/dso-selector/modal-wrappers/create-collection-parent-selector/themed-create-collection-parent-selector.component.ts @@ -7,10 +7,11 @@ import { CreateCollectionParentSelectorComponent } from './create-collection-par * Themed wrapper for CreateCollectionParentSelectorComponent */ @Component({ - selector: 'ds-themed-create-collection-parent-selector', + selector: 'ds-create-collection-parent-selector', styleUrls: [], templateUrl: '../../../theme-support/themed.component.html', standalone: true, + imports: [CreateCollectionParentSelectorComponent], }) export class ThemedCreateCollectionParentSelectorComponent extends ThemedComponent { diff --git a/src/app/shared/dso-selector/modal-wrappers/create-community-parent-selector/create-community-parent-selector.component.ts b/src/app/shared/dso-selector/modal-wrappers/create-community-parent-selector/create-community-parent-selector.component.ts index 27b09b749cb..6b1e51dbf5b 100644 --- a/src/app/shared/dso-selector/modal-wrappers/create-community-parent-selector/create-community-parent-selector.component.ts +++ b/src/app/shared/dso-selector/modal-wrappers/create-community-parent-selector/create-community-parent-selector.component.ts @@ -36,7 +36,7 @@ import { */ @Component({ - selector: 'ds-create-community-parent-selector', + selector: 'ds-base-create-community-parent-selector', styleUrls: ['./create-community-parent-selector.component.scss'], templateUrl: './create-community-parent-selector.component.html', standalone: true, diff --git a/src/app/shared/dso-selector/modal-wrappers/create-community-parent-selector/themed-create-community-parent-selector.component.ts b/src/app/shared/dso-selector/modal-wrappers/create-community-parent-selector/themed-create-community-parent-selector.component.ts index 9568cc261da..e9f66099666 100644 --- a/src/app/shared/dso-selector/modal-wrappers/create-community-parent-selector/themed-create-community-parent-selector.component.ts +++ b/src/app/shared/dso-selector/modal-wrappers/create-community-parent-selector/themed-create-community-parent-selector.component.ts @@ -7,10 +7,11 @@ import { CreateCommunityParentSelectorComponent } from './create-community-paren * Themed wrapper for CreateCommunityParentSelectorComponent */ @Component({ - selector: 'ds-themed-create-community-parent-selector', + selector: 'ds-create-community-parent-selector', styleUrls: [], templateUrl: '../../../theme-support/themed.component.html', standalone: true, + imports: [CreateCommunityParentSelectorComponent], }) export class ThemedCreateCommunityParentSelectorComponent extends ThemedComponent { diff --git a/src/app/shared/dso-selector/modal-wrappers/create-item-parent-selector/create-item-parent-selector.component.ts b/src/app/shared/dso-selector/modal-wrappers/create-item-parent-selector/create-item-parent-selector.component.ts index 4c649ba85b1..ede3cc36095 100644 --- a/src/app/shared/dso-selector/modal-wrappers/create-item-parent-selector/create-item-parent-selector.component.ts +++ b/src/app/shared/dso-selector/modal-wrappers/create-item-parent-selector/create-item-parent-selector.component.ts @@ -31,7 +31,7 @@ import { */ @Component({ - selector: 'ds-create-item-parent-selector', + selector: 'ds-base-create-item-parent-selector', // styleUrls: ['./create-item-parent-selector.component.scss'], // templateUrl: '../dso-selector-modal-wrapper.component.html', templateUrl: './create-item-parent-selector.component.html', diff --git a/src/app/shared/dso-selector/modal-wrappers/create-item-parent-selector/themed-create-item-parent-selector.component.ts b/src/app/shared/dso-selector/modal-wrappers/create-item-parent-selector/themed-create-item-parent-selector.component.ts index 68bf918c45e..f6cd552629f 100644 --- a/src/app/shared/dso-selector/modal-wrappers/create-item-parent-selector/themed-create-item-parent-selector.component.ts +++ b/src/app/shared/dso-selector/modal-wrappers/create-item-parent-selector/themed-create-item-parent-selector.component.ts @@ -10,10 +10,11 @@ import { CreateItemParentSelectorComponent } from './create-item-parent-selector * Themed wrapper for CreateItemParentSelectorComponent */ @Component({ - selector: 'ds-themed-create-item-parent-selector', + selector: 'ds-create-item-parent-selector', styleUrls: [], templateUrl: '../../../theme-support/themed.component.html', standalone: true, + imports: [CreateItemParentSelectorComponent], }) export class ThemedCreateItemParentSelectorComponent extends ThemedComponent { diff --git a/src/app/shared/dso-selector/modal-wrappers/edit-collection-selector/edit-collection-selector.component.ts b/src/app/shared/dso-selector/modal-wrappers/edit-collection-selector/edit-collection-selector.component.ts index 65424e643da..611a4f13dec 100644 --- a/src/app/shared/dso-selector/modal-wrappers/edit-collection-selector/edit-collection-selector.component.ts +++ b/src/app/shared/dso-selector/modal-wrappers/edit-collection-selector/edit-collection-selector.component.ts @@ -30,7 +30,7 @@ import { */ @Component({ - selector: 'ds-edit-collection-selector', + selector: 'ds-base-edit-collection-selector', templateUrl: '../dso-selector-modal-wrapper.component.html', standalone: true, imports: [NgIf, DSOSelectorComponent, TranslateModule], diff --git a/src/app/shared/dso-selector/modal-wrappers/edit-collection-selector/themed-edit-collection-selector.component.ts b/src/app/shared/dso-selector/modal-wrappers/edit-collection-selector/themed-edit-collection-selector.component.ts index 834b4a5f0b3..28604c18b66 100644 --- a/src/app/shared/dso-selector/modal-wrappers/edit-collection-selector/themed-edit-collection-selector.component.ts +++ b/src/app/shared/dso-selector/modal-wrappers/edit-collection-selector/themed-edit-collection-selector.component.ts @@ -7,10 +7,11 @@ import { EditCollectionSelectorComponent } from './edit-collection-selector.comp * Themed wrapper for EditCollectionSelectorComponent */ @Component({ - selector: 'ds-themed-edit-collection-selector', + selector: 'ds-edit-collection-selector', styleUrls: [], templateUrl: '../../../theme-support/themed.component.html', standalone: true, + imports: [EditCollectionSelectorComponent], }) export class ThemedEditCollectionSelectorComponent extends ThemedComponent { diff --git a/src/app/shared/dso-selector/modal-wrappers/edit-community-selector/edit-community-selector.component.ts b/src/app/shared/dso-selector/modal-wrappers/edit-community-selector/edit-community-selector.component.ts index 6f781cb9eb8..3f7ede0de0d 100644 --- a/src/app/shared/dso-selector/modal-wrappers/edit-community-selector/edit-community-selector.component.ts +++ b/src/app/shared/dso-selector/modal-wrappers/edit-community-selector/edit-community-selector.component.ts @@ -30,7 +30,7 @@ import { */ @Component({ - selector: 'ds-edit-community-selector', + selector: 'ds-base-edit-community-selector', templateUrl: '../dso-selector-modal-wrapper.component.html', standalone: true, imports: [NgIf, DSOSelectorComponent, TranslateModule], diff --git a/src/app/shared/dso-selector/modal-wrappers/edit-community-selector/themed-edit-community-selector.component.ts b/src/app/shared/dso-selector/modal-wrappers/edit-community-selector/themed-edit-community-selector.component.ts index 27798879ff6..0e33746edc9 100644 --- a/src/app/shared/dso-selector/modal-wrappers/edit-community-selector/themed-edit-community-selector.component.ts +++ b/src/app/shared/dso-selector/modal-wrappers/edit-community-selector/themed-edit-community-selector.component.ts @@ -7,10 +7,11 @@ import { EditCommunitySelectorComponent } from './edit-community-selector.compon * Themed wrapper for EditCommunitySelectorComponent */ @Component({ - selector: 'ds-themed-edit-community-selector', + selector: 'ds-edit-community-selector', styleUrls: [], templateUrl: '../../../theme-support/themed.component.html', standalone: true, + imports: [EditCommunitySelectorComponent], }) export class ThemedEditCommunitySelectorComponent extends ThemedComponent { diff --git a/src/app/shared/dso-selector/modal-wrappers/edit-item-selector/edit-item-selector.component.ts b/src/app/shared/dso-selector/modal-wrappers/edit-item-selector/edit-item-selector.component.ts index ebcc936a3ec..903f4327344 100644 --- a/src/app/shared/dso-selector/modal-wrappers/edit-item-selector/edit-item-selector.component.ts +++ b/src/app/shared/dso-selector/modal-wrappers/edit-item-selector/edit-item-selector.component.ts @@ -26,7 +26,7 @@ import { */ @Component({ - selector: 'ds-edit-item-selector', + selector: 'ds-base-edit-item-selector', templateUrl: 'edit-item-selector.component.html', standalone: true, imports: [NgIf, DSOSelectorComponent, TranslateModule], diff --git a/src/app/shared/dso-selector/modal-wrappers/edit-item-selector/themed-edit-item-selector.component.ts b/src/app/shared/dso-selector/modal-wrappers/edit-item-selector/themed-edit-item-selector.component.ts index e7b0a456d21..fbb6850a021 100644 --- a/src/app/shared/dso-selector/modal-wrappers/edit-item-selector/themed-edit-item-selector.component.ts +++ b/src/app/shared/dso-selector/modal-wrappers/edit-item-selector/themed-edit-item-selector.component.ts @@ -7,10 +7,11 @@ import { EditItemSelectorComponent } from './edit-item-selector.component'; * Themed wrapper for EditItemSelectorComponent */ @Component({ - selector: 'ds-themed-edit-item-selector', + selector: 'ds-edit-item-selector', styleUrls: [], templateUrl: '../../../theme-support/themed.component.html', standalone: true, + imports: [EditItemSelectorComponent], }) export class ThemedEditItemSelectorComponent extends ThemedComponent { diff --git a/src/app/shared/dso-selector/modal-wrappers/import-batch-selector/import-batch-selector.component.ts b/src/app/shared/dso-selector/modal-wrappers/import-batch-selector/import-batch-selector.component.ts index 599b9977ef2..2b3785c0f9c 100644 --- a/src/app/shared/dso-selector/modal-wrappers/import-batch-selector/import-batch-selector.component.ts +++ b/src/app/shared/dso-selector/modal-wrappers/import-batch-selector/import-batch-selector.component.ts @@ -40,7 +40,7 @@ export class ImportBatchSelectorComponent extends DSOSelectorModalWrapperCompone * An event fired when the modal is closed */ @Output() - response = new EventEmitter(); + response = new EventEmitter(); constructor(protected activeModal: NgbActiveModal, protected route: ActivatedRoute) { diff --git a/src/app/shared/entity-dropdown/entity-dropdown.component.html b/src/app/shared/entity-dropdown/entity-dropdown.component.html index 374c589e3e5..049f5c81bed 100644 --- a/src/app/shared/entity-dropdown/entity-dropdown.component.html +++ b/src/app/shared/entity-dropdown/entity-dropdown.component.html @@ -23,8 +23,8 @@
  • diff --git a/src/app/shared/file-download-link/file-download-link.component.ts b/src/app/shared/file-download-link/file-download-link.component.ts index 991f5ba8645..9b01cd799d4 100644 --- a/src/app/shared/file-download-link/file-download-link.component.ts +++ b/src/app/shared/file-download-link/file-download-link.component.ts @@ -32,7 +32,7 @@ import { } from '../empty.util'; @Component({ - selector: 'ds-file-download-link', + selector: 'ds-base-file-download-link', templateUrl: './file-download-link.component.html', styleUrls: ['./file-download-link.component.scss'], standalone: true, diff --git a/src/app/shared/file-download-link/themed-file-download-link.component.ts b/src/app/shared/file-download-link/themed-file-download-link.component.ts index e4085b06f91..c0fc4597f5c 100644 --- a/src/app/shared/file-download-link/themed-file-download-link.component.ts +++ b/src/app/shared/file-download-link/themed-file-download-link.component.ts @@ -9,10 +9,11 @@ import { ThemedComponent } from '../theme-support/themed.component'; import { FileDownloadLinkComponent } from './file-download-link.component'; @Component({ - selector: 'ds-themed-file-download-link', + selector: 'ds-file-download-link', styleUrls: [], templateUrl: '../theme-support/themed.component.html', standalone: true, + imports: [FileDownloadLinkComponent], }) export class ThemedFileDownloadLinkComponent extends ThemedComponent { diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts index 1ef9a9e3504..c26df24fea5 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts @@ -155,7 +155,7 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo @Input() formModel: DynamicFormControlModel[]; @Input() asBootstrapFormGroup = false; @Input() bindId = true; - @Input() context: any | null = null; + @Input() context: any = null; @Input() group: UntypedFormGroup; @Input() hostClass: string[]; @Input() hasErrorMessaging = false; diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component.html index 001e0bc339c..944e4650abd 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component.html @@ -1,7 +1,7 @@
    - + diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/existing-relation-list-element/existing-relation-list-element.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/existing-relation-list-element/existing-relation-list-element.component.html index 5a5bd2ff2ae..08efff42197 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/existing-relation-list-element/existing-relation-list-element.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/existing-relation-list-element/existing-relation-list-element.component.html @@ -1,7 +1,7 @@
    - + diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.ts index 4589171e364..62a6b8044fd 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.ts @@ -96,6 +96,8 @@ export class DsDatePickerComponent extends DynamicFormControlComponent implement this.initialDay = now.getUTCDate(); if (this.model && this.model.value !== null) { + // todo: model value could object or Date according to its type annotation + // eslint-disable-next-line @typescript-eslint/no-base-to-string const values = this.model.value.toString().split(DS_DATE_PICKER_SEPARATOR); if (values.length > 0) { this.initialYear = parseInt(values[0], 10); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/list/dynamic-list-radio-group.model.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/list/dynamic-list-radio-group.model.ts index d6ab989cd53..af5f65802d1 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/list/dynamic-list-radio-group.model.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/list/dynamic-list-radio-group.model.ts @@ -1,5 +1,6 @@ import { DynamicFormControlLayout, + DynamicFormControlRelation, DynamicRadioGroupModel, DynamicRadioGroupModelConfig, serializable, @@ -16,12 +17,14 @@ export interface DynamicListModelConfig extends DynamicRadioGroupModelConfig { @serializable() vocabularyOptions: VocabularyOptions; @serializable() repeatable: boolean; + @serializable() typeBindRelations: DynamicFormControlRelation[]; @serializable() groupLength: number; @serializable() required: boolean; @serializable() hint: string; @@ -36,6 +39,7 @@ export class DynamicListRadioGroupModel extends DynamicRadioGroupModel { this.required = config.required; this.hint = config.hint; this.value = config.value; + this.typeBindRelations = config.typeBindRelations ? config.typeBindRelations : []; } get hasAuthority(): boolean { diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.html index e661c458b67..38f15a5ed1c 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.component.html @@ -57,7 +57,7 @@
    - +
    +
    - - +

    {{ 'submission.sections.describe.relationship-lookup.selection-tab.title.' + externalSource.id | translate}}

    @@ -21,8 +21,8 @@

    {{ 'submission.sections.describe.relationship-lookup.selection-tab.title.' + [importConfig]="importConfig" (importObject)="import($event)"> - +
    diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.spec.ts index d7090b55c8f..79831fe8ca2 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.spec.ts @@ -174,7 +174,7 @@ describe('DsDynamicLookupRelationExternalSourceTabComponent', () => { }); it('should display a ds-themed-loading component', () => { - const loading = fixture.debugElement.query(By.css('ds-themed-loading')); + const loading = fixture.debugElement.query(By.css('ds-loading')); expect(loading).not.toBeNull(); }); }); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.ts index 484abce7d65..5a1f13544ff 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/dynamic-lookup-relation-external-source-tab.component.ts @@ -63,7 +63,7 @@ import { ExternalSourceEntryImportModalComponent } from './external-source-entry import { ThemedExternalSourceEntryImportModalComponent } from './external-source-entry-import-modal/themed-external-source-entry-import-modal.component'; @Component({ - selector: 'ds-dynamic-lookup-relation-external-source-tab', + selector: 'ds-base-dynamic-lookup-relation-external-source-tab', styleUrls: ['./dynamic-lookup-relation-external-source-tab.component.scss'], templateUrl: './dynamic-lookup-relation-external-source-tab.component.html', providers: [ diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component.spec.ts index c0090f36a30..e2a4bbf4bbc 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component.spec.ts @@ -21,7 +21,7 @@ import { NotificationsService } from '../../../../../../notifications/notificati import { ItemSearchResult } from '../../../../../../object-collection/shared/item-search-result.model'; import { SelectableListService } from '../../../../../../object-list/selectable-list/selectable-list.service'; import { createSuccessfulRemoteDataObject$ } from '../../../../../../remote-data.utils'; -import { SearchResultsComponent } from '../../../../../../search/search-results/search-results.component'; +import { ThemedSearchResultsComponent } from '../../../../../../search/search-results/themed-search-results.component'; import { createPaginatedList } from '../../../../../../testing/utils.test'; import { RelationshipOptions } from '../../../../models/relationship-options.model'; import { @@ -97,7 +97,7 @@ describe('DsDynamicLookupRelationExternalSourceTabComponent', () => { schemas: [NO_ERRORS_SCHEMA], }) .overrideComponent(ExternalSourceEntryImportModalComponent, { - remove: { imports: [SearchResultsComponent] }, + remove: { imports: [ThemedSearchResultsComponent] }, }) .compileComponents(); })); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component.ts index d9581dcd85c..c2516ca9a81 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/external-source-entry-import-modal.component.ts @@ -46,7 +46,7 @@ import { SelectableListService } from '../../../../../../object-list/selectable- import { PaginationComponentOptions } from '../../../../../../pagination/pagination-component-options.model'; import { PaginatedSearchOptions } from '../../../../../../search/models/paginated-search-options.model'; import { SearchResult } from '../../../../../../search/models/search-result.model'; -import { SearchResultsComponent } from '../../../../../../search/search-results/search-results.component'; +import { ThemedSearchResultsComponent } from '../../../../../../search/search-results/themed-search-results.component'; import { RelationshipOptions } from '../../../../models/relationship-options.model'; /** @@ -61,12 +61,12 @@ export enum ImportType { } @Component({ - selector: 'ds-external-source-entry-import-modal', + selector: 'ds-base-external-source-entry-import-modal', styleUrls: ['./external-source-entry-import-modal.component.scss'], templateUrl: './external-source-entry-import-modal.component.html', imports: [ TranslateModule, - SearchResultsComponent, + ThemedSearchResultsComponent, NgIf, AsyncPipe, ], diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/themed-external-source-entry-import-modal.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/themed-external-source-entry-import-modal.component.ts index f9d2137f9bb..35dba9ca543 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/themed-external-source-entry-import-modal.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/external-source-entry-import-modal/themed-external-source-entry-import-modal.component.ts @@ -4,10 +4,11 @@ import { ThemedComponent } from '../../../../../../theme-support/themed.componen import { ExternalSourceEntryImportModalComponent } from './external-source-entry-import-modal.component'; @Component({ - selector: 'ds-themed-external-source-entry-import-modal', + selector: 'ds-external-source-entry-import-modal', styleUrls: [], templateUrl: '../../../../../../../shared/theme-support/themed.component.html', standalone: true, + imports: [ExternalSourceEntryImportModalComponent], }) export class ThemedExternalSourceEntryImportModalComponent extends ThemedComponent { protected getComponentName(): string { diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/themed-dynamic-lookup-relation-external-source-tab.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/themed-dynamic-lookup-relation-external-source-tab.component.ts index 0673bd41af3..9e4df4f5f8e 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/themed-dynamic-lookup-relation-external-source-tab.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/external-source-tab/themed-dynamic-lookup-relation-external-source-tab.component.ts @@ -15,10 +15,11 @@ import { RelationshipOptions } from '../../../models/relationship-options.model' import { DsDynamicLookupRelationExternalSourceTabComponent } from './dynamic-lookup-relation-external-source-tab.component'; @Component({ - selector: 'ds-themed-dynamic-lookup-relation-external-source-tab', + selector: 'ds-dynamic-lookup-relation-external-source-tab', styleUrls: [], templateUrl: '../../../../../theme-support/themed.component.html', standalone: true, + imports: [DsDynamicLookupRelationExternalSourceTabComponent], }) export class ThemedDynamicLookupRelationExternalSourceTabComponent extends ThemedComponent { protected inAndOutputNames: (keyof DsDynamicLookupRelationExternalSourceTabComponent & keyof this)[] = ['label', 'listId', diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.html index 12bc93ab0e6..cfd2763b924 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.html @@ -1,4 +1,4 @@ -
    - + diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.ts index 8bf1c9c8b4c..06b4946e124 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/dynamic-lookup-relation-search-tab.component.ts @@ -53,7 +53,7 @@ import { RelationshipOptions } from '../../../models/relationship-options.model' @Component({ - selector: 'ds-dynamic-lookup-relation-search-tab', + selector: 'ds-base-dynamic-lookup-relation-search-tab', styleUrls: ['./dynamic-lookup-relation-search-tab.component.scss'], templateUrl: './dynamic-lookup-relation-search-tab.component.html', providers: [ diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/themed-dynamic-lookup-relation-search-tab.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/themed-dynamic-lookup-relation-search-tab.component.ts index cc82967080a..71d55e6494d 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/themed-dynamic-lookup-relation-search-tab.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/search-tab/themed-dynamic-lookup-relation-search-tab.component.ts @@ -18,10 +18,11 @@ import { RelationshipOptions } from '../../../models/relationship-options.model' import { DsDynamicLookupRelationSearchTabComponent } from './dynamic-lookup-relation-search-tab.component'; @Component({ - selector: 'ds-themed-dynamic-lookup-relation-search-tab', + selector: 'ds-dynamic-lookup-relation-search-tab', styleUrls: [], templateUrl: '../../../../../theme-support/themed.component.html', standalone: true, + imports: [DsDynamicLookupRelationSearchTabComponent], }) export class ThemedDynamicLookupRelationSearchTabComponent extends ThemedComponent { protected inAndOutputNames: (keyof DsDynamicLookupRelationSearchTabComponent & keyof this)[] = ['relationship', 'listId', diff --git a/src/app/shared/form/builder/form-builder.service.spec.ts b/src/app/shared/form/builder/form-builder.service.spec.ts index 6cf3f709ab3..1e481391915 100644 --- a/src/app/shared/form/builder/form-builder.service.spec.ts +++ b/src/app/shared/form/builder/form-builder.service.spec.ts @@ -31,12 +31,14 @@ import { DynamicTextAreaModel, DynamicTimePickerModel, } from '@ng-dynamic-forms/core'; +import { TranslateService } from '@ngx-translate/core'; import { FormRowModel } from '../../../core/config/models/config-submission-form.model'; import { SubmissionFormsModel } from '../../../core/config/models/config-submission-forms.model'; import { ConfigurationDataService } from '../../../core/data/configuration-data.service'; import { ConfigurationProperty } from '../../../core/shared/configuration-property.model'; import { VocabularyOptions } from '../../../core/submission/vocabularies/models/vocabulary-options.model'; +import { getMockTranslateService } from '../../mocks/translate.service.mock'; import { createSuccessfulRemoteDataObject$ } from '../../remote-data.utils'; import { DynamicDsDatePickerModel } from './ds-dynamic-form-ui/models/date-picker/date-picker.model'; import { DynamicConcatModel } from './ds-dynamic-form-ui/models/ds-dynamic-concat.model'; @@ -85,6 +87,7 @@ describe('FormBuilderService test suite', () => { beforeEach(() => { configSpy = createConfigSuccessSpy(typeFieldTestValue); + let translateService = getMockTranslateService(); TestBed.configureTestingModule({ imports: [ReactiveFormsModule], providers: [ @@ -93,6 +96,7 @@ describe('FormBuilderService test suite', () => { { provide: NG_VALIDATORS, useValue: testValidator, multi: true }, { provide: NG_ASYNC_VALIDATORS, useValue: testAsyncValidator, multi: true }, { provide: ConfigurationDataService, useValue: configSpy }, + { provide: TranslateService, useValue: translateService }, ], }); diff --git a/src/app/shared/form/builder/models/form-field.model.ts b/src/app/shared/form/builder/models/form-field.model.ts index f81c955fab9..a89801007f9 100644 --- a/src/app/shared/form/builder/models/form-field.model.ts +++ b/src/app/shared/form/builder/models/form-field.model.ts @@ -39,43 +39,43 @@ export class FormFieldModel { * The hints for this metadata field to display on form */ @autoserialize - hints: string; + hints: string; /** * The label for this metadata field to display on form */ @autoserialize - label: string; + label: string; /** * The languages available for this metadata field to display on form */ @autoserialize - languageCodes: LanguageCode[]; + languageCodes: LanguageCode[]; /** * The error message for this metadata field to display on form in case of field is required */ @autoserialize - mandatoryMessage: string; + mandatoryMessage: string; /** * Representing if this metadata field is mandatory or not */ @autoserialize - mandatory: string; + mandatory: string; /** * Representing if this metadata field is repeatable or not */ @autoserialize - repeatable: boolean; + repeatable: boolean; /** * Containing additional properties for this metadata field */ @autoserialize - input: { + input: { /** * Representing the type for this metadata field */ @@ -91,41 +91,41 @@ export class FormFieldModel { * Representing additional vocabulary configuration for this metadata field */ @autoserialize - selectableMetadata: SelectableMetadata[]; + selectableMetadata: SelectableMetadata[]; /** * Representing additional relationship configuration for this metadata field */ @autoserialize - selectableRelationship: RelationshipOptions; + selectableRelationship: RelationshipOptions; @autoserialize - rows: FormRowModel[]; + rows: FormRowModel[]; /** * Representing the scope for this metadata field */ @autoserialize - scope: string; + scope: string; /** * Containing additional css classes for this metadata field to use on form */ @autoserialize - style: string; + style: string; /** * Containing types to bind for this field */ @autoserialize - typeBind: string[]; + typeBind: string[]; /** * Containing the value for this metadata field */ @autoserialize - value: any; + value: any; @autoserialize - visibility: SectionVisibility; + visibility: SectionVisibility; } diff --git a/src/app/shared/form/builder/parsers/concat-field-parser.ts b/src/app/shared/form/builder/parsers/concat-field-parser.ts index 3b29d0eb482..40711c188d1 100644 --- a/src/app/shared/form/builder/parsers/concat-field-parser.ts +++ b/src/app/shared/form/builder/parsers/concat-field-parser.ts @@ -1,4 +1,5 @@ import { Inject } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; import { hasNoValue, @@ -34,17 +35,18 @@ export class ConcatFieldParser extends FieldParser { @Inject(CONFIG_DATA) configData: FormFieldModel, @Inject(INIT_FORM_VALUES) initFormValues, @Inject(PARSER_OPTIONS) parserOptions: ParserOptions, + translate: TranslateService, protected separator: string, protected firstPlaceholder: string = null, protected secondPlaceholder: string = null) { - super(submissionId, configData, initFormValues, parserOptions); + super(submissionId, configData, initFormValues, parserOptions, translate); this.separator = separator; this.firstPlaceholder = firstPlaceholder; this.secondPlaceholder = secondPlaceholder; } - public modelFactory(fieldValue?: FormFieldMetadataValueObject | any, label?: boolean): any { + public modelFactory(fieldValue?: FormFieldMetadataValueObject, label?: boolean): any { const id: string = this.configData.selectableMetadata[0].metadata; const clsInput = { diff --git a/src/app/shared/form/builder/parsers/date-field-parser.spec.ts b/src/app/shared/form/builder/parsers/date-field-parser.spec.ts index d1912a7cad9..ec2172523fe 100644 --- a/src/app/shared/form/builder/parsers/date-field-parser.spec.ts +++ b/src/app/shared/form/builder/parsers/date-field-parser.spec.ts @@ -1,12 +1,17 @@ +import { getMockTranslateService } from 'src/app/shared/mocks/translate.service.mock'; + import { DynamicDsDatePickerModel } from '../ds-dynamic-form-ui/models/date-picker/date-picker.model'; import { FormFieldModel } from '../models/form-field.model'; import { FormFieldMetadataValueObject } from '../models/form-field-metadata-value.model'; import { DateFieldParser } from './date-field-parser'; import { ParserOptions } from './parser-options'; + + describe('DateFieldParser test suite', () => { let field: FormFieldModel; let initFormValues: any = {}; + let translateService = getMockTranslateService(); const submissionId = '1234'; const parserOptions: ParserOptions = { @@ -37,13 +42,13 @@ describe('DateFieldParser test suite', () => { }); it('should init parser properly', () => { - const parser = new DateFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new DateFieldParser(submissionId, field, initFormValues, parserOptions, translateService); expect(parser instanceof DateFieldParser).toBe(true); }); it('should return a DynamicDsDatePickerModel object when repeatable option is false', () => { - const parser = new DateFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new DateFieldParser(submissionId, field, initFormValues, parserOptions, translateService); const fieldModel = parser.parse(); @@ -56,7 +61,7 @@ describe('DateFieldParser test suite', () => { }; const expectedValue = '1983-11-18'; - const parser = new DateFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new DateFieldParser(submissionId, field, initFormValues, parserOptions, translateService); const fieldModel = parser.parse(); diff --git a/src/app/shared/form/builder/parsers/date-field-parser.ts b/src/app/shared/form/builder/parsers/date-field-parser.ts index ea9f193e334..8104568b1aa 100644 --- a/src/app/shared/form/builder/parsers/date-field-parser.ts +++ b/src/app/shared/form/builder/parsers/date-field-parser.ts @@ -9,7 +9,7 @@ import { FieldParser } from './field-parser'; export class DateFieldParser extends FieldParser { - public modelFactory(fieldValue?: FormFieldMetadataValueObject | any, label?: boolean): any { + public modelFactory(fieldValue?: FormFieldMetadataValueObject, label?: boolean): any { let malformedDate = false; const inputDateModelConfig: DynamicDsDateControlModelConfig = this.initModel(null, false, true); inputDateModelConfig.legend = this.configData.label; @@ -18,6 +18,8 @@ export class DateFieldParser extends FieldParser { this.setValues(inputDateModelConfig as any, fieldValue); // Init Data and validity check if (isNotEmpty(inputDateModelConfig.value)) { + // todo: model value could be object or Date according to its type annotation + // eslint-disable-next-line @typescript-eslint/no-base-to-string const value = inputDateModelConfig.value.toString(); if (value.length >= 4) { const valuesArray = value.split(DS_DATE_PICKER_SEPARATOR); diff --git a/src/app/shared/form/builder/parsers/disabled-field-parser.spec.ts b/src/app/shared/form/builder/parsers/disabled-field-parser.spec.ts index fd6908ed3b8..759f357f282 100644 --- a/src/app/shared/form/builder/parsers/disabled-field-parser.spec.ts +++ b/src/app/shared/form/builder/parsers/disabled-field-parser.spec.ts @@ -1,3 +1,5 @@ +import { getMockTranslateService } from 'src/app/shared/mocks/translate.service.mock'; + import { DynamicDisabledModel } from '../ds-dynamic-form-ui/models/disabled/dynamic-disabled.model'; import { FormFieldModel } from '../models/form-field.model'; import { DisabledFieldParser } from './disabled-field-parser'; @@ -6,6 +8,7 @@ import { ParserOptions } from './parser-options'; describe('DisabledFieldParser test suite', () => { let field: FormFieldModel; let initFormValues: any = {}; + let translateService = getMockTranslateService(); const submissionId = '1234'; const parserOptions: ParserOptions = { @@ -35,13 +38,13 @@ describe('DisabledFieldParser test suite', () => { }); it('should init parser properly', () => { - const parser = new DisabledFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new DisabledFieldParser(submissionId, field, initFormValues, parserOptions, translateService); expect(parser instanceof DisabledFieldParser).toBe(true); }); it('should return a DynamicDisabledModel object when repeatable option is false', () => { - const parser = new DisabledFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new DisabledFieldParser(submissionId, field, initFormValues, parserOptions, translateService); const fieldModel = parser.parse(); @@ -56,7 +59,7 @@ describe('DisabledFieldParser test suite', () => { }; const expectedValue = 'test description'; - const parser = new DisabledFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new DisabledFieldParser(submissionId, field, initFormValues, parserOptions, translateService); const fieldModel = parser.parse(); expect(fieldModel.value.value).toEqual(expectedValue); diff --git a/src/app/shared/form/builder/parsers/disabled-field-parser.ts b/src/app/shared/form/builder/parsers/disabled-field-parser.ts index e9b97ba7d93..ac977de40a7 100644 --- a/src/app/shared/form/builder/parsers/disabled-field-parser.ts +++ b/src/app/shared/form/builder/parsers/disabled-field-parser.ts @@ -10,7 +10,7 @@ import { FieldParser } from './field-parser'; */ export class DisabledFieldParser extends FieldParser { - public modelFactory(fieldValue?: FormFieldMetadataValueObject | any, label?: boolean): any { + public modelFactory(fieldValue?: FormFieldMetadataValueObject, label?: boolean): any { const emptyModelConfig: DsDynamicDisabledModelConfig = this.initModel(null, label); this.setValues(emptyModelConfig, fieldValue, true); return new DynamicDisabledModel(emptyModelConfig); diff --git a/src/app/shared/form/builder/parsers/dropdown-field-parser.spec.ts b/src/app/shared/form/builder/parsers/dropdown-field-parser.spec.ts index 0ab376d1aaa..c0c3daa3044 100644 --- a/src/app/shared/form/builder/parsers/dropdown-field-parser.spec.ts +++ b/src/app/shared/form/builder/parsers/dropdown-field-parser.spec.ts @@ -1,3 +1,5 @@ +import { getMockTranslateService } from 'src/app/shared/mocks/translate.service.mock'; + import { DynamicScrollableDropdownModel } from '../ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.model'; import { FormFieldModel } from '../models/form-field.model'; import { DropdownFieldParser } from './dropdown-field-parser'; @@ -5,6 +7,7 @@ import { ParserOptions } from './parser-options'; describe('DropdownFieldParser test suite', () => { let field: FormFieldModel; + let translateService = getMockTranslateService(); const submissionId = '1234'; const initFormValues = {}; @@ -37,13 +40,13 @@ describe('DropdownFieldParser test suite', () => { }); it('should init parser properly', () => { - const parser = new DropdownFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new DropdownFieldParser(submissionId, field, initFormValues, parserOptions, translateService); expect(parser instanceof DropdownFieldParser).toBe(true); }); it('should return a DynamicScrollableDropdownModel object when repeatable option is false', () => { - const parser = new DropdownFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new DropdownFieldParser(submissionId, field, initFormValues, parserOptions, translateService); const fieldModel = parser.parse(); @@ -52,7 +55,7 @@ describe('DropdownFieldParser test suite', () => { it('should throw when authority is not passed', () => { field.selectableMetadata[0].controlledVocabulary = null; - const parser = new DropdownFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new DropdownFieldParser(submissionId, field, initFormValues, parserOptions, translateService); expect(() => parser.parse()) .toThrow(); diff --git a/src/app/shared/form/builder/parsers/dropdown-field-parser.ts b/src/app/shared/form/builder/parsers/dropdown-field-parser.ts index 1fc28d1274b..5a21f794f81 100644 --- a/src/app/shared/form/builder/parsers/dropdown-field-parser.ts +++ b/src/app/shared/form/builder/parsers/dropdown-field-parser.ts @@ -1,5 +1,6 @@ import { Inject } from '@angular/core'; import { DynamicFormControlLayout } from '@ng-dynamic-forms/core'; +import { TranslateService } from '@ngx-translate/core'; import { isNotEmpty } from '../../../empty.util'; import { @@ -24,11 +25,12 @@ export class DropdownFieldParser extends FieldParser { @Inject(CONFIG_DATA) configData: FormFieldModel, @Inject(INIT_FORM_VALUES) initFormValues, @Inject(PARSER_OPTIONS) parserOptions: ParserOptions, + translate: TranslateService, ) { - super(submissionId, configData, initFormValues, parserOptions); + super(submissionId, configData, initFormValues, parserOptions, translate); } - public modelFactory(fieldValue?: FormFieldMetadataValueObject | any, label?: boolean): any { + public modelFactory(fieldValue?: FormFieldMetadataValueObject, label?: boolean): any { const dropdownModelConfig: DynamicScrollableDropdownModelConfig = this.initModel(null, label); let layout: DynamicFormControlLayout; diff --git a/src/app/shared/form/builder/parsers/field-parser.ts b/src/app/shared/form/builder/parsers/field-parser.ts index c77b244d6a3..590d5f564e9 100644 --- a/src/app/shared/form/builder/parsers/field-parser.ts +++ b/src/app/shared/form/builder/parsers/field-parser.ts @@ -8,6 +8,7 @@ import { MATCH_VISIBLE, OR_OPERATOR, } from '@ng-dynamic-forms/core'; +import { TranslateService } from '@ngx-translate/core'; import uniqueId from 'lodash/uniqueId'; import { SubmissionScopeType } from '../../../../core/submission/submission-scope-type'; @@ -61,6 +62,7 @@ export abstract class FieldParser { @Inject(CONFIG_DATA) protected configData: FormFieldModel, @Inject(INIT_FORM_VALUES) protected initFormValues: any, @Inject(PARSER_OPTIONS) protected parserOptions: ParserOptions, + protected translate: TranslateService, ) { } @@ -68,8 +70,8 @@ export abstract class FieldParser { public parse() { if (((this.getInitValueCount() > 1 && !this.configData.repeatable) || (this.configData.repeatable)) - && (this.configData.input.type !== ParserType.List) - && (this.configData.input.type !== ParserType.Tag) + && (this.configData.input.type !== ParserType.List.valueOf()) + && (this.configData.input.type !== ParserType.Tag.valueOf()) ) { let arrayCounter = 0; let fieldArrayCounter = 0; @@ -81,7 +83,7 @@ export abstract class FieldParser { } let isDraggable = true; - if (this.configData.input.type === ParserType.Onebox && this.configData?.selectableMetadata?.length > 1) { + if (this.configData.input.type === ParserType.Onebox.valueOf() && this.configData?.selectableMetadata?.length > 1) { isDraggable = false; } const config = { @@ -344,12 +346,12 @@ export abstract class FieldParser { && isNotEmpty(fieldScope) && isNotEmpty(visibility) && (( - submissionScope === SubmissionScopeType.WorkspaceItem + submissionScope === SubmissionScopeType.WorkspaceItem.valueOf() && visibility.main === VisibilityType.READONLY ) || (visibility.other === VisibilityType.READONLY - && submissionScope === SubmissionScopeType.WorkflowItem + && submissionScope === SubmissionScopeType.WorkflowItem.valueOf() ) ); } @@ -405,11 +407,14 @@ export abstract class FieldParser { } else { regex = new RegExp(this.configData.input.regex); } + const baseTranslationKey = 'error.validation.pattern'; + const fieldranslationKey = `${baseTranslationKey}.${controlModel.id}`; + const fieldTranslationExists = this.translate.instant(fieldranslationKey) !== fieldranslationKey; controlModel.validators = Object.assign({}, controlModel.validators, { pattern: regex }); controlModel.errorMessages = Object.assign( {}, controlModel.errorMessages, - { pattern: 'error.validation.pattern' }); + { pattern: fieldTranslationExists ? fieldranslationKey : baseTranslationKey }); } protected markAsRequired(controlModel) { diff --git a/src/app/shared/form/builder/parsers/list-field-parser.spec.ts b/src/app/shared/form/builder/parsers/list-field-parser.spec.ts index f0a446c0cef..646fee9dec0 100644 --- a/src/app/shared/form/builder/parsers/list-field-parser.spec.ts +++ b/src/app/shared/form/builder/parsers/list-field-parser.spec.ts @@ -1,3 +1,5 @@ +import { getMockTranslateService } from 'src/app/shared/mocks/translate.service.mock'; + import { DynamicListCheckboxGroupModel } from '../ds-dynamic-form-ui/models/list/dynamic-list-checkbox-group.model'; import { DynamicListRadioGroupModel } from '../ds-dynamic-form-ui/models/list/dynamic-list-radio-group.model'; import { FormFieldModel } from '../models/form-field.model'; @@ -8,6 +10,7 @@ import { ParserOptions } from './parser-options'; describe('ListFieldParser test suite', () => { let field: FormFieldModel; let initFormValues = {}; + let translateService = getMockTranslateService(); const submissionId = '1234'; const parserOptions: ParserOptions = { @@ -39,13 +42,13 @@ describe('ListFieldParser test suite', () => { }); it('should init parser properly', () => { - const parser = new ListFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new ListFieldParser(submissionId, field, initFormValues, parserOptions, translateService); expect(parser instanceof ListFieldParser).toBe(true); }); it('should return a DynamicListCheckboxGroupModel object when repeatable option is true', () => { - const parser = new ListFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new ListFieldParser(submissionId, field, initFormValues, parserOptions, translateService); const fieldModel = parser.parse(); @@ -54,7 +57,7 @@ describe('ListFieldParser test suite', () => { it('should return a DynamicListRadioGroupModel object when repeatable option is false', () => { field.repeatable = false; - const parser = new ListFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new ListFieldParser(submissionId, field, initFormValues, parserOptions, translateService); const fieldModel = parser.parse(); @@ -67,7 +70,7 @@ describe('ListFieldParser test suite', () => { }; const expectedValue = [new FormFieldMetadataValueObject('test type')]; - const parser = new ListFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new ListFieldParser(submissionId, field, initFormValues, parserOptions, translateService); const fieldModel = parser.parse(); diff --git a/src/app/shared/form/builder/parsers/list-field-parser.ts b/src/app/shared/form/builder/parsers/list-field-parser.ts index f786e888ceb..dd619872478 100644 --- a/src/app/shared/form/builder/parsers/list-field-parser.ts +++ b/src/app/shared/form/builder/parsers/list-field-parser.ts @@ -6,7 +6,7 @@ import { FieldParser } from './field-parser'; export class ListFieldParser extends FieldParser { - public modelFactory(fieldValue?: FormFieldMetadataValueObject | any, label?: boolean): any { + public modelFactory(fieldValue?: FormFieldMetadataValueObject, label?: boolean): any { const listModelConfig = this.initModel(null, label); listModelConfig.repeatable = this.configData.repeatable; diff --git a/src/app/shared/form/builder/parsers/lookup-field-parser.spec.ts b/src/app/shared/form/builder/parsers/lookup-field-parser.spec.ts index 6d57e686432..2ed45803edc 100644 --- a/src/app/shared/form/builder/parsers/lookup-field-parser.spec.ts +++ b/src/app/shared/form/builder/parsers/lookup-field-parser.spec.ts @@ -1,3 +1,5 @@ +import { getMockTranslateService } from 'src/app/shared/mocks/translate.service.mock'; + import { DynamicLookupModel } from '../ds-dynamic-form-ui/models/lookup/dynamic-lookup.model'; import { FormFieldModel } from '../models/form-field.model'; import { FormFieldMetadataValueObject } from '../models/form-field-metadata-value.model'; @@ -7,6 +9,7 @@ import { ParserOptions } from './parser-options'; describe('LookupFieldParser test suite', () => { let field: FormFieldModel; let initFormValues = {}; + let translateService = getMockTranslateService(); const submissionId = '1234'; const parserOptions: ParserOptions = { @@ -38,13 +41,13 @@ describe('LookupFieldParser test suite', () => { }); it('should init parser properly', () => { - const parser = new LookupFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new LookupFieldParser(submissionId, field, initFormValues, parserOptions, translateService); expect(parser instanceof LookupFieldParser).toBe(true); }); it('should return a DynamicLookupModel object when repeatable option is false', () => { - const parser = new LookupFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new LookupFieldParser(submissionId, field, initFormValues, parserOptions, translateService); const fieldModel = parser.parse(); @@ -57,7 +60,7 @@ describe('LookupFieldParser test suite', () => { }; const expectedValue = new FormFieldMetadataValueObject('test journal'); - const parser = new LookupFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new LookupFieldParser(submissionId, field, initFormValues, parserOptions, translateService); const fieldModel = parser.parse(); diff --git a/src/app/shared/form/builder/parsers/lookup-field-parser.ts b/src/app/shared/form/builder/parsers/lookup-field-parser.ts index de7ba04e76d..cb75022cfff 100644 --- a/src/app/shared/form/builder/parsers/lookup-field-parser.ts +++ b/src/app/shared/form/builder/parsers/lookup-field-parser.ts @@ -7,7 +7,7 @@ import { FieldParser } from './field-parser'; export class LookupFieldParser extends FieldParser { - public modelFactory(fieldValue?: FormFieldMetadataValueObject | any, label?: boolean): any { + public modelFactory(fieldValue?: FormFieldMetadataValueObject, label?: boolean): any { if (this.configData.selectableMetadata[0].controlledVocabulary) { const lookupModelConfig: DynamicLookupModelConfig = this.initModel(null, label); diff --git a/src/app/shared/form/builder/parsers/lookup-name-field-parser.spec.ts b/src/app/shared/form/builder/parsers/lookup-name-field-parser.spec.ts index c6e8df8985d..3384071f6ee 100644 --- a/src/app/shared/form/builder/parsers/lookup-name-field-parser.spec.ts +++ b/src/app/shared/form/builder/parsers/lookup-name-field-parser.spec.ts @@ -1,3 +1,5 @@ +import { getMockTranslateService } from 'src/app/shared/mocks/translate.service.mock'; + import { DynamicLookupNameModel } from '../ds-dynamic-form-ui/models/lookup/dynamic-lookup-name.model'; import { FormFieldModel } from '../models/form-field.model'; import { FormFieldMetadataValueObject } from '../models/form-field-metadata-value.model'; @@ -7,6 +9,7 @@ import { ParserOptions } from './parser-options'; describe('LookupNameFieldParser test suite', () => { let field: FormFieldModel; let initFormValues = {}; + let translateService = getMockTranslateService(); const submissionId = '1234'; const parserOptions: ParserOptions = { @@ -38,13 +41,13 @@ describe('LookupNameFieldParser test suite', () => { }); it('should init parser properly', () => { - const parser = new LookupNameFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new LookupNameFieldParser(submissionId, field, initFormValues, parserOptions, translateService); expect(parser instanceof LookupNameFieldParser).toBe(true); }); it('should return a DynamicLookupNameModel object when repeatable option is false', () => { - const parser = new LookupNameFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new LookupNameFieldParser(submissionId, field, initFormValues, parserOptions, translateService); const fieldModel = parser.parse(); @@ -57,7 +60,7 @@ describe('LookupNameFieldParser test suite', () => { }; const expectedValue = new FormFieldMetadataValueObject('test author'); - const parser = new LookupNameFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new LookupNameFieldParser(submissionId, field, initFormValues, parserOptions, translateService); const fieldModel = parser.parse(); diff --git a/src/app/shared/form/builder/parsers/lookup-name-field-parser.ts b/src/app/shared/form/builder/parsers/lookup-name-field-parser.ts index 0701d7cb7d4..ba7f2f0235b 100644 --- a/src/app/shared/form/builder/parsers/lookup-name-field-parser.ts +++ b/src/app/shared/form/builder/parsers/lookup-name-field-parser.ts @@ -7,7 +7,7 @@ import { FieldParser } from './field-parser'; export class LookupNameFieldParser extends FieldParser { - public modelFactory(fieldValue?: FormFieldMetadataValueObject | any, label?: boolean): any { + public modelFactory(fieldValue?: FormFieldMetadataValueObject, label?: boolean): any { if (this.configData.selectableMetadata[0].controlledVocabulary) { const lookupModelConfig: DynamicLookupNameModelConfig = this.initModel(null, label); diff --git a/src/app/shared/form/builder/parsers/name-field-parser.spec.ts b/src/app/shared/form/builder/parsers/name-field-parser.spec.ts index 7184e67e96f..80b3f9ee83a 100644 --- a/src/app/shared/form/builder/parsers/name-field-parser.spec.ts +++ b/src/app/shared/form/builder/parsers/name-field-parser.spec.ts @@ -1,3 +1,5 @@ +import { getMockTranslateService } from 'src/app/shared/mocks/translate.service.mock'; + import { DynamicConcatModel } from '../ds-dynamic-form-ui/models/ds-dynamic-concat.model'; import { FormFieldModel } from '../models/form-field.model'; import { FormFieldMetadataValueObject } from '../models/form-field-metadata-value.model'; @@ -9,6 +11,7 @@ describe('NameFieldParser test suite', () => { let field2: FormFieldModel; let field3: FormFieldModel; let initFormValues: any = {}; + let translateService = getMockTranslateService(); const submissionId = '1234'; const parserOptions: ParserOptions = { @@ -71,13 +74,13 @@ describe('NameFieldParser test suite', () => { }); it('should init parser properly', () => { - const parser = new NameFieldParser(submissionId, field1, initFormValues, parserOptions); + const parser = new NameFieldParser(submissionId, field1, initFormValues, parserOptions, translateService); expect(parser instanceof NameFieldParser).toBe(true); }); it('should return a DynamicConcatModel object when repeatable option is false', () => { - const parser = new NameFieldParser(submissionId, field2, initFormValues, parserOptions); + const parser = new NameFieldParser(submissionId, field2, initFormValues, parserOptions, translateService); const fieldModel = parser.parse(); @@ -85,7 +88,7 @@ describe('NameFieldParser test suite', () => { }); it('should return a DynamicConcatModel object with the correct separator', () => { - const parser = new NameFieldParser(submissionId, field2, initFormValues, parserOptions); + const parser = new NameFieldParser(submissionId, field2, initFormValues, parserOptions, translateService); const fieldModel = parser.parse(); @@ -98,7 +101,7 @@ describe('NameFieldParser test suite', () => { }; const expectedValue = new FormFieldMetadataValueObject('test, name', undefined, undefined, 'test'); - const parser = new NameFieldParser(submissionId, field1, initFormValues, parserOptions); + const parser = new NameFieldParser(submissionId, field1, initFormValues, parserOptions, translateService); const fieldModel = parser.parse(); diff --git a/src/app/shared/form/builder/parsers/name-field-parser.ts b/src/app/shared/form/builder/parsers/name-field-parser.ts index 1c0fbd6d01e..4bb36ad4d03 100644 --- a/src/app/shared/form/builder/parsers/name-field-parser.ts +++ b/src/app/shared/form/builder/parsers/name-field-parser.ts @@ -1,4 +1,5 @@ import { Inject } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; import { FormFieldModel } from '../models/form-field.model'; import { ConcatFieldParser } from './concat-field-parser'; @@ -17,7 +18,8 @@ export class NameFieldParser extends ConcatFieldParser { @Inject(CONFIG_DATA) configData: FormFieldModel, @Inject(INIT_FORM_VALUES) initFormValues, @Inject(PARSER_OPTIONS) parserOptions: ParserOptions, + translate: TranslateService, ) { - super(submissionId, configData, initFormValues, parserOptions, ',', 'form.last-name', 'form.first-name'); + super(submissionId, configData, initFormValues, parserOptions, translate, ',', 'form.last-name', 'form.first-name'); } } diff --git a/src/app/shared/form/builder/parsers/onebox-field-parser.spec.ts b/src/app/shared/form/builder/parsers/onebox-field-parser.spec.ts index 467431d963c..b2a50395e1a 100644 --- a/src/app/shared/form/builder/parsers/onebox-field-parser.spec.ts +++ b/src/app/shared/form/builder/parsers/onebox-field-parser.spec.ts @@ -1,3 +1,5 @@ +import { getMockTranslateService } from 'src/app/shared/mocks/translate.service.mock'; + import { DsDynamicInputModel } from '../ds-dynamic-form-ui/models/ds-dynamic-input.model'; import { DynamicQualdropModel } from '../ds-dynamic-form-ui/models/ds-dynamic-qualdrop.model'; import { DynamicOneboxModel } from '../ds-dynamic-form-ui/models/onebox/dynamic-onebox.model'; @@ -10,6 +12,7 @@ describe('OneboxFieldParser test suite', () => { let field1: FormFieldModel; let field2: FormFieldModel; let field3: FormFieldModel; + let translateService = getMockTranslateService(); const submissionId = '1234'; const initFormValues = {}; @@ -73,13 +76,13 @@ describe('OneboxFieldParser test suite', () => { }); it('should init parser properly', () => { - const parser = new OneboxFieldParser(submissionId, field1, initFormValues, parserOptions); + const parser = new OneboxFieldParser(submissionId, field1, initFormValues, parserOptions, translateService); expect(parser instanceof OneboxFieldParser).toBe(true); }); it('should return a DynamicQualdropModel object when selectableMetadata is multiple', () => { - const parser = new OneboxFieldParser(submissionId, field2, initFormValues, parserOptions); + const parser = new OneboxFieldParser(submissionId, field2, initFormValues, parserOptions, translateService); const fieldModel = parser.parse(); @@ -87,7 +90,7 @@ describe('OneboxFieldParser test suite', () => { }); it('should return a DsDynamicInputModel object when selectableMetadata is not multiple', () => { - const parser = new OneboxFieldParser(submissionId, field3, initFormValues, parserOptions); + const parser = new OneboxFieldParser(submissionId, field3, initFormValues, parserOptions, translateService); const fieldModel = parser.parse(); @@ -95,7 +98,7 @@ describe('OneboxFieldParser test suite', () => { }); it('should return a DynamicOneboxModel object when selectableMetadata has authority', () => { - const parser = new OneboxFieldParser(submissionId, field1, initFormValues, parserOptions); + const parser = new OneboxFieldParser(submissionId, field1, initFormValues, parserOptions, translateService); const fieldModel = parser.parse(); @@ -124,7 +127,7 @@ describe('OneboxFieldParser test suite', () => { languageCodes: [], } as FormFieldModel; - parser = new OneboxFieldParser(submissionId, regexField, initFormValues, parserOptions); + parser = new OneboxFieldParser(submissionId, regexField, initFormValues, parserOptions, translateService); fieldModel = parser.parse(); }); diff --git a/src/app/shared/form/builder/parsers/onebox-field-parser.ts b/src/app/shared/form/builder/parsers/onebox-field-parser.ts index 2b994146c72..9c5ef7423e5 100644 --- a/src/app/shared/form/builder/parsers/onebox-field-parser.ts +++ b/src/app/shared/form/builder/parsers/onebox-field-parser.ts @@ -24,7 +24,7 @@ import { FieldParser } from './field-parser'; export class OneboxFieldParser extends FieldParser { - public modelFactory(fieldValue?: FormFieldMetadataValueObject | any, label?: boolean): any { + public modelFactory(fieldValue?: FormFieldMetadataValueObject, label?: boolean): any { if (this.configData.selectableMetadata.length > 1) { // Case Qualdrop Model const clsGroup = { diff --git a/src/app/shared/form/builder/parsers/parser-factory.ts b/src/app/shared/form/builder/parsers/parser-factory.ts index 439baf4d4b1..a56a27d77f7 100644 --- a/src/app/shared/form/builder/parsers/parser-factory.ts +++ b/src/app/shared/form/builder/parsers/parser-factory.ts @@ -1,4 +1,5 @@ import { StaticProvider } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; import { DateFieldParser } from './date-field-parser'; import { DisabledFieldParser } from './disabled-field-parser'; @@ -26,6 +27,7 @@ const fieldParserDeps = [ CONFIG_DATA, INIT_FORM_VALUES, PARSER_OPTIONS, + TranslateService, ]; /** diff --git a/src/app/shared/form/builder/parsers/relation-group-field-parser.spec.ts b/src/app/shared/form/builder/parsers/relation-group-field-parser.spec.ts index ef4f0f709a5..9eeeeea35c3 100644 --- a/src/app/shared/form/builder/parsers/relation-group-field-parser.spec.ts +++ b/src/app/shared/form/builder/parsers/relation-group-field-parser.spec.ts @@ -1,3 +1,5 @@ +import { getMockTranslateService } from 'src/app/shared/mocks/translate.service.mock'; + import { DynamicRelationGroupModel } from '../ds-dynamic-form-ui/models/relation-group/dynamic-relation-group.model'; import { FormFieldModel } from '../models/form-field.model'; import { FormFieldMetadataValueObject } from '../models/form-field-metadata-value.model'; @@ -7,6 +9,7 @@ import { RelationGroupFieldParser } from './relation-group-field-parser'; describe('RelationGroupFieldParser test suite', () => { let field: FormFieldModel; let initFormValues = {}; + let translateService = getMockTranslateService(); const submissionId = '1234'; const parserOptions: ParserOptions = { @@ -73,13 +76,13 @@ describe('RelationGroupFieldParser test suite', () => { }); it('should init parser properly', () => { - const parser = new RelationGroupFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new RelationGroupFieldParser(submissionId, field, initFormValues, parserOptions, translateService); expect(parser instanceof RelationGroupFieldParser).toBe(true); }); it('should return a DynamicRelationGroupModel object', () => { - const parser = new RelationGroupFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new RelationGroupFieldParser(submissionId, field, initFormValues, parserOptions, translateService); const fieldModel = parser.parse(); @@ -88,7 +91,7 @@ describe('RelationGroupFieldParser test suite', () => { it('should throw when rows configuration is empty', () => { field.rows = null; - const parser = new RelationGroupFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new RelationGroupFieldParser(submissionId, field, initFormValues, parserOptions, translateService); expect(() => parser.parse()) .toThrow(); @@ -99,7 +102,7 @@ describe('RelationGroupFieldParser test suite', () => { author: [new FormFieldMetadataValueObject('test author')], affiliation: [new FormFieldMetadataValueObject('test affiliation')], }; - const parser = new RelationGroupFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new RelationGroupFieldParser(submissionId, field, initFormValues, parserOptions, translateService); const fieldModel = parser.parse(); const expectedValue = [{ diff --git a/src/app/shared/form/builder/parsers/relation-group-field-parser.ts b/src/app/shared/form/builder/parsers/relation-group-field-parser.ts index 112bfdaf243..30401b20efc 100644 --- a/src/app/shared/form/builder/parsers/relation-group-field-parser.ts +++ b/src/app/shared/form/builder/parsers/relation-group-field-parser.ts @@ -11,7 +11,7 @@ import { FieldParser } from './field-parser'; export class RelationGroupFieldParser extends FieldParser { - public modelFactory(fieldValue?: FormFieldMetadataValueObject | any, label?: boolean) { + public modelFactory(fieldValue?: FormFieldMetadataValueObject, label?: boolean) { const modelConfiguration: DynamicRelationGroupModelConfig = this.initModel(null, label); modelConfiguration.submissionId = this.submissionId; diff --git a/src/app/shared/form/builder/parsers/row-parser.spec.ts b/src/app/shared/form/builder/parsers/row-parser.spec.ts index 9fde7cc8392..d87931a4880 100644 --- a/src/app/shared/form/builder/parsers/row-parser.spec.ts +++ b/src/app/shared/form/builder/parsers/row-parser.spec.ts @@ -1,3 +1,7 @@ +import { Injector } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { getMockTranslateService } from 'src/app/shared/mocks/translate.service.mock'; + import { FormRowModel } from '../../../../core/config/models/config-submission-form.model'; import { DynamicRowArrayModel } from '../ds-dynamic-form-ui/models/ds-dynamic-row-array-model'; import { DynamicRowGroupModel } from '../ds-dynamic-form-ui/models/ds-dynamic-row-group-model'; @@ -16,6 +20,7 @@ describe('RowParser test suite', () => { let row8: FormRowModel; let row9: FormRowModel; let row10: FormRowModel; + let injector: Injector; const submissionId = '1234'; const scopeUUID = 'testScopeUUID'; @@ -25,6 +30,12 @@ describe('RowParser test suite', () => { const typeField = 'dc_type'; beforeEach(() => { + let translateService = getMockTranslateService(); + injector = Injector.create({ + providers: [ + { provide: TranslateService, useValue: translateService }, + ], + }); row1 = { fields: [ { @@ -330,14 +341,14 @@ describe('RowParser test suite', () => { }); it('should init parser properly', () => { - const parser = new RowParser(undefined); + const parser = new RowParser(injector); expect(parser instanceof RowParser).toBe(true); }); describe('parse', () => { it('should return a DynamicRowGroupModel object', () => { - const parser = new RowParser(undefined); + const parser = new RowParser(injector); const rowModel = parser.parse(submissionId, row1, scopeUUID, initFormValues, submissionScope, readOnly, typeField); @@ -345,7 +356,7 @@ describe('RowParser test suite', () => { }); it('should return a row with three fields', () => { - const parser = new RowParser(undefined); + const parser = new RowParser(injector); const rowModel = parser.parse(submissionId, row1, scopeUUID, initFormValues, submissionScope, readOnly, typeField); @@ -353,7 +364,7 @@ describe('RowParser test suite', () => { }); it('should return a DynamicRowArrayModel object', () => { - const parser = new RowParser(undefined); + const parser = new RowParser(injector); const rowModel = parser.parse(submissionId, row2, scopeUUID, initFormValues, submissionScope, readOnly, typeField); @@ -361,7 +372,7 @@ describe('RowParser test suite', () => { }); it('should return a row that contains only scoped fields', () => { - const parser = new RowParser(undefined); + const parser = new RowParser(injector); const rowModel = parser.parse(submissionId, row3, scopeUUID, initFormValues, submissionScope, readOnly, typeField); @@ -369,7 +380,7 @@ describe('RowParser test suite', () => { }); it('should be able to parse a dropdown combo field', () => { - const parser = new RowParser(undefined); + const parser = new RowParser(injector); const rowModel = parser.parse(submissionId, row4, scopeUUID, initFormValues, submissionScope, readOnly, typeField); @@ -377,7 +388,7 @@ describe('RowParser test suite', () => { }); it('should be able to parse a lookup-name field', () => { - const parser = new RowParser(undefined); + const parser = new RowParser(injector); const rowModel = parser.parse(submissionId, row5, scopeUUID, initFormValues, submissionScope, readOnly, typeField); @@ -385,7 +396,7 @@ describe('RowParser test suite', () => { }); it('should be able to parse a list field', () => { - const parser = new RowParser(undefined); + const parser = new RowParser(injector); const rowModel = parser.parse(submissionId, row6, scopeUUID, initFormValues, submissionScope, readOnly, typeField); @@ -393,7 +404,7 @@ describe('RowParser test suite', () => { }); it('should be able to parse a date field', () => { - const parser = new RowParser(undefined); + const parser = new RowParser(injector); const rowModel = parser.parse(submissionId, row7, scopeUUID, initFormValues, submissionScope, readOnly, typeField); @@ -401,7 +412,7 @@ describe('RowParser test suite', () => { }); it('should be able to parse a tag field', () => { - const parser = new RowParser(undefined); + const parser = new RowParser(injector); const rowModel = parser.parse(submissionId, row8, scopeUUID, initFormValues, submissionScope, readOnly, typeField); @@ -409,7 +420,7 @@ describe('RowParser test suite', () => { }); it('should be able to parse a textarea field', () => { - const parser = new RowParser(undefined); + const parser = new RowParser(injector); const rowModel = parser.parse(submissionId, row9, scopeUUID, initFormValues, submissionScope, readOnly, typeField); @@ -417,7 +428,7 @@ describe('RowParser test suite', () => { }); it('should be able to parse a group field', () => { - const parser = new RowParser(undefined); + const parser = new RowParser(injector); const rowModel = parser.parse(submissionId, row10, scopeUUID, initFormValues, submissionScope, readOnly, typeField); diff --git a/src/app/shared/form/builder/parsers/row-parser.ts b/src/app/shared/form/builder/parsers/row-parser.ts index 97c9cb82576..b4febfc47ff 100644 --- a/src/app/shared/form/builder/parsers/row-parser.ts +++ b/src/app/shared/form/builder/parsers/row-parser.ts @@ -154,9 +154,9 @@ export class RowParser { && ( isEmpty(visibility) && ( - submissionScope === SubmissionScopeType.WorkspaceItem && scope !== SubmissionFieldScopeType.WorkspaceItem + submissionScope === SubmissionScopeType.WorkspaceItem.valueOf() && scope !== SubmissionFieldScopeType.WorkspaceItem.valueOf() || - submissionScope === SubmissionScopeType.WorkflowItem && scope !== SubmissionFieldScopeType.WorkflowItem + submissionScope === SubmissionScopeType.WorkflowItem.valueOf() && scope !== SubmissionFieldScopeType.WorkflowItem.valueOf() ) ); } diff --git a/src/app/shared/form/builder/parsers/series-field-parser.spec.ts b/src/app/shared/form/builder/parsers/series-field-parser.spec.ts index d4b37e5d7f4..8141bf23e06 100644 --- a/src/app/shared/form/builder/parsers/series-field-parser.spec.ts +++ b/src/app/shared/form/builder/parsers/series-field-parser.spec.ts @@ -1,3 +1,5 @@ +import { getMockTranslateService } from 'src/app/shared/mocks/translate.service.mock'; + import { DynamicConcatModel } from '../ds-dynamic-form-ui/models/ds-dynamic-concat.model'; import { FormFieldModel } from '../models/form-field.model'; import { FormFieldMetadataValueObject } from '../models/form-field-metadata-value.model'; @@ -7,6 +9,7 @@ import { SeriesFieldParser } from './series-field-parser'; describe('SeriesFieldParser test suite', () => { let field: FormFieldModel; let initFormValues: any = {}; + let translateService = getMockTranslateService(); const submissionId = '1234'; const parserOptions: ParserOptions = { @@ -34,13 +37,13 @@ describe('SeriesFieldParser test suite', () => { }); it('should init parser properly', () => { - const parser = new SeriesFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new SeriesFieldParser(submissionId, field, initFormValues, parserOptions, translateService); expect(parser instanceof SeriesFieldParser).toBe(true); }); it('should return a DynamicConcatModel object when repeatable option is false', () => { - const parser = new SeriesFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new SeriesFieldParser(submissionId, field, initFormValues, parserOptions, translateService); const fieldModel = parser.parse(); @@ -48,7 +51,7 @@ describe('SeriesFieldParser test suite', () => { }); it('should return a DynamicConcatModel object with the correct separator', () => { - const parser = new SeriesFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new SeriesFieldParser(submissionId, field, initFormValues, parserOptions, translateService); const fieldModel = parser.parse(); @@ -61,7 +64,7 @@ describe('SeriesFieldParser test suite', () => { }; const expectedValue = new FormFieldMetadataValueObject('test; series', undefined, undefined, 'test'); - const parser = new SeriesFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new SeriesFieldParser(submissionId, field, initFormValues, parserOptions, translateService); const fieldModel = parser.parse(); diff --git a/src/app/shared/form/builder/parsers/series-field-parser.ts b/src/app/shared/form/builder/parsers/series-field-parser.ts index ce85d07d298..196718ab87c 100644 --- a/src/app/shared/form/builder/parsers/series-field-parser.ts +++ b/src/app/shared/form/builder/parsers/series-field-parser.ts @@ -1,4 +1,5 @@ import { Inject } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; import { FormFieldModel } from '../models/form-field.model'; import { ConcatFieldParser } from './concat-field-parser'; @@ -17,7 +18,8 @@ export class SeriesFieldParser extends ConcatFieldParser { @Inject(CONFIG_DATA) configData: FormFieldModel, @Inject(INIT_FORM_VALUES) initFormValues, @Inject(PARSER_OPTIONS) parserOptions: ParserOptions, + translate: TranslateService, ) { - super(submissionId, configData, initFormValues, parserOptions, ';'); + super(submissionId, configData, initFormValues, parserOptions, translate, ';'); } } diff --git a/src/app/shared/form/builder/parsers/tag-field-parser.spec.ts b/src/app/shared/form/builder/parsers/tag-field-parser.spec.ts index 571d06d983a..303d63cad5d 100644 --- a/src/app/shared/form/builder/parsers/tag-field-parser.spec.ts +++ b/src/app/shared/form/builder/parsers/tag-field-parser.spec.ts @@ -1,3 +1,5 @@ +import { getMockTranslateService } from 'src/app/shared/mocks/translate.service.mock'; + import { DynamicTagModel } from '../ds-dynamic-form-ui/models/tag/dynamic-tag.model'; import { FormFieldModel } from '../models/form-field.model'; import { FormFieldMetadataValueObject } from '../models/form-field-metadata-value.model'; @@ -7,6 +9,7 @@ import { TagFieldParser } from './tag-field-parser'; describe('TagFieldParser test suite', () => { let field: FormFieldModel; let initFormValues: any = {}; + let translateService = getMockTranslateService(); const submissionId = '1234'; const parserOptions: ParserOptions = { @@ -38,13 +41,13 @@ describe('TagFieldParser test suite', () => { }); it('should init parser properly', () => { - const parser = new TagFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new TagFieldParser(submissionId, field, initFormValues, parserOptions, translateService); expect(parser instanceof TagFieldParser).toBe(true); }); it('should return a DynamicTagModel object when repeatable option is false', () => { - const parser = new TagFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new TagFieldParser(submissionId, field, initFormValues, parserOptions, translateService); const fieldModel = parser.parse(); @@ -59,7 +62,7 @@ describe('TagFieldParser test suite', () => { ], }; - const parser = new TagFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new TagFieldParser(submissionId, field, initFormValues, parserOptions, translateService); const fieldModel = parser.parse(); diff --git a/src/app/shared/form/builder/parsers/tag-field-parser.ts b/src/app/shared/form/builder/parsers/tag-field-parser.ts index 5c3f2e60bc3..6534b9dc5fa 100644 --- a/src/app/shared/form/builder/parsers/tag-field-parser.ts +++ b/src/app/shared/form/builder/parsers/tag-field-parser.ts @@ -7,7 +7,7 @@ import { FieldParser } from './field-parser'; export class TagFieldParser extends FieldParser { - public modelFactory(fieldValue?: FormFieldMetadataValueObject | any, label?: boolean): any { + public modelFactory(fieldValue?: FormFieldMetadataValueObject, label?: boolean): any { const tagModelConfig: DynamicTagModelConfig = this.initModel(null, label); if (this.configData.selectableMetadata[0].controlledVocabulary && this.configData.selectableMetadata[0].controlledVocabulary.length > 0) { diff --git a/src/app/shared/form/builder/parsers/textarea-field-parser.spec.ts b/src/app/shared/form/builder/parsers/textarea-field-parser.spec.ts index 95fef2103c7..cfab7c36e31 100644 --- a/src/app/shared/form/builder/parsers/textarea-field-parser.spec.ts +++ b/src/app/shared/form/builder/parsers/textarea-field-parser.spec.ts @@ -1,3 +1,5 @@ +import { getMockTranslateService } from 'src/app/shared/mocks/translate.service.mock'; + import { DsDynamicTextAreaModel } from '../ds-dynamic-form-ui/models/ds-dynamic-textarea.model'; import { FormFieldModel } from '../models/form-field.model'; import { FormFieldMetadataValueObject } from '../models/form-field-metadata-value.model'; @@ -7,6 +9,7 @@ import { TextareaFieldParser } from './textarea-field-parser'; describe('TextareaFieldParser test suite', () => { let field: FormFieldModel; let initFormValues: any = {}; + let translateService = getMockTranslateService(); const submissionId = '1234'; const parserOptions: ParserOptions = { @@ -36,13 +39,13 @@ describe('TextareaFieldParser test suite', () => { }); it('should init parser properly', () => { - const parser = new TextareaFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new TextareaFieldParser(submissionId, field, initFormValues, parserOptions, translateService); expect(parser instanceof TextareaFieldParser).toBe(true); }); it('should return a DsDynamicTextAreaModel object when repeatable option is false', () => { - const parser = new TextareaFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new TextareaFieldParser(submissionId, field, initFormValues, parserOptions, translateService); const fieldModel = parser.parse(); @@ -57,7 +60,7 @@ describe('TextareaFieldParser test suite', () => { }; const expectedValue = 'test description'; - const parser = new TextareaFieldParser(submissionId, field, initFormValues, parserOptions); + const parser = new TextareaFieldParser(submissionId, field, initFormValues, parserOptions, translateService); const fieldModel = parser.parse(); diff --git a/src/app/shared/form/builder/parsers/textarea-field-parser.ts b/src/app/shared/form/builder/parsers/textarea-field-parser.ts index c253899b3d7..a19fa0ccd27 100644 --- a/src/app/shared/form/builder/parsers/textarea-field-parser.ts +++ b/src/app/shared/form/builder/parsers/textarea-field-parser.ts @@ -8,7 +8,7 @@ import { FieldParser } from './field-parser'; export class TextareaFieldParser extends FieldParser { - public modelFactory(fieldValue?: FormFieldMetadataValueObject | any, label?: boolean): any { + public modelFactory(fieldValue?: FormFieldMetadataValueObject, label?: boolean): any { const textAreaModelConfig: DsDynamicTextAreaModelConfig = this.initModel(null, label); const layout = { diff --git a/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.html b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.html index 54a1992b976..412c732b019 100644 --- a/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.html +++ b/src/app/shared/form/vocabulary-treeview/vocabulary-treeview.component.html @@ -22,7 +22,7 @@

    - +

    {{'vocabulary-treeview.search.no-result' | translate}}

    diff --git a/src/app/shared/idle-modal/idle-modal.component.ts b/src/app/shared/idle-modal/idle-modal.component.ts index b8633147da5..112ed7719cb 100644 --- a/src/app/shared/idle-modal/idle-modal.component.ts +++ b/src/app/shared/idle-modal/idle-modal.component.ts @@ -37,7 +37,7 @@ export class IdleModalComponent implements OnInit { * An event fired when the modal is closed */ @Output() - response = new EventEmitter(); + response = new EventEmitter(); constructor(private activeModal: NgbActiveModal, private authService: AuthService, diff --git a/src/app/shared/lang-switch/lang-switch.component.ts b/src/app/shared/lang-switch/lang-switch.component.ts index c29b3f375a2..3acb1694194 100644 --- a/src/app/shared/lang-switch/lang-switch.component.ts +++ b/src/app/shared/lang-switch/lang-switch.component.ts @@ -18,7 +18,7 @@ import { environment } from '../../../environments/environment'; import { LocaleService } from '../../core/locale/locale.service'; @Component({ - selector: 'ds-lang-switch', + selector: 'ds-base-lang-switch', styleUrls: ['lang-switch.component.scss'], templateUrl: 'lang-switch.component.html', standalone: true, diff --git a/src/app/shared/lang-switch/themed-lang-switch.component.ts b/src/app/shared/lang-switch/themed-lang-switch.component.ts index 2e4d7f50e54..685d0f1799d 100644 --- a/src/app/shared/lang-switch/themed-lang-switch.component.ts +++ b/src/app/shared/lang-switch/themed-lang-switch.component.ts @@ -7,10 +7,11 @@ import { LangSwitchComponent } from './lang-switch.component'; * Themed wrapper for {@link LangSwitchComponent} */ @Component({ - selector: 'ds-themed-lang-switch', + selector: 'ds-lang-switch', styleUrls: [], templateUrl: '../theme-support/themed.component.html', standalone: true, + imports: [LangSwitchComponent], }) export class ThemedLangSwitchComponent extends ThemedComponent { diff --git a/src/app/shared/loading/loading.component.ts b/src/app/shared/loading/loading.component.ts index 03846fe3946..b982af42082 100644 --- a/src/app/shared/loading/loading.component.ts +++ b/src/app/shared/loading/loading.component.ts @@ -11,7 +11,7 @@ import { Subscription } from 'rxjs'; import { hasValue } from '../empty.util'; @Component({ - selector: 'ds-loading', + selector: 'ds-base-loading', styleUrls: ['./loading.component.scss'], templateUrl: './loading.component.html', standalone: true, diff --git a/src/app/shared/loading/themed-loading.component.ts b/src/app/shared/loading/themed-loading.component.ts index 983bdadff0f..d16e0b988e7 100644 --- a/src/app/shared/loading/themed-loading.component.ts +++ b/src/app/shared/loading/themed-loading.component.ts @@ -12,10 +12,11 @@ import { LoadingComponent } from './loading.component'; * Themed wrapper for LoadingComponent */ @Component({ - selector: 'ds-themed-loading', + selector: 'ds-loading', styleUrls: [], templateUrl: '../../shared/theme-support/themed.component.html', standalone: true, + imports: [LoadingComponent], }) export class ThemedLoadingComponent extends ThemedComponent { diff --git a/src/app/shared/log-in/log-in.component.html b/src/app/shared/log-in/log-in.component.html index d80513d5d04..309e226772e 100644 --- a/src/app/shared/log-in/log-in.component.html +++ b/src/app/shared/log-in/log-in.component.html @@ -1,4 +1,4 @@ - +