Compare commits

..
84 Commits
Author SHA1 Message Date
AleksanderSklorz d1bda4f898 Release 8.4.1 (#11827)
* Release 8.4.1

* Release 8.4.1
2026-04-21 12:01:35 +02:00
AleksanderSklorz 03f04bf118 Release 8.4.0 (#11826)
* Release 8.4.0

* Release 8.4.0

* Release 8.4.0

* Release 8.4.0
2026-04-21 11:08:40 +02:00
dependabot[bot] 0dd3e454f5 build(deps): bump actions/cache from 5.0.4 to 5.0.5 in /.github/actions/download-node-modules-and-artifacts (#11820)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-20 14:32:15 +02:00
dependabot[bot] 025e3cf636 build(deps): bump Alfresco/alfresco-build-tools from 17.1.0 to 17.2.0 in /.github/actions/setup (#11821)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-20 14:32:01 +02:00
dependabot[bot] 07455c4217 build(deps): bump actions/cache from 5.0.4 to 5.0.5 in /.github/actions/upload-node-modules-and-artifacts (#11822)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-20 14:31:47 +02:00
dependabot[bot] 9beeaeed8d build(deps): bump actions/cache from 5.0.4 to 5.0.5 in /.github/actions/setup (#11823)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-20 14:31:32 +02:00
dependabot[bot] a86f0790da build(deps): bump github/codeql-action from 4.35.1 to 4.35.2 (#11824)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-20 14:31:09 +02:00
dependabot[bot] 86e8fb75d0 build(deps): bump Alfresco/alfresco-build-tools from 17.1.0 to 17.2.0 (#11825)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-20 14:30:43 +02:00
Dominik Iwanek af95723f30 [ACS-11589] [ACA] info drawer test-area does not show full text (#11816) 2026-04-20 10:33:14 +02:00
Denys Vuika d70ae599c7 Fix security vulnerabilities in npm dependencies (#11815)
* Update package dependencies: remove unused 'picomatch' and 'minimatch' modules from package-lock.json, and add specific versions for 'picomatch', 'minimatch', 'path-to-regexp', and 'serialize-javascript' in package.json.

* Upgrade nx and @nx/workspace to fix minimatch vulnerabilities

- Upgrade nx from 22.4.1 to 22.6.3
- Upgrade @nx/workspace from 22.4.5 to 22.6.3
- Remove minimatch override to maintain Karma compatibility

This resolves the high severity minimatch vulnerabilities while
keeping tests functional.

* Refactor nx.json: Consolidate sharedGlobals array and add analytics flag

- Merged multiple lines in the sharedGlobals array for better readability.
- Added an analytics flag set to false for configuration.

* Update package dependencies: bump @nx packages to version 22.6.5 [ci:force]

* Add test specifications for feature flags and user initial pipe [ci:force]

- Introduced new selectors for feature flag components in `features.directive.spec.ts` and `not-features.directive.spec.ts`.
- Added an injectable sanitizer class in `user-initial.pipe.spec.ts` to enhance testing capabilities.
- Created a new log file `out.txt` to capture Karma test execution details and warnings.
2026-04-16 13:35:42 +01:00
Alfresco BuildandCrowdin Bot e2ae224924 New Crowdin translations by GitHub Action (#11810)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2026-04-16 07:45:07 -04:00
Denys Vuika 07c6a4d923 Remove jasmine-spec-reporter dependency from package.json and package-lock.json (#11814) 2026-04-16 12:23:50 +01:00
Denys Vuika 6fc8dda887 Remove mocha and jasmine-ajax dependencies (#11813) 2026-04-16 10:20:49 +01:00
dependabot[bot] b550712160 build(deps): bump follow-redirects from 1.15.11 to 1.16.0 (#11812)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.11 to 1.16.0.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.11...v1.16.0)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-version: 1.16.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-15 20:10:16 +01:00
dependabot[bot] 969bb4455e build(deps): bump vite, @angular-devkit/build-angular and @angular/build (#11811)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) to 6.4.2 and updates ancestor dependencies [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite), [@angular-devkit/build-angular](https://github.com/angular/angular-cli) and [@angular/build](https://github.com/angular/angular-cli). These dependencies need to be updated together.


Updates `vite` from 6.4.1 to 6.4.2
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v6.4.2/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.4.2/packages/vite)

Updates `@angular-devkit/build-angular` from 19.2.22 to 19.2.24
- [Release notes](https://github.com/angular/angular-cli/releases)
- [Changelog](https://github.com/angular/angular-cli/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular-cli/compare/v19.2.22...v19.2.24)

Updates `@angular/build` from 19.2.22 to 19.2.24
- [Release notes](https://github.com/angular/angular-cli/releases)
- [Changelog](https://github.com/angular/angular-cli/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular-cli/compare/v19.2.22...v19.2.24)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 6.4.2
  dependency-type: indirect
- dependency-name: "@angular-devkit/build-angular"
  dependency-version: 19.2.24
  dependency-type: direct:development
- dependency-name: "@angular/build"
  dependency-version: 19.2.24
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-15 20:09:40 +01:00
David Olson 48eb258311 AAE-44184 Colspan setting on form fields is ignored or not properly applied (#11800)
* AAE-44184 Colspan setting on form fields is ignored or not properly applied

* AAE-44184 Better handling of empty columns

* AAE-44184 Fixing stale adf-form-field instances

* AAE-44184 Consolidating duplicate code
2026-04-15 10:46:38 -05:00
Michal Kinas 32850a0ce8 [MNT-25185] Display authority name instead of id if provided (#11809)
* [MNT-25185] Display authority name instead of id if provided

* [MNT-25185] CR fixes
2026-04-15 10:12:04 +02:00
Anton Ramanovich 8a6bcac29e [ACS-11506]: moved aria-live region (#11808)
* [ACS-11506]: moved aria-live region

* [ACS-11506]: regression tests
2026-04-14 10:01:36 +02:00
Alfresco BuildandCrowdin Bot 7a70ae8eb6 New Crowdin translations by GitHub Action (#11796)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2026-04-13 14:01:46 +01:00
dependabot[bot] 1ee94fcb2c build(deps): bump axios from 1.13.6 to 1.15.0 (#11802)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-13 10:13:53 +02:00
dependabot[bot] c1a6c28a29 build(deps): bump Alfresco/alfresco-build-tools from 17.0.0 to 17.1.0 in /.github/actions/setup (#11803)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-13 10:09:35 +02:00
dependabot[bot] 747da93b0f build(deps): bump actions/github-script from 8.0.0 to 9.0.0 (#11804)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-13 10:09:22 +02:00
dependabot[bot] 714434f755 build(deps): bump hyland/github-actions-ensure-sha-pinned-actions from 1.2.0 to 2.0.0 (#11805)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-13 10:08:03 +02:00
dependabot[bot] 17bedfd940 build(deps): bump Alfresco/alfresco-build-tools from 17.0.0 to 17.1.0 (#11806)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-13 10:07:43 +02:00
Wojciech Duda 8ce0561ef5 AAE-44086 Unify styling and coloring of errors in forms (#11797) 2026-04-08 10:24:22 +00:00
dependabot[bot] 0e063beb40 build(deps): bump lodash-es from 4.17.23 to 4.18.1 (#11789)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-07 19:49:21 +02:00
dependabot[bot] 6b15cd05c7 build(deps): bump lodash from 4.17.23 to 4.18.1 (#11790)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-07 19:48:41 +02:00
dependabot[bot] 868a9204f4 build(deps): bump Alfresco/alfresco-build-tools from 15.12.1 to 17.0.0 in /.github/actions/setup (#11794)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-07 19:38:56 +02:00
dependabot[bot] bddf2d9cf0 build(deps): bump Alfresco/alfresco-build-tools from 15.12.1 to 17.0.0 (#11795)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-07 19:38:41 +02:00
Darren Thornton 69a9dc1386 AAE-44002 Allow user input for date and datetime fields (#11791) 2026-04-06 13:23:51 -05:00
David Olson 70a6f42649 AAE-40741 Form rule Validate form doesn't do anything (#11788) 2026-04-06 09:44:23 -05:00
Darren Thornton 74252797b7 AAE-28918 Fix for start process button is enabled when required widgets are read only without value (#11781)
* AAE-28918 Fix start process button is enabled when required widgets are read only without value

* Apply Copilot review suggestions.

* updates after code review comments

* revert change made earlier
2026-04-01 13:32:30 -05:00
Dominik Iwanek 79871455f4 [ACS-10242] SR: Personal files: Filter by Size popup announces entire content instead of dialog title (#11782) 2026-04-01 14:53:44 +02:00
Alfresco BuildandCrowdin Bot 2cd51b4789 New Crowdin translations by GitHub Action (#11787)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2026-04-01 12:30:38 +01:00
dependabot[bot] a3e34d35a4 build(deps-dev): bump @xmldom/xmldom from 0.8.11 to 0.8.12 (#11785)
Bumps [@xmldom/xmldom](https://github.com/xmldom/xmldom) from 0.8.11 to 0.8.12.
- [Release notes](https://github.com/xmldom/xmldom/releases)
- [Changelog](https://github.com/xmldom/xmldom/blob/master/CHANGELOG.md)
- [Commits](https://github.com/xmldom/xmldom/compare/0.8.11...0.8.12)

---
updated-dependencies:
- dependency-name: "@xmldom/xmldom"
  dependency-version: 0.8.12
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-01 12:30:11 +01:00
Tomek Hanaj d7a8f03dbf AAE-43749 Added date formatting according to locale (#11769)
* [AAE-43749] added date formatting according to locale

* [AAE-43749] applied pr comments

* [AAE-43749] pipe use default date format reacting to locale
2026-04-01 12:29:41 +01:00
dependabot[bot] 7b32eb49d8 build(deps-dev): bump brace-expansion from 1.1.12 to 1.1.13 (#11786)
Bumps [brace-expansion](https://github.com/juliangruber/brace-expansion) from 1.1.12 to 1.1.13.
- [Release notes](https://github.com/juliangruber/brace-expansion/releases)
- [Commits](https://github.com/juliangruber/brace-expansion/compare/v1.1.12...v1.1.13)

---
updated-dependencies:
- dependency-name: brace-expansion
  dependency-version: 1.1.13
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-01 10:24:38 +02:00
Anton RamanovichandMichalKinas a3e13da3a4 [ACS-10280]: Keyboard Navigation: Search: Unnecessary stops in the results table using the Tab key (#11736)
* [ACS-10280]: move selection handling to row

* [ACS-10280]: clean up

* [ACS-10280]: rollback title

* [ACS-10280]: migrate to conditional aria-hidden

* [ACS-10280]: revert to fix hxp

* [ACS-10280]: sonar fix

* [ACS-10280] Use new Angular control flow syntax

* [ACS-10280] Unit test fix

---------

Co-authored-by: MichalKinas <michal.kinas@hyland.com>
2026-04-01 10:17:00 +02:00
Michal Kinas 565db01819 [MNT-25635] Search filter autocomplete search for tags when input changes (#11780) 2026-04-01 09:29:43 +02:00
Amedeo Lepore f321b74be0 AAE-21162 Add deploymentCompletion property to ApplicationInstance model (#11784) 2026-03-31 15:10:45 +02:00
Wojciech Duda 28fe6d3a76 AAE-43710 Fix form field spacing misalignments (#11763) 2026-03-31 10:32:26 +02:00
dependabot[bot]andDenys Vuika 7b29d56272 build(deps): bump minimatch, @nx/angular, @nx/eslint-plugin, @nx/js, @nx/node, @nx/storybook, @typescript-eslint/eslint-plugin and @typescript-eslint/parser (#11779)
* build(deps): bump minimatch, @nx/angular, @nx/eslint-plugin, @nx/js, @nx/node, @nx/storybook, @typescript-eslint/eslint-plugin and @typescript-eslint/parser

Bumps [minimatch](https://github.com/isaacs/minimatch) to 10.2.4 and updates ancestor dependencies [minimatch](https://github.com/isaacs/minimatch), [@nx/angular](https://github.com/nrwl/nx/tree/HEAD/packages/angular), [@nx/eslint-plugin](https://github.com/nrwl/nx/tree/HEAD/packages/eslint-plugin), [@nx/js](https://github.com/nrwl/nx/tree/HEAD/packages/js), [@nx/node](https://github.com/nrwl/nx/tree/HEAD/packages/node), [@nx/storybook](https://github.com/nrwl/nx/tree/HEAD/packages/storybook), [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) and [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser). These dependencies need to be updated together.


Updates `minimatch` from 10.1.1 to 10.2.4
- [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md)
- [Commits](https://github.com/isaacs/minimatch/compare/v10.1.1...v10.2.4)

Updates `@nx/angular` from 22.1.3 to 22.6.3
- [Release notes](https://github.com/nrwl/nx/releases)
- [Commits](https://github.com/nrwl/nx/commits/22.6.3/packages/angular)

Updates `@nx/eslint-plugin` from 22.3.3 to 22.6.3
- [Release notes](https://github.com/nrwl/nx/releases)
- [Commits](https://github.com/nrwl/nx/commits/22.6.3/packages/eslint-plugin)

Updates `@nx/js` from 22.1.3 to 22.6.3
- [Release notes](https://github.com/nrwl/nx/releases)
- [Commits](https://github.com/nrwl/nx/commits/22.6.3/packages/js)

Updates `@nx/node` from 22.1.3 to 22.6.3
- [Release notes](https://github.com/nrwl/nx/releases)
- [Commits](https://github.com/nrwl/nx/commits/22.6.3/packages/node)

Updates `@nx/storybook` from 20.8.4 to 22.6.3
- [Release notes](https://github.com/nrwl/nx/releases)
- [Commits](https://github.com/nrwl/nx/commits/22.6.3/packages/storybook)

Updates `@typescript-eslint/eslint-plugin` from 6.21.0 to 8.57.2
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.57.2/packages/eslint-plugin)

Updates `@typescript-eslint/parser` from 6.21.0 to 8.57.2
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.57.2/packages/parser)

---
updated-dependencies:
- dependency-name: minimatch
  dependency-version: 10.2.4
  dependency-type: indirect
- dependency-name: "@nx/angular"
  dependency-version: 22.6.3
  dependency-type: direct:development
- dependency-name: "@nx/eslint-plugin"
  dependency-version: 22.6.3
  dependency-type: direct:development
- dependency-name: "@nx/js"
  dependency-version: 22.6.3
  dependency-type: direct:development
- dependency-name: "@nx/node"
  dependency-version: 22.6.3
  dependency-type: direct:development
- dependency-name: "@nx/storybook"
  dependency-version: 22.6.3
  dependency-type: direct:development
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.57.2
  dependency-type: direct:development
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.57.2
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>

* refactor(eslint): remove @typescript-eslint/brace-style rule and clean up component file

Removed the '@typescript-eslint/brace-style' rule from the ESLint configuration and cleaned up the process-list-cloud.component.ts file by removing the associated eslint-disable comment.

* fix(eslint): change @typescript-eslint/prefer-optional-chain rule from error to warn

Updated the ESLint configuration to modify the severity of the '@typescript-eslint/prefer-optional-chain' rule from 'error' to 'warn' for improved flexibility in code quality enforcement.

* fix(eslint): disable no-explicit-any rule and refactor LogicalSearchCondition type

Disabled the '@typescript-eslint/no-explicit-any' rule in the ESLint configuration and refactored the LogicalSearchCondition type to use a type alias instead of an interface for improved clarity and consistency.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Denys Vuika <denys.vuika@gmail.com>
2026-03-30 11:42:27 +01:00
Alfresco BuildandCrowdin Bot 7953eee9b0 New Crowdin translations by GitHub Action (#11778)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2026-03-30 10:32:24 +01:00
dependabot[bot] c6d577a6c3 build(deps): bump brace-expansion in /lib/cli (#11770)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-30 10:17:51 +02:00
dependabot[bot] bda12d5105 build(deps): bump Alfresco/alfresco-build-tools from 15.12.0 to 15.12.1 in /.github/actions/setup (#11774)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-30 10:15:17 +02:00
dependabot[bot] 641cfd8cf4 build(deps): bump crowdin/github-action from 2.15.2 to 2.16.0 (#11775)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-30 10:15:02 +02:00
dependabot[bot] 8cdc05d433 build(deps): bump Alfresco/alfresco-build-tools from 15.12.0 to 15.12.1 (#11776)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-30 10:14:44 +02:00
dependabot[bot] 4751563d3b build(deps): bump github/codeql-action from 4.34.1 to 4.35.1 (#11777)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-30 10:14:30 +02:00
Darren ThorntonandCopilot d526d31425 AAE-34137 Fix for disabling complete button on the form after declining form confirmation dialog (#11766)
* AAE-34137 Reenable Save and Complete buttons if user rejects on Confirm dialog

* Apply suggestion from Copilot, add takeUntilDestroy

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-27 10:24:38 -05:00
dependabot[bot] 430bd08fa9 build(deps): bump node-forge from 1.3.3 to 1.4.0 (#11768)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-27 14:13:05 +01:00
dependabot[bot] 23eca963b7 build(deps): bump yaml and lint-staged (#11765)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-27 11:50:00 +01:00
dependabot[bot] 31a85fe5df build(deps-dev): bump handlebars from 4.7.8 to 4.7.9 (#11767)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-27 11:48:10 +01:00
dependabot[bot] 9d03588f07 build(deps): bump smol-toml from 1.6.0 to 1.6.1 (#11764)
Bumps [smol-toml](https://github.com/squirrelchat/smol-toml) from 1.6.0 to 1.6.1.
- [Release notes](https://github.com/squirrelchat/smol-toml/releases)
- [Commits](https://github.com/squirrelchat/smol-toml/compare/v1.6.0...v1.6.1)

---
updated-dependencies:
- dependency-name: smol-toml
  dependency-version: 1.6.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-26 13:05:41 +00:00
David Olson e97439f09b AAE-43391 Disable 'Start process' and 'Complete' when whitespace is entered into required form fields (#11760) 2026-03-24 09:50:30 -05:00
Soumyajit Chakraborty bdd4b687c6 AAE-43290 updating the minor version for angular in ADF (#11752) 2026-03-24 08:35:03 +05:30
dependabot[bot] 30a15dec46 build(deps): bump kamatama41/get-pr-number-action from 0.9.1 to 1.0.1 (#11724)
Bumps [kamatama41/get-pr-number-action](https://github.com/kamatama41/get-pr-number-action) from 0.9.1 to 1.0.1.
- [Release notes](https://github.com/kamatama41/get-pr-number-action/releases)
- [Commits](https://github.com/kamatama41/get-pr-number-action/compare/0bcaab5752c0b699149e74667c8ce2f764cbb7fa...ff143e03abaa79d346ca5407d49d335b5def979e)

---
updated-dependencies:
- dependency-name: kamatama41/get-pr-number-action
  dependency-version: 1.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-23 09:28:27 +00:00
Alfresco BuildandCrowdin Bot f1895f725d New Crowdin translations by GitHub Action (#11751)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2026-03-23 08:11:24 +00:00
dependabot[bot] 74953b7098 build(deps): bump flatted from 3.4.1 to 3.4.2 (#11753)
Bumps [flatted](https://github.com/WebReflection/flatted) from 3.4.1 to 3.4.2.
- [Commits](https://github.com/WebReflection/flatted/compare/v3.4.1...v3.4.2)

---
updated-dependencies:
- dependency-name: flatted
  dependency-version: 3.4.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-23 08:11:04 +00:00
dependabot[bot] d88be7122b build(deps): bump actions/cache (#11754)
Bumps [actions/cache](https://github.com/actions/cache) from 5.0.3 to 5.0.4.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/cdf6c1fa76f9f475f3d7449005a359c84ca0f306...668228422ae6a00e4ad889ee87cd7109ec5666a7)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: 5.0.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-23 08:10:40 +00:00
dependabot[bot] 56d5593b46 build(deps): bump actions/cache (#11755)
Bumps [actions/cache](https://github.com/actions/cache) from 5.0.3 to 5.0.4.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/cdf6c1fa76f9f475f3d7449005a359c84ca0f306...668228422ae6a00e4ad889ee87cd7109ec5666a7)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: 5.0.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-23 08:10:17 +00:00
dependabot[bot] d25d8044ef build(deps): bump Alfresco/alfresco-build-tools from 15.9.1 to 15.12.0 (#11757)
Bumps [Alfresco/alfresco-build-tools](https://github.com/alfresco/alfresco-build-tools) from 15.9.1 to 15.12.0.
- [Release notes](https://github.com/alfresco/alfresco-build-tools/releases)
- [Commits](https://github.com/alfresco/alfresco-build-tools/compare/b7013d54c5255a71f931fd1316d0fcdb5c36c13c...0f483aca096ad614dbee2a4b0c9222437c285d1c)

---
updated-dependencies:
- dependency-name: Alfresco/alfresco-build-tools
  dependency-version: 15.12.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-23 08:08:49 +00:00
dependabot[bot] e0b4113c8c build(deps): bump Alfresco/alfresco-build-tools (#11756)
Bumps [Alfresco/alfresco-build-tools](https://github.com/alfresco/alfresco-build-tools) from 15.9.1 to 15.12.0.
- [Release notes](https://github.com/alfresco/alfresco-build-tools/releases)
- [Commits](https://github.com/alfresco/alfresco-build-tools/compare/b7013d54c5255a71f931fd1316d0fcdb5c36c13c...0f483aca096ad614dbee2a4b0c9222437c285d1c)

---
updated-dependencies:
- dependency-name: Alfresco/alfresco-build-tools
  dependency-version: 15.12.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-23 08:08:24 +00:00
dependabot[bot] 171087d11e build(deps): bump actions/cache in /.github/actions/setup (#11758)
Bumps [actions/cache](https://github.com/actions/cache) from 5.0.3 to 5.0.4.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/cdf6c1fa76f9f475f3d7449005a359c84ca0f306...668228422ae6a00e4ad889ee87cd7109ec5666a7)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: 5.0.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-23 08:08:06 +00:00
dependabot[bot] d9811b6bd9 build(deps): bump github/codeql-action from 4.32.6 to 4.34.1 (#11759)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.32.6 to 4.34.1.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/0d579ffd059c29b07949a3cce3983f0780820c98...38697555549f1db7851b81482ff19f1fa5c4fedc)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.34.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-23 08:07:49 +00:00
Michal Kinas 46989ae081 [ACS-11319] Move tree actions menu item buttons inside the component (#11749)
* [ACS-11319] Move tree actions menu item buttons inside the component

* [ACS-11319] Copilot review fixes
2026-03-19 14:47:30 +01:00
Alfresco BuildandCrowdin Bot 22d8d00e2e New Crowdin translations by GitHub Action (#11750)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2026-03-19 11:48:28 +00:00
Samuel Fialho a50dfd050d CSX-460 Revert Remove excess disabled attribute PR (#11748) 2026-03-19 10:20:53 +00:00
Dominik Iwanek e57910f5c3 [ACS-11271] Rebranding of FE apps (#11746) 2026-03-19 08:58:01 +01:00
Mykyta Maliarchuk 3bea95b8e0 Revert "[ACS-10219] add class selector (#11387)" (#11745)
This reverts commit f5f7c04a85.
2026-03-18 16:24:07 +01:00
Mykyta Maliarchuk adce4cabf5 [MNT-25447] Fix: Viewing preview renditions for versions fails (#11747)
* [MNT-25447] Fix: Viewing preview renditions for versions fails

* [MNT-25447] cr fix
2026-03-18 13:40:09 +01:00
Diogo Bastos ebf742c54b AAE-43331 Expand adf-icon (#11744)
* AAE-43331 Expand adf-icon

* AAE-43331 Fix css
2026-03-18 11:12:58 +00:00
Benn Snyder 759d206302 HXIDP-6471 Provide start process variables to custom screen (#11712)
* HXIDP-6471 Provide start process variables to custom screen

* Apply recommendations

* Apply more recommendations

* Add appName property

* Fix input types and defaults
2026-03-16 16:16:02 -04:00
AleksanderSklorz a865372819 [ACS-10267] Announce titles for repository info as headings (#11728)
* [ACS-10267] Announce titles for repository info as headings

* [ACS-10267] Addressed copilot comments

* [ACS-10267] Addressed copilot comments
2026-03-16 11:31:33 +01:00
dependabot[bot] 6c5a205d3e build(deps): bump flatted from 3.3.3 to 3.4.1 (#11739)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-16 10:31:09 +01:00
dependabot[bot] 983c8a1b5f build(deps): bump Alfresco/alfresco-build-tools from 15.7.1 to 15.9.1 in /.github/actions/setup (#11740)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-16 10:24:42 +01:00
dependabot[bot] 2bab1560be build(deps): bump Alfresco/alfresco-build-tools from 15.7.1 to 15.9.1 (#11741)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-16 10:24:26 +01:00
dependabot[bot] 5c6dcb8f3c build(deps): bump crowdin/github-action from 2.15.0 to 2.15.2 (#11742)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-16 10:24:11 +01:00
Alfresco BuildandCrowdin Bot f3cf57c9d8 New Crowdin translations by GitHub Action (#11732)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2026-03-16 08:40:50 +00:00
Michal Kinas 2bab587876 [ACS-11205] Bring back removed getter (#11735) 2026-03-13 12:14:31 +01:00
David Olson e325ad3871 AAE-39678 Apply visibility conditions if dependent field's value is changed with form rules (#11729) 2026-03-12 11:51:20 -05:00
David Olson a8ae3d3b4e AAE-42908 Evaluate expressions for rich-text-display list types (#11726) 2026-03-12 11:51:02 -05:00
Michal Kinas bc41c33ba8 [ACS-11205] Add LazyApi decorator (#11711)
* [ACS-11205] Add LazyApi decorator

* [ACS-11205] Add unit tests and CR fixes

* [ACS-11259] Storybook build fix
2026-03-12 10:15:38 +01:00
AleksanderSklorz 83e80906d8 [ACS-11213] upgrade ngx translate to v17 (#11719)
* [ACS-11213] Upgraded ngx-translate to v17

* [ACS-11213] Fix translations

* [ACS-11213] Reverted redundant change

* [ACS-11213] Translations fix

* [ACS-11213] Fixed unit tests

* [ACS-11213] Added unit tests for changes in translate-loader.service

* [ACS-11213] Added empty line

* [ACS-11213] Addressed copilot comments
2026-03-12 09:52:59 +01:00
Michal Kinas ef5944a09c Post-release version bump (#11734) 2026-03-11 20:30:57 +01:00
254 changed files with 9372 additions and 14871 deletions
+2 -2
View File
@@ -78,7 +78,7 @@ module.exports = {
}
],
'@typescript-eslint/await-thenable': 'error',
'@typescript-eslint/prefer-optional-chain': 'error',
'@typescript-eslint/prefer-optional-chain': 'warn',
'@typescript-eslint/prefer-readonly': 'error',
'@typescript-eslint/no-inferrable-types': 'off',
'@typescript-eslint/no-require-imports': 'off',
@@ -103,9 +103,9 @@ module.exports = {
'@typescript-eslint/member-ordering': 'off',
'@typescript-eslint/no-empty-function': 'off',
'prefer-arrow/prefer-arrow-functions': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'prefer-promise-reject-errors': 'error',
'brace-style': 'off',
'@typescript-eslint/brace-style': 'error',
'comma-dangle': 'error',
'default-case': 'error',
'import/order': 'off',
@@ -4,7 +4,7 @@ runs:
using: "composite"
steps:
- name: Restore dist from cache
uses: actions/cache/restore@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: dist
key: dist-${{ github.run_id }}-${{ github.run_attempt }}
@@ -13,7 +13,7 @@ runs:
fail-on-cache-miss: true
- name: Restore nxcache from cache
uses: actions/cache/restore@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: nxcache
key: nxcache-${{ github.run_id }}-${{ github.run_attempt }}
@@ -22,7 +22,7 @@ runs:
fail-on-cache-miss: true
- name: Restore node_modules from cache
uses: actions/cache/restore@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: node_modules
key: node-modules-${{ github.run_id }}-${{ github.run_attempt }}
+2 -2
View File
@@ -25,12 +25,12 @@ runs:
cache-dependency-path: package-lock.json
- name: get latest tag sha
id: tag-sha
uses: Alfresco/alfresco-build-tools/.github/actions/git-latest-tag@40f2376b812403b51e0cea49eaff04c1b8d65cfd # v15.7.1
uses: Alfresco/alfresco-build-tools/.github/actions/git-latest-tag@c00625b5f30db226fb0634299effc4cd15fdd7bb # v17.2.0
# CACHE
- name: Node Modules cache
id: node-modules-cache
if: ${{ inputs.enable-node-modules-cache == 'true' }}
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
env:
cache-name: node-modules-cache
with:
@@ -5,19 +5,19 @@ runs:
using: "composite"
steps:
- name: Save dist to cache
uses: actions/cache/save@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: dist
key: dist-${{ github.run_id }}-${{ github.run_attempt }}
- name: Save nxcache to cache
uses: actions/cache/save@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: nxcache
key: nxcache-${{ github.run_id }}-${{ github.run_attempt }}
- name: Save node_modules to cache
uses: actions/cache/save@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: node_modules
key: node-modules-${{ github.run_id }}-${{ github.run_attempt }}
+3 -3
View File
@@ -30,7 +30,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@0d579ffd059c29b07949a3cce3983f0780820c98 # v3.29.5
uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v3.29.5
# Override language selection by uncommenting this and choosing your languages
with:
languages: javascript
@@ -39,7 +39,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@0d579ffd059c29b07949a3cce3983f0780820c98 # v3.29.5
uses: github/codeql-action/autobuild@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v3.29.5
# ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@@ -53,4 +53,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@0d579ffd059c29b07949a3cce3983f0780820c98 # v3.29.5
uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v3.29.5
+1 -1
View File
@@ -9,7 +9,7 @@ jobs:
if: github.event.registry_package.package_type == 'npm' && github.event.registry_package.name == 'adf-core'
steps:
- name: Dispatch event to monorepo
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
PACKAGE_NAME: ${{ github.event.registry_package.name }}
PACKAGE_VERSION: ${{ github.event.registry_package.package_version.name }}
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
ref: develop
token: ${{ secrets.BOT_GITHUB_TOKEN }}
- name: Pull translations from Crowdin
uses: crowdin/github-action@8818ff65bfc4322384f983ea37e3926948c11745 # v2.15.0
uses: crowdin/github-action@7ca9c452bfe9197d3bb7fa83a4d7e2b0c9ae835d # v2.16.0
with:
skip_ref_checkout: true
upload_sources: false
+5 -5
View File
@@ -46,7 +46,7 @@ jobs:
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Ensure SHA pinned actions
uses: hyland/github-actions-ensure-sha-pinned-actions@1afac08cba4e5ea12263a46f49683570690ae3af # v1.2.0
uses: hyland/github-actions-ensure-sha-pinned-actions@7d494b6b53e71f75194d74b4dd890a2266d060b5 # v2.0.0
- name: Check package-lock.json version
run: |
@@ -66,10 +66,10 @@ jobs:
fetch-depth: 0
- name: Get branch name
uses: Alfresco/alfresco-build-tools/.github/actions/get-branch-name@40f2376b812403b51e0cea49eaff04c1b8d65cfd # v15.7.1
uses: Alfresco/alfresco-build-tools/.github/actions/get-branch-name@c00625b5f30db226fb0634299effc4cd15fdd7bb # v17.2.0
- name: Save commit message
uses: Alfresco/alfresco-build-tools/.github/actions/get-commit-message@40f2376b812403b51e0cea49eaff04c1b8d65cfd # v15.7.1
uses: Alfresco/alfresco-build-tools/.github/actions/get-commit-message@c00625b5f30db226fb0634299effc4cd15fdd7bb # v17.2.0
with:
header-only: true
@@ -89,7 +89,7 @@ jobs:
- name: Get PR number
if: ${{ github.event_name != 'schedule' && github.event_name != 'workflow_dispatch' }}
uses: kamatama41/get-pr-number-action@0bcaab5752c0b699149e74667c8ce2f764cbb7fa # v0.9.1
uses: kamatama41/get-pr-number-action@ff143e03abaa79d346ca5407d49d335b5def979e # v1.0.1
id: action
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
@@ -256,7 +256,7 @@ jobs:
fetch-depth: 1
- name: PR contains forbidden labels
id: pr-forbidden
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const issueHasLabels = require('./scripts/github/update/check-issue-has-label.js');
+2 -2
View File
@@ -93,7 +93,7 @@ jobs:
set -u;
./scripts/github/build/bumpversion.sh
- name: Set migrations
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const setMigrations = require('./scripts/github/release/set-migrations.js');
@@ -179,7 +179,7 @@ jobs:
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Push Source Files to Crowdin
uses: crowdin/github-action@8818ff65bfc4322384f983ea37e3926948c11745 # v2.15.0
uses: crowdin/github-action@7ca9c452bfe9197d3bb7fa83a4d7e2b0c9ae835d # v2.16.0
with:
upload_sources: true
upload_sources_args: --delete-obsolete
@@ -18,7 +18,6 @@ Shows the nodes in tree structure, each node containing children is collapsible/
[displayName]="'Tree display name'"
[loadMoreSuffix]="'subnodes'"
[emptyContentTemplate]="emptyContentTemplate"
[nodeActionsMenuTemplate]="nodeActionsMenuTemplate"
(paginationChanged)="onPaginationChanged($event)">
</adf-tree>
```
@@ -34,7 +33,6 @@ Shows the nodes in tree structure, each node containing children is collapsible/
| emptyContentTemplate | [`TemplateRef`](https://angular.io/api/core/TemplateRef)`<any>` | | [TemplateRef](https://angular.io/api/core/TemplateRef) to provide empty template when no nodes are loaded |
| expandIcon | `string` | "chevron_right" | Icon shown when node has children and is collapsed. By default set to chevron_right |
| loadMoreSuffix | `string` | | Load more suffix for load more button |
| nodeActionsMenuTemplate | [`TemplateRef`](https://angular.io/api/core/TemplateRef)`<any>` | | [TemplateRef](https://angular.io/api/core/TemplateRef) to provide context menu items for context menu displayed on each row |
| selectableNodes | `boolean` | false | Variable defining if tree nodes should be selectable. By default set to false |
| stickyHeader | `boolean` | false | Variable defining if tree header should be sticky. By default set to false |
| contextMenuOptions | `any[]` | | Array of context menu options which should be displayed for each row. |
@@ -88,7 +86,6 @@ First step is to provide necessary input value.
[loadMoreSuffix]="'subnodes'"
[selectableNodes]="true"
[emptyContentTemplate]="emptyContentTemplate"
[nodeActionsMenuTemplate]="nodeActionsMenuTemplate"
(paginationChanged)="onPaginationChanged($event)">
</adf-tree>
```
+1 -1
View File
@@ -14,7 +14,7 @@ Reusable header for Alfresco applications.
```html
<adf-layout-header
title="title"
logo="logo.png"
logo="logo.svg"
[redirectUrl]="'/home'"
color="primary"
(clicked)=toggleMenu($event)>
+1
View File
@@ -61,3 +61,4 @@ The pages linked below contain the licenses for all third party dependencies of
- [ADF 8.2.0](license-info-8.2.0.md)
- [ADF 8.2.1](license-info-8.2.1.md)
- [ADF 8.3.1](license-info-8.3.1.md)
- [ADF 8.4.1](license-info-8.4.1.md)
+48
View File
@@ -0,0 +1,48 @@
---
Title: License info, alfresco-ng2-components 8.4.0
---
# License information for alfresco-ng2-components 8.4.0
This page lists all third party libraries the project depends on.
## Libraries
| Name | Version | License |
| --- | --- | --- |
| [@angular/animations](https://github.com/angular/angular) | 19.2.20 | [MIT](https://opensource.org/license/mit/) |
| [@angular/cdk](https://github.com/angular/components) | 19.2.19 | [MIT](https://opensource.org/license/mit/) |
| [@angular/common](https://github.com/angular/angular) | 19.2.20 | [MIT](https://opensource.org/license/mit/) |
| [@angular/compiler](https://github.com/angular/angular) | 19.2.20 | [MIT](https://opensource.org/license/mit/) |
| [@angular/core](https://github.com/angular/angular) | 19.2.20 | [MIT](https://opensource.org/license/mit/) |
| [@angular/forms](https://github.com/angular/angular) | 19.2.20 | [MIT](https://opensource.org/license/mit/) |
| [@angular/material-date-fns-adapter](https://github.com/angular/components) | 19.2.19 | [MIT](https://opensource.org/license/mit/) |
| [@angular/material](https://github.com/angular/components) | 19.2.19 | [MIT](https://opensource.org/license/mit/) |
| [@angular/platform-browser-dynamic](https://github.com/angular/angular) | 19.2.20 | [MIT](https://opensource.org/license/mit/) |
| [@angular/platform-browser](https://github.com/angular/angular) | 19.2.20 | [MIT](https://opensource.org/license/mit/) |
| [@angular/router](https://github.com/angular/angular) | 19.2.20 | [MIT](https://opensource.org/license/mit/) |
| [@apollo/client](https://github.com/apollographql/apollo-client) | 3.13.1 | [MIT](https://opensource.org/license/mit/) |
| [@cspell/eslint-plugin](https://github.com/streetsidesoftware/cspell) | 9.4.0 | [MIT](https://opensource.org/license/mit/) |
| [@mat-datetimepicker/core](https://github.com/kuhnroyal/mat-datetimepicker) | 15.0.2 | [MIT](https://opensource.org/license/mit/) |
| [@ngx-translate/core](https://github.com/ngx-translate/core) | 17.0.0 | [MIT](https://opensource.org/license/mit/) |
| [angular-oauth2-oidc-jwks](https://github.com/manfredsteyer/angular-oauth2-oidc) | 17.0.2 | [MIT](https://opensource.org/license/mit/) |
| [angular-oauth2-oidc](https://github.com/manfredsteyer/angular-oauth2-oidc) | 17.0.2 | [MIT](https://opensource.org/license/mit/) |
| [apollo-angular](https://github.com/kamilkisiela/apollo-angular) | 10.0.3 | [MIT](https://opensource.org/license/mit/) |
| [chart.js](https://github.com/chartjs/Chart.js) | 4.4.4 | [MIT](https://opensource.org/license/mit/) |
| [cropperjs](https://github.com/fengyuanchen/cropperjs) | 1.6.2 | [MIT](https://opensource.org/license/mit/) |
| [date-fns](https://github.com/date-fns/date-fns) | 2.30.0 | [MIT](https://opensource.org/license/mit/) |
| dotenv-expand | 5.1.0 | [BSD-2-Clause](https://opensource.org/licenses/BSD-2-Clause) |
| editorjs-html | 4.0.5 | [MIT](https://opensource.org/license/mit/) |
| [eventemitter3](https://github.com/primus/eventemitter3) | 5.0.4 | [MIT](https://opensource.org/license/mit/) |
| [graphql-ws](https://github.com/enisdenjo/graphql-ws) | 6.0.7 | [MIT](https://opensource.org/license/mit/) |
| [material-icons](https://github.com/marella/material-icons) | 1.13.14 | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0) |
| [minimatch-browser](https://github.com/isaacs/minimatch) | 1.0.0 | [ISC](https://www.isc.org/licenses/) |
| [ng2-charts](https://github.com/valor-software/ng2-charts) | 4.1.1 | [ISC](https://www.isc.org/licenses/) |
| [node-fetch](https://github.com/node-fetch/node-fetch) | 3.3.2 | [MIT](https://opensource.org/license/mit/) |
| [pdfjs-dist](https://github.com/mozilla/pdf.js) | 5.1.91 | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0) |
| [raphael](https://github.com/DmitryBaranovskiy/raphael) | 2.3.0 | [MIT](https://opensource.org/license/mit/) |
| [rxjs](https://github.com/reactivex/rxjs) | 7.8.2 | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0) |
| [superagent](https://github.com/ladjs/superagent) | 9.0.2 | [MIT](https://opensource.org/license/mit/) |
| [tslib](https://github.com/Microsoft/tslib) | 2.8.1 | [0BSD](http://landley.net/toybox/license.html) |
| [zone.js](https://github.com/angular/angular) | 0.15.0 | [MIT](https://opensource.org/license/mit/) |
+1
View File
@@ -9,6 +9,7 @@ The first **General Availability** release was v2.0.0.
## General Availability
- [8.4.1](RelNote-8.4.1.md)
- [8.3.1](RelNote-8.3.1.md)
- [8.2.1](RelNote-8.2.1.md)
- [8.2.0](RelNote-8.2.0.md)
+40
View File
@@ -0,0 +1,40 @@
---
Title: Changelog for alfresco-ng2-components v8.4.0
---
# Changelog
- [af95723f30](https://github.com/Alfresco/alfresco-ng2-components/commit/af95723f30) [ACS-11589] [ACA] info drawer test-area does not show full text (#11816)
- [d70ae599c7](https://github.com/Alfresco/alfresco-ng2-components/commit/d70ae599c7) Fix security vulnerabilities in npm dependencies (#11815)
- [07c6a4d923](https://github.com/Alfresco/alfresco-ng2-components/commit/07c6a4d923) Remove jasmine-spec-reporter dependency from package.json and package-lock.json (#11814)
- [6fc8dda887](https://github.com/Alfresco/alfresco-ng2-components/commit/6fc8dda887) Remove mocha and jasmine-ajax dependencies (#11813)
- [48eb258311](https://github.com/Alfresco/alfresco-ng2-components/commit/48eb258311) AAE-44184 Colspan setting on form fields is ignored or not properly applied (#11800)
- [32850a0ce8](https://github.com/Alfresco/alfresco-ng2-components/commit/32850a0ce8) [MNT-25185] Display authority name instead of id if provided (#11809)
- [8a6bcac29e](https://github.com/Alfresco/alfresco-ng2-components/commit/8a6bcac29e) [ACS-11506]: moved aria-live region (#11808)
- [8ce0561ef5](https://github.com/Alfresco/alfresco-ng2-components/commit/8ce0561ef5) AAE-44086 Unify styling and coloring of errors in forms (#11797)
- [69a9dc1386](https://github.com/Alfresco/alfresco-ng2-components/commit/69a9dc1386) AAE-44002 Allow user input for date and datetime fields (#11791)
- [70a6f42649](https://github.com/Alfresco/alfresco-ng2-components/commit/70a6f42649) AAE-40741 Form rule `Validate form` doesn&#39;t do anything (#11788)
- [74252797b7](https://github.com/Alfresco/alfresco-ng2-components/commit/74252797b7) AAE-28918 Fix for start process button is enabled when required widgets are read only without value (#11781)
- [79871455f4](https://github.com/Alfresco/alfresco-ng2-components/commit/79871455f4) [ACS-10242] SR: Personal files: Filter by Size popup announces entire content instead of dialog title (#11782)
- [d7a8f03dbf](https://github.com/Alfresco/alfresco-ng2-components/commit/d7a8f03dbf) AAE-43749 Added date formatting according to locale (#11769)
- [a3e13da3a4](https://github.com/Alfresco/alfresco-ng2-components/commit/a3e13da3a4) [ACS-10280]: Keyboard Navigation: Search: Unnecessary stops in the results table using the Tab key (#11736)
- [565db01819](https://github.com/Alfresco/alfresco-ng2-components/commit/565db01819) [MNT-25635] Search filter autocomplete search for tags when input changes (#11780)
- [f321b74be0](https://github.com/Alfresco/alfresco-ng2-components/commit/f321b74be0) AAE-21162 Add deploymentCompletion property to ApplicationInstance model (#11784)
- [28fe6d3a76](https://github.com/Alfresco/alfresco-ng2-components/commit/28fe6d3a76) AAE-43710 Fix form field spacing misalignments (#11763)
- [d526d31425](https://github.com/Alfresco/alfresco-ng2-components/commit/d526d31425) AAE-34137 Fix for disabling `complete` button on the form after declining form confirmation dialog (#11766)
- [e97439f09b](https://github.com/Alfresco/alfresco-ng2-components/commit/e97439f09b) AAE-43391 Disable &#39;Start process&#39; and &#39;Complete&#39; when whitespace is entered into required form fields (#11760)
- [bdd4b687c6](https://github.com/Alfresco/alfresco-ng2-components/commit/bdd4b687c6) AAE-43290 updating the minor version for angular in ADF (#11752)
- [46989ae081](https://github.com/Alfresco/alfresco-ng2-components/commit/46989ae081) [ACS-11319] Move tree actions menu item buttons inside the component (#11749)
- [a50dfd050d](https://github.com/Alfresco/alfresco-ng2-components/commit/a50dfd050d) CSX-460 Revert Remove excess disabled attribute PR (#11748)
- [e57910f5c3](https://github.com/Alfresco/alfresco-ng2-components/commit/e57910f5c3) [ACS-11271] Rebranding of FE apps (#11746)
- [3bea95b8e0](https://github.com/Alfresco/alfresco-ng2-components/commit/3bea95b8e0) Revert &#34;[ACS-10219] add class selector (#11387)&#34; (#11745)
- [adce4cabf5](https://github.com/Alfresco/alfresco-ng2-components/commit/adce4cabf5) [MNT-25447] Fix: Viewing preview renditions for versions fails (#11747)
- [ebf742c54b](https://github.com/Alfresco/alfresco-ng2-components/commit/ebf742c54b) AAE-43331 Expand adf-icon (#11744)
- [759d206302](https://github.com/Alfresco/alfresco-ng2-components/commit/759d206302) HXIDP-6471 Provide start process variables to custom screen (#11712)
- [a865372819](https://github.com/Alfresco/alfresco-ng2-components/commit/a865372819) [ACS-10267] Announce titles for repository info as headings (#11728)
- [2bab587876](https://github.com/Alfresco/alfresco-ng2-components/commit/2bab587876) [ACS-11205] Bring back removed getter (#11735)
- [e325ad3871](https://github.com/Alfresco/alfresco-ng2-components/commit/e325ad3871) AAE-39678 Apply visibility conditions if dependent field&#39;s value is changed with form rules (#11729)
- [a8ae3d3b4e](https://github.com/Alfresco/alfresco-ng2-components/commit/a8ae3d3b4e) AAE-42908 Evaluate expressions for rich-text-display list types (#11726)
- [bc41c33ba8](https://github.com/Alfresco/alfresco-ng2-components/commit/bc41c33ba8) [ACS-11205] Add LazyApi decorator (#11711)
- [83e80906d8](https://github.com/Alfresco/alfresco-ng2-components/commit/83e80906d8) [ACS-11213] upgrade ngx translate to v17 (#11719)
- [ef5944a09c](https://github.com/Alfresco/alfresco-ng2-components/commit/ef5944a09c) Post-release version bump (#11734)
+1
View File
@@ -58,3 +58,4 @@ The pages linked below contain the audit for all third party dependencies of ADF
- [ADF 8.2.0](audit-info-8.2.0.md)
- [ADF 8.2.1](audit-info-8.2.1.md)
- [ADF 8.3.1](audit-info-8.3.1.md)
- [ADF 8.4.1](audit-info-8.4.1.md)
+23
View File
@@ -0,0 +1,23 @@
---
Title: Audit info, alfresco-ng2-components 8.4.0
---
# Audit information for alfresco-ng2-components 8.4.0
This page lists the security audit of the dependencies this project depends on.
## Risks
- Critical risk: 0
- High risk: 0
- Moderate risk: 0
- Low risk: 0
Dependencies analyzed:
## Libraries
| Severity | Module | Vulnerable versions |
| --- | --- | --- |
+12 -12
View File
@@ -1,15 +1,15 @@
{
"name": "@alfresco/adf-cli",
"version": "8.3.1",
"version": "8.4.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@alfresco/adf-cli",
"version": "8.3.1",
"version": "8.4.1",
"license": "Apache-2.0",
"dependencies": {
"@alfresco/js-api": ">=9.2.0",
"@alfresco/js-api": ">=9.4.0",
"ejs": "^3.1.10",
"license-checker": "^25.0.1",
"node-fetch": "^2.7.0",
@@ -26,9 +26,9 @@
}
},
"node_modules/@alfresco/js-api": {
"version": "9.2.1",
"resolved": "https://registry.npmjs.org/@alfresco/js-api/-/js-api-9.2.1.tgz",
"integrity": "sha512-GuxBtvBzu3nqu0G+FUGM2boND8VxBI2lX7TE72zX4CbTsS4/0YKZvpTpmOVqZOW4tlNQxy1fExPqQlEPahx+fg==",
"version": "9.4.0",
"resolved": "https://registry.npmjs.org/@alfresco/js-api/-/js-api-9.4.0.tgz",
"integrity": "sha512-2yRlZRZHA0AK1KZgtnpVkT1vUtoKYA8eWd0lrn1Wc6oSVwRW6rY2tzFab/44NZaGi+hgP6TkGhHPGcddavKn4g==",
"license": "Apache-2.0",
"dependencies": {
"eventemitter3": "^5.0.1",
@@ -126,9 +126,9 @@
"license": "MIT"
},
"node_modules/brace-expansion": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz",
"integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
@@ -859,9 +859,9 @@
}
},
"node_modules/read-package-json/node_modules/brace-expansion": {
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"version": "1.1.13",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
"integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "@alfresco/adf-cli",
"description": "Alfresco ADF cli and utils",
"version": "8.3.1",
"version": "8.4.1",
"author": "Hyland Software, Inc. and its affiliates",
"bin": {
"adf-cli": "bin/adf-cli",
@@ -22,7 +22,7 @@
"unlink": "cd ../../dist/libs/cli && npm unlink"
},
"dependencies": {
"@alfresco/js-api": ">=9.2.0",
"@alfresco/js-api": ">=9.4.0",
"ejs": "^3.1.10",
"license-checker": "^25.0.1",
"node-fetch": "^2.7.0",
+3 -9
View File
@@ -29,7 +29,7 @@ module.exports = function (config) {
{ pattern: 'lib/config/app.config.json', included: false, served: true, watched: false }
],
frameworks: ['jasmine-ajax', 'jasmine', '@angular-devkit/build-angular'],
frameworks: ['jasmine', '@angular-devkit/build-angular'],
proxies: {
'/assets/images/': '/base/lib/core/src/lib/assets/images/',
@@ -42,13 +42,11 @@ module.exports = function (config) {
},
plugins: [
require('karma-jasmine-ajax'),
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage'),
require('@angular-devkit/build-angular/plugins/karma'),
require('karma-mocha-reporter')
require('@angular-devkit/build-angular/plugins/karma')
],
client: {
clearContext: false,
@@ -61,10 +59,6 @@ module.exports = function (config) {
suppressAll: true // removes the duplicated traces
},
mochaReporter: {
ignoreSkipped: process.env.KARMA_IGNORE_SKIPPED === 'true'
},
coverageReporter: {
dir: join(__dirname, '../../coverage/content-services'),
subdir: '.',
@@ -86,7 +80,7 @@ module.exports = function (config) {
}
},
reporters: ['mocha', 'kjhtml'],
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: constants.LOG_INFO,
+4 -4
View File
@@ -1,7 +1,7 @@
{
"name": "@alfresco/adf-content-services",
"description": "Alfresco ADF content services",
"version": "8.3.1",
"version": "8.4.1",
"author": "Hyland Software, Inc. and its affiliates",
"repository": {
"type": "git",
@@ -21,9 +21,9 @@
"@angular/platform-browser": ">=14.1.3",
"@angular/platform-browser-dynamic": ">=14.1.3",
"@angular/router": ">=14.1.3",
"@alfresco/js-api": ">=9.3.1",
"@ngx-translate/core": ">=16.0.0",
"@alfresco/adf-core": ">=8.3.1"
"@alfresco/js-api": ">=9.4.1",
"@ngx-translate/core": ">=17.0.0",
"@alfresco/adf-core": ">=8.4.1"
},
"keywords": [
"content-services",
@@ -16,7 +16,7 @@
*/
import { Injectable, inject } from '@angular/core';
import { Agent, AgentsApi } from '@alfresco/js-api';
import { Agent, AgentsApi, LazyApi } from '@alfresco/js-api';
import { BehaviorSubject, from, Observable, of } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { AlfrescoApiService } from '../../services';
@@ -27,13 +27,10 @@ import { AlfrescoApiService } from '../../services';
export class AgentService {
private readonly apiService = inject(AlfrescoApiService);
private _agentsApi: AgentsApi;
private readonly agents = new BehaviorSubject<Agent[]>([]);
get agentsApi(): AgentsApi {
this._agentsApi = this._agentsApi ?? new AgentsApi(this.apiService.getInstance());
return this._agentsApi;
}
@LazyApi((self: AgentService) => new AgentsApi(self.apiService.getInstance()))
declare readonly agentsApi: AgentsApi;
agents$ = this.agents.asObservable();
@@ -1 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="17.2 134.6 562 573.1"><path fill="#FFF" d="M298.2,421.3L219,340.4l-2.9-2.9c-45.4-46.5-119.5-46.5-164.7-0.2c-45.6,46.3-45.6,121.5,0,167.8 c45.2,46.4,119,46.4,164.4,0L298.2,421.3z"/><path fill="#FFF" d="M298.2,421.2v114.3l0.2,4.2c0,65.5-52.2,119-116.5,119c-64.3,0-116.5-53.1-116.5-118.6 c0-65.6,52.4-118.8,116.5-118.8H298.2z"/><path fill="#FFF" d="M298.2,421.2v114.3l0.2,4.2c0,65.5-52.2,119-116.5,119c-64.3,0-116.5-53.1-116.5-118.6 c0-65.6,52.4-118.8,116.5-118.8H298.2z"/><path fill="#FFF" d="M298.2,421.2v114.3l0.2,4.2c0,65.5-52.2,119-116.5,119c-64.3,0-116.5-53.1-116.5-118.6 c0-7.3,0.8-14.4,2-21.2c45.4,32.2,108.2,27.7,148.6-13.7l82.4-83.8V421.2z"/><path fill="#8ABF42" d="M181.9,436.1c-56.1,0-101.6,46.5-101.6,103.8c0,57.1,45.6,103.5,101.6,103.5c56.2,0,101.7-46.4,101.7-103.5 v-4.5v-99.3H182.1H181.9z"/><path fill="#FFF" d="M298.2,421.2l79.2,80.8l3.3,2.9c45.2,46.4,45.5,121.8,0,168.1c-45.6,46.3-119.2,46.3-164.8,0 c-45.4-46.3-45.4-121.5,0-168L298.2,421.2z"/><path fill="#8ABF42" d="M226.5,515.6c-39.8,40.5-39.8,106.2,0,146.6c39.6,40.5,104,40.5,143.8,0c39.6-40.4,39.6-106.1,0-146.6 l-3.3-3l-68.7-70.2l-71.7,73.1V515.6z"/><path fill="#FFF" d="M298.2,421.2h112.2l4.1-0.2c64.4,0,116.5,53.2,116.5,118.8c0,65.6-52,118.6-116.3,118.6 c-64.3,0-116.5-53.1-116.5-118.6V421.2z"/><path fill="#8ABF42" d="M313.1,539.8c0,57.3,45.4,103.7,101.6,103.7c56,0,101.4-46.4,101.4-103.7c0-57.3-45.4-103.6-101.4-103.6 h-4.3h-97.4v103.3V539.8z"/><path fill="#FFF" d="M298.2,421.2l79.2-80.9l3.1-3.1c45.4-46.3,119.2-46.5,164.6-0.2c45.4,46.4,45.4,121.5,0,167.9 c-45.4,46.4-119.2,46.4-164.6,0L298.2,421.2z"/><path fill="#8ABF42" d="M391.1,494.3c39.4,40.6,103.8,40.6,143.6,0c39.8-40.4,39.8-106,0-146.5c-39.8-40.5-104.1-40.5-143.6,0 l-3.3,3.2l-68.6,70.3l71.5,73L391.1,494.3z"/><path fill="#FFF" d="M298.2,421.2V306.8v-4.3c0-65.5,51.9-118.8,116.5-118.8c64.2,0,116.1,52.9,116.1,118.6 c0,65.6-52,118.8-116.1,118.8H298.2z"/><path fill="#F89F31" d="M414.7,406.1c56,0,101.4-46.4,101.4-103.7c0-57.1-45.4-103.6-101.4-103.6c-56.3,0-101.8,46.5-101.8,103.6 l0.2,4.4v99.3h101.1H414.7z"/><path fill="#FFF" d="M298.2,421.2L219,340.3l-3.1-2.9c-45.4-46.5-45.4-121.8,0-168.1c45.2-46.4,119.1-46.4,164.6,0 c45.4,46.3,45.4,121.6,0,167.9L298.2,421.2z"/><path fill="#0080C5" d="M370.1,327.6c39.6-40.5,39.6-106.2,0-146.6c-39.8-40.5-104-40.5-143.7,0c-39.8,40.4-39.8,106.1,0,146.6 l2.9,3.1l69,70.1l71.6-73L370.1,327.6z"/><path fill="#FFF" d="M298.2,422.1H186.1l-4.2,0.1c-64.1,0-116.5-53.2-116.5-118.8c0-65.5,52.2-118.7,116.3-118.7 c64.3,0,116.6,53.2,116.6,118.8V422.1z"/><path fill="#0080C5" d="M283.5,303.5c0-57.3-45.4-103.6-101.8-103.6c-56,0-101.6,46.3-101.6,103.5c0,57.2,45.6,103.7,101.6,103.7 l4.4-0.1h97.4V303.8V303.5z"/><path fill="#FFF" d="M298.2,422.1l-281,0.1c0-30.4,11.2-60.8,34.2-84c45.2-46.3,119-46.3,164.4,0L298.2,422.1z"/><path fill="#0080C5" d="M205.4,348.9l71.9,73.3h-95.5c-51.6,0-95.5,34.3-110.7,81.9c-3.1-2.7-6.4-5.5-9.3-8.7 c-39.8-40.5-39.8-106,0-146.5C101.3,308.4,165.8,308.4,205.4,348.9"/><path fill="#005DA9" d="M205.6,349l56.9,58l-80.9,0.2c-46.6,0-85.8-31.9-97.8-75.5c38.6-22.1,89.2-16.8,121.6,17.1L205.6,349z"/><path fill="#005DA9" d="M283.5,303.7l-0.1,82.1l-57.1-58.2c-32.9-33.6-38.7-84.4-17-123.8c42.7,12.2,74.2,52.2,74.2,99.8V303.7z"/><path fill="#005DA9" d="M312.6,386v-82.4c0-47.5,31.5-87.5,74.2-99.8c21.6,39.5,17.6,89-16.4,123.3L312.6,386z"/><path fill="#FFDE4F" d="M333.9,406.1l57.1-58.3c32.9-33.6,82.8-39.3,121.4-17.2c-12.2,43.5-49.4,74.8-95.3,75.6L333.9,406.1z"/><path fill="#48A64A" d="M333.8,436.1h80.8c46.6,0,85.8,31.7,97.8,75.4c-38.9,22.2-88.7,16.3-121.8-17.2L333.8,436.1z"/><path fill="#48A64A" d="M313.1,539.2v-82l57.2,58.2c32.9,33.7,38.5,84.7,16.8,124.1c-42.7-12.2-74-52.4-74-99.9V539.2z"/><path fill="#48A64A" d="M226.6,515.4l56.9-58l0.1,82.4c0,47.5-31.3,87.4-74,99.7c-21.6-39.5-15.8-90.4,17-123.9V515.4z"/><path fill="#48A64A" d="M182.4,436.1h80.4l-57,58.2c-32.8,33.5-83.1,39.3-121.7,17.3c12.1-43.7,51.4-75.5,98-75.5H182.4z"/></svg>
<svg width="24" height="24" viewBox="0 0 316 316" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M159.2 162.346L152.375 169.174L114.409 207.15L114.41 207.151C95.0944 226.491 91.3457 255.445 103.066 278.58L105.601 283.58L100.048 284.35C97.5523 284.696 95.002 284.89 92.4004 284.89C58.599 284.89 31.2188 257.426 31.2188 223.6C31.2189 189.771 58.6023 162.346 92.4004 162.346H159.2Z" fill="#F1CB60" stroke="white" stroke-width="8"/>
<path d="M161.863 223.528C161.863 250.858 179.632 273.984 204.244 282.042L209.613 283.799L206.171 288.28C204.697 290.199 203.069 292.185 201.168 294.053L201.169 294.054C177.272 317.982 138.527 317.982 114.63 294.054C90.7354 270.129 90.7354 231.344 114.63 207.419L114.737 207.312L155.033 166.965L161.863 160.126V223.528Z" fill="#52A1FF" stroke="white" stroke-width="8"/>
<path d="M168.975 163.484L206.938 201.495C226.257 220.806 255.17 224.584 278.189 212.857L283.198 210.306L283.968 215.873C284.313 218.371 284.508 220.924 284.508 223.528C284.508 257.357 257.124 284.783 223.326 284.783C189.528 284.783 162.145 257.357 162.145 223.528V156.646L168.975 163.484Z" fill="#52A1FF" stroke="white" stroke-width="8"/>
<path d="M287.968 109.621C289.701 110.956 291.383 112.384 293.011 113.93L293.705 114.6L293.721 114.615L293.735 114.629C317.63 138.554 317.63 177.339 293.735 201.264C269.838 225.192 231.094 225.192 207.196 201.264L207.089 201.157L166.793 160.809L159.975 153.983H223.291C250.543 153.983 273.676 136.196 281.725 111.548L283.482 106.166L287.968 109.621Z" fill="#06C9A4" stroke="white" stroke-width="8"/>
<path d="M223.29 31.1108C257.091 31.1108 284.472 58.5754 284.472 92.4009C284.472 126.23 257.088 153.655 223.29 153.655H156.496L163.314 146.829L201.28 108.814C220.562 89.5077 224.344 60.5534 212.624 37.4214L210.09 32.4214L215.643 31.6509C218.138 31.3049 220.688 31.1108 223.29 31.1108Z" fill="#06C9A4" stroke="white" stroke-width="8"/>
<path d="M114.521 21.9453C138.419 -1.98214 177.163 -1.98201 201.061 21.9453C224.953 45.8676 224.956 84.6509 201.062 108.542L201.062 108.543L200.953 108.652L160.657 148.999L153.827 155.838V92.4365C153.827 65.1407 136.058 41.9797 111.447 33.9229L106.023 32.1465L109.542 27.6543C111.031 25.7534 112.682 23.7871 114.521 21.9453Z" fill="#6E33FF" stroke="white" stroke-width="8"/>
<path d="M92.3301 31.2173C126.128 31.2174 153.512 58.6426 153.512 92.4712V153.69H147.817L146.646 152.516L110.4 116.225L110.37 116.195L110.34 116.164L108.773 114.526C89.4526 95.1918 60.4773 91.3832 37.4277 103.108L32.3408 105.696L31.6445 100.031C31.3429 97.577 31.1484 95.0763 31.1484 92.4712C31.1486 58.6426 58.532 31.2173 92.3301 31.2173Z" fill="#6E33FF" stroke="white" stroke-width="8"/>
<path d="M21.9209 114.737C45.8182 90.8094 84.5627 90.8094 108.46 114.737L148.863 155.192L155.682 162.019H92.3652C90.8311 162.019 89.3122 162.086 87.7979 162.189L87.6611 162.198H87.5254C87.4492 162.198 87.2902 162.209 86.9639 162.246L86.9277 162.25L86.8926 162.252C85.408 162.391 83.9689 162.56 82.5908 162.79L82.5107 162.803L82.4297 162.813C82.4583 162.809 82.4593 162.807 82.3359 162.833C82.29 162.842 82.1909 162.863 82.0977 162.881C82.0291 162.895 81.945 162.908 81.8506 162.923L81.8516 162.925C80.5313 163.163 79.241 163.434 77.9443 163.742L77.8125 163.773L77.6797 163.794C77.6455 163.8 77.6113 163.806 77.585 163.81C77.5563 163.815 77.5338 163.818 77.5127 163.822C77.5041 163.823 77.4963 163.824 77.4893 163.826L77.4492 163.839L77.2891 163.878C75.9507 164.205 74.6195 164.604 73.2402 165.053C73.1272 165.091 73.0137 165.131 72.8691 165.182C72.735 165.23 72.5701 165.286 72.3916 165.346L72.3926 165.347C71.0135 165.83 69.646 166.344 68.3232 166.887L68.1299 166.966C66.862 167.502 65.6611 168.056 64.5137 168.663L64.4746 168.683L64.4355 168.703C64.3466 168.747 64.2575 168.795 64.1172 168.87C64.0059 168.929 63.8551 169.008 63.6885 169.092L63.6895 169.093C62.4463 169.75 61.2522 170.416 60.1152 171.131L60.1143 171.13C59.9666 171.227 59.8284 171.315 59.7422 171.368C59.6129 171.447 59.5605 171.48 59.5244 171.504L59.4756 171.537L59.4248 171.568C58.4258 172.193 57.4061 172.892 56.3779 173.62C56.2243 173.749 56.0938 173.847 56.0088 173.909C55.9378 173.96 55.8634 174.012 55.8408 174.028C55.8034 174.054 55.8117 174.048 55.833 174.032L55.7861 174.067C54.7178 174.845 53.6631 175.701 52.6191 176.612L52.6074 176.623L52.5947 176.633C52.4695 176.741 52.3441 176.848 52.2188 176.956C52.1013 177.056 51.9828 177.156 51.8652 177.257L51.8662 177.258C50.8262 178.165 49.7815 179.144 48.8047 180.122L48.5537 180.373C47.6777 181.25 46.8437 182.176 45.9697 183.183C45.8135 183.387 45.6703 183.554 45.5732 183.665C45.3997 183.862 45.4018 183.855 45.3564 183.91L45.3486 183.919C44.4388 185.006 43.5746 186.073 42.7939 187.148C42.7312 187.236 42.6712 187.323 42.5967 187.431C42.5177 187.545 42.4206 187.685 42.3115 187.838L42.3047 187.847C41.5605 188.884 40.8682 189.937 40.1514 191.063C40.1001 191.151 40.0531 191.227 40.0127 191.289C39.98 191.339 39.9466 191.385 39.9199 191.423C39.1621 192.724 38.4678 193.918 37.8467 195.129C37.7813 195.26 37.7157 195.391 37.6504 195.522C37.5787 195.665 37.5072 195.809 37.4355 195.953C36.7984 197.228 36.2384 198.388 35.7441 199.573C35.6963 199.727 35.6486 199.856 35.6094 199.958C35.5728 200.052 35.5371 200.136 35.5205 200.175C35.4987 200.227 35.4954 200.237 35.4922 200.245L35.4707 200.297C34.9663 201.509 34.5042 202.735 34.1133 203.942L34.0723 204.069L34.0225 204.193C33.9639 204.339 33.7844 204.809 33.4883 205.303L31.1553 209.196L27.5869 206.393C25.6385 204.863 23.7246 203.178 21.9209 201.372C-1.97351 177.447 -1.97359 138.662 21.9209 114.737Z" fill="#F1CB60" stroke="white" stroke-width="8"/>
<ellipse cx="157.5" cy="158" rx="5.5" ry="5" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

@@ -20,7 +20,7 @@ import { AlfrescoApiService } from '../../services/alfresco-api.service';
import { AppConfigService } from '@alfresco/adf-core';
import { from, Observable, of, zip } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { AspectEntry, AspectPaging, AspectsApi, ListAspectsOpts } from '@alfresco/js-api';
import { AspectEntry, AspectPaging, AspectsApi, LazyApi, ListAspectsOpts } from '@alfresco/js-api';
import { CustomAspectPaging } from '../interfaces/custom-aspect-paging.interface';
export const StandardAspectsWhere = `(modelId in ('cm:contentmodel', 'emailserver:emailserverModel', 'smf:smartFolder', 'app:applicationmodel' ))`;
@@ -33,11 +33,8 @@ export class AspectListService {
private readonly alfrescoApiService = inject(AlfrescoApiService);
private readonly appConfigService = inject(AppConfigService);
private _aspectsApi: AspectsApi;
get aspectsApi(): AspectsApi {
this._aspectsApi = this._aspectsApi ?? new AspectsApi(this.alfrescoApiService.getInstance());
return this._aspectsApi;
}
@LazyApi((self: AspectListService) => new AspectsApi(self.alfrescoApiService.getInstance()))
declare readonly aspectsApi: AspectsApi;
getAllAspects(standardOpts?: ListAspectsOpts, customOpts?: ListAspectsOpts): Observable<CustomAspectPaging> {
const visibleAspectList = this.getVisibleAspects();
@@ -25,7 +25,8 @@ import {
CategoryPaging,
ResultSetPaging,
SearchApi,
SEARCH_LANGUAGE
SEARCH_LANGUAGE,
LazyApi
} from '@alfresco/js-api';
import { AlfrescoApiService } from '../../services/alfresco-api.service';
import { from, Observable } from 'rxjs';
@@ -36,18 +37,11 @@ export class CategoryService {
private readonly userPreferencesService = inject(UserPreferencesService);
private readonly appConfigService = inject(AppConfigService);
private _categoriesApi: CategoriesApi;
private _searchApi: SearchApi;
@LazyApi((self: CategoryService) => new CategoriesApi(self.apiService.getInstance()))
declare readonly categoriesApi: CategoriesApi;
get categoriesApi(): CategoriesApi {
this._categoriesApi = this._categoriesApi ?? new CategoriesApi(this.apiService.getInstance());
return this._categoriesApi;
}
get searchApi(): SearchApi {
this._searchApi = this._searchApi ?? new SearchApi(this.apiService.getInstance());
return this._searchApi;
}
@LazyApi((self: CategoryService) => new SearchApi(self.apiService.getInstance()))
declare readonly searchApi: SearchApi;
/**
* Get subcategories of a given parent category
@@ -16,7 +16,7 @@
*/
import { Injectable, inject } from '@angular/core';
import { ContentApi, Node, NodeEntry } from '@alfresco/js-api';
import { ContentApi, LazyApi, Node, NodeEntry } from '@alfresco/js-api';
import { Subject } from 'rxjs';
import { AuthenticationService, ThumbnailService } from '@alfresco/adf-core';
import { PermissionsEnum } from '../models/permissions.enum';
@@ -42,11 +42,8 @@ export class ContentService {
folderCreate = new Subject<Node>();
folderEdit = new Subject<Node>();
private _contentApi: ContentApi;
get contentApi(): ContentApi {
this._contentApi = this._contentApi ?? new ContentApi(this.apiService.getInstance());
return this._contentApi;
}
@LazyApi((self: ContentService) => new ContentApi(self.apiService.getInstance()))
declare readonly contentApi: ContentApi;
/**
* Gets a content URL for the given node.
@@ -24,7 +24,8 @@ import {
DiscoveryApi,
AboutApi,
SystemPropertiesApi,
BpmProductVersionModel
BpmProductVersionModel,
LazyApi
} from '@alfresco/js-api';
import { AlfrescoApiService } from '../../services/alfresco-api.service';
import { AuthenticationService } from '@alfresco/adf-core';
@@ -36,11 +37,14 @@ export class DiscoveryApiService {
private readonly authenticationService = inject(AuthenticationService);
private readonly alfrescoApiService = inject(AlfrescoApiService);
private _discoveryApi: DiscoveryApi;
get discoveryApi(): DiscoveryApi {
this._discoveryApi = this._discoveryApi ?? new DiscoveryApi(this.alfrescoApiService.getInstance());
return this._discoveryApi;
}
@LazyApi((self: DiscoveryApiService) => new DiscoveryApi(self.alfrescoApiService.getInstance()))
declare readonly discoveryApi: DiscoveryApi;
@LazyApi((self: DiscoveryApiService) => new AboutApi(self.alfrescoApiService.getInstance()))
declare readonly aboutApi: AboutApi;
@LazyApi((self: DiscoveryApiService) => new SystemPropertiesApi(self.alfrescoApiService.getInstance()))
declare readonly systemPropertiesApi: SystemPropertiesApi;
/**
* Gets product information for Content Services.
@@ -78,14 +82,11 @@ export class DiscoveryApiService {
* @returns ProductVersionModel containing product details
*/
getBpmProductInfo(): Observable<BpmProductVersionModel> {
const aboutApi = new AboutApi(this.alfrescoApiService.getInstance());
return from(aboutApi.getAppVersion());
return from(this.aboutApi.getAppVersion());
}
getBPMSystemProperties(): Observable<SystemPropertiesRepresentation> {
const systemPropertiesApi = new SystemPropertiesApi(this.alfrescoApiService.getInstance());
return from(systemPropertiesApi.getProperties()).pipe(
return from(this.systemPropertiesApi.getProperties()).pipe(
map((res) => {
if ('string' === typeof res) {
throw new Error('Not valid response');
@@ -16,7 +16,7 @@
*/
import { Injectable, inject } from '@angular/core';
import { FavoritesApi, NodePaging, FavoritePaging } from '@alfresco/js-api';
import { FavoritesApi, NodePaging, FavoritePaging, LazyApi } from '@alfresco/js-api';
import { Observable, from, of } from 'rxjs';
import { AlfrescoApiService } from '../../services/alfresco-api.service';
import { UserPreferencesService } from '@alfresco/adf-core';
@@ -29,11 +29,8 @@ export class FavoritesApiService {
private readonly apiService = inject(AlfrescoApiService);
private readonly preferences = inject(UserPreferencesService);
private _favoritesApi: FavoritesApi;
get favoritesApi(): FavoritesApi {
this._favoritesApi = this._favoritesApi ?? new FavoritesApi(this.apiService.getInstance());
return this._favoritesApi;
}
@LazyApi((self: FavoritesApiService) => new FavoritesApi(self.apiService.getInstance()))
declare readonly favoritesApi: FavoritesApi;
static remapEntry({ entry }: any): any {
entry.properties = {
@@ -27,7 +27,8 @@ import {
TrashcanApi,
SizeDetailsEntry,
JobIdBodyEntry,
NodeAssociationPaging
NodeAssociationPaging,
LazyApi
} from '@alfresco/js-api';
import { Injectable, inject } from '@angular/core';
import { from, Observable, Subject, throwError } from 'rxjs';
@@ -47,17 +48,11 @@ export class NodesApiService {
*/
nodeUpdated = new Subject<Node>();
private _trashcanApi: TrashcanApi;
get trashcanApi(): TrashcanApi {
this._trashcanApi = this._trashcanApi ?? new TrashcanApi(this.apiService.getInstance());
return this._trashcanApi;
}
@LazyApi((self: NodesApiService) => new TrashcanApi(self.apiService.getInstance()))
declare readonly trashcanApi: TrashcanApi;
private _nodesApi: NodesApi;
get nodesApi(): NodesApi {
this._nodesApi = this._nodesApi ?? new NodesApi(this.apiService.getInstance());
return this._nodesApi;
}
@LazyApi((self: NodesApiService) => new NodesApi(self.apiService.getInstance()))
declare readonly nodesApi: NodesApi;
private getEntryFromEntity(entity: NodeEntry): Node {
return entity.entry;
@@ -19,7 +19,7 @@ import { Injectable, inject } from '@angular/core';
import { from, Observable, of } from 'rxjs';
import { AuthenticationService } from '@alfresco/adf-core';
import { map, tap } from 'rxjs/operators';
import { Pagination, PeopleApi, PersonBodyCreate, PersonBodyUpdate } from '@alfresco/js-api';
import { LazyApi, Pagination, PeopleApi, PersonBodyCreate, PersonBodyUpdate } from '@alfresco/js-api';
import { EcmUserModel } from '../models/ecm-user.model';
import { ContentService } from './content.service';
import { AlfrescoApiService } from '../../services/alfresco-api.service';
@@ -49,11 +49,8 @@ export class PeopleContentService {
private currentUser: EcmUserModel;
private _peopleApi: PeopleApi;
get peopleApi(): PeopleApi {
this._peopleApi = this._peopleApi ?? new PeopleApi(this.apiService.getInstance());
return this._peopleApi;
}
@LazyApi((self: PeopleContentService) => new PeopleApi(self.apiService.getInstance()))
declare readonly peopleApi: PeopleApi;
constructor() {
const authenticationService = inject(AuthenticationService);
@@ -16,7 +16,7 @@
*/
import { Injectable, inject } from '@angular/core';
import { ContentApi, RenditionEntry, RenditionPaging, RenditionsApi, VersionsApi } from '@alfresco/js-api';
import { ContentApi, LazyApi, RenditionEntry, RenditionPaging, RenditionsApi, VersionsApi } from '@alfresco/js-api';
import { Track, TranslationService, ViewUtilService } from '@alfresco/adf-core';
import { AlfrescoApiService } from '../../services/alfresco-api.service';
@@ -56,26 +56,16 @@ export class RenditionService {
* Timeout used for setInterval.
*/
private readonly TRY_TIMEOUT: number = 10000;
_renditionsApi: RenditionsApi;
get renditionsApi(): RenditionsApi {
this._renditionsApi = this._renditionsApi ?? new RenditionsApi(this.apiService.getInstance());
return this._renditionsApi;
}
_contentApi: ContentApi;
get contentApi(): ContentApi {
this._contentApi = this._contentApi ?? new ContentApi(this.apiService.getInstance());
return this._contentApi;
}
_versionsApi: VersionsApi;
private readonly DEFAULT_RENDITION: string = 'imgpreview';
get versionsApi(): VersionsApi {
this._versionsApi = this._versionsApi ?? new VersionsApi(this.apiService.getInstance());
return this._versionsApi;
}
@LazyApi((self: RenditionService) => new RenditionsApi(self.apiService.getInstance()))
declare readonly renditionsApi: RenditionsApi;
@LazyApi((self: RenditionService) => new ContentApi(self.apiService.getInstance()))
declare readonly contentApi: ContentApi;
@LazyApi((self: RenditionService) => new VersionsApi(self.apiService.getInstance()))
declare readonly versionsApi: VersionsApi;
getRenditionUrl(nodeId: string, type: string, renditionExists: boolean): string {
return renditionExists && type !== RenditionService.ContentGroup.IMAGE
@@ -194,7 +184,7 @@ export class RenditionService {
if (status === 'CREATED') {
clearInterval(intervalId);
return resolve(this.handleNodeRendition(nodeId, rendition.entry.content.mimeType, versionId));
return resolve(this.handleNodeRendition(nodeId, renditionId, versionId));
}
},
() => reject(new Error('Error geting version rendition'))
@@ -15,9 +15,9 @@
* limitations under the License.
*/
import { TestBed } from '@angular/core/testing';
import { fakeAsync, TestBed, tick } from '@angular/core/testing';
import { TranslationService, ViewUtilService } from '@alfresco/adf-core';
import { Rendition, RenditionEntry, RenditionPaging, RenditionsApi } from '@alfresco/js-api';
import { ContentApi, Rendition, RenditionEntry, RenditionPaging, RenditionsApi, VersionsApi } from '@alfresco/js-api';
import { AlfrescoApiService } from '../../services/alfresco-api.service';
import { RenditionService } from './rendition.service';
@@ -37,7 +37,9 @@ const getRenditionPaging = (status: Rendition.StatusEnum): RenditionPaging => ({
describe('RenditionService', () => {
let renditionService: RenditionService;
let renditionsApi: any;
let renditionsApi: jasmine.SpyObj<RenditionsApi>;
let versionsApiSpy: jasmine.SpyObj<VersionsApi>;
let contentApiSpy: jasmine.SpyObj<ContentApi>;
beforeEach(() => {
TestBed.configureTestingModule({
@@ -53,25 +55,45 @@ describe('RenditionService', () => {
getRendition: jasmine.createSpy('getRendition'),
createRendition: jasmine.createSpy('createRendition')
}
},
{
provide: VersionsApi,
useValue: {
listVersionRenditions: jasmine.createSpy('listVersionRenditions'),
createVersionRendition: jasmine.createSpy('createVersionRendition').and.returnValue(Promise.resolve()),
getVersionRendition: jasmine.createSpy('getVersionRendition')
}
},
{
provide: ContentApi,
useValue: {
getVersionRenditionUrl: jasmine.createSpy('getVersionRenditionUrl').and.returnValue('version-rendition-url')
}
}
]
});
renditionService = TestBed.inject(RenditionService);
renditionsApi = TestBed.inject(RenditionsApi);
renditionsApi = TestBed.inject(RenditionsApi) as jasmine.SpyObj<RenditionsApi>;
versionsApiSpy = TestBed.inject(VersionsApi) as jasmine.SpyObj<VersionsApi>;
contentApiSpy = TestBed.inject(ContentApi) as jasmine.SpyObj<ContentApi>;
spyOnProperty(renditionService, 'renditionsApi').and.returnValue(renditionsApi);
spyOnProperty(renditionService, 'versionsApi').and.returnValue(versionsApiSpy);
spyOnProperty(renditionService, 'contentApi').and.returnValue(contentApiSpy);
});
describe('getRendition', () => {
it('should retry getting the rendition until maxRetries if status is NOT_CREATED', async () => {
it('should retry getting the rendition until maxRetries if status is NOT_CREATED', fakeAsync(() => {
const mockRenditionPaging: RenditionPaging = getRenditionPaging(Rendition.StatusEnum.NOTCREATED);
const mockRenditionEntry: RenditionEntry = getRenditionEntry(Rendition.StatusEnum.NOTCREATED);
renditionsApi.listRenditions.and.returnValue(Promise.resolve(mockRenditionPaging));
renditionsApi.getRendition.and.returnValue(Promise.resolve(mockRenditionEntry));
await renditionService.getRendition('nodeId', 'pdf');
renditionService.getRendition('nodeId', 'pdf');
tick(5000);
expect(renditionsApi.getRendition).toHaveBeenCalledTimes(renditionService.maxRetries);
}, 10000);
}));
});
it('should return the rendition when status transitions from PENDING to CREATED', async () => {
@@ -101,4 +123,23 @@ describe('RenditionService', () => {
expect(result).toEqual(mockRenditionPaging.list.entries[0]);
expect(renditionsApi.getRendition).not.toHaveBeenCalled();
});
it('should pass renditionId (not mimeType) to getVersionRenditionUrl when version rendition transitions to CREATED', fakeAsync(() => {
const nodeId = 'nodeId';
const versionId = 'versionId';
const renditionId = 'pdf';
const mimeType = 'application/pdf';
versionsApiSpy.listVersionRenditions.and.returnValue(Promise.resolve(getRenditionPaging(Rendition.StatusEnum.NOTCREATED)));
versionsApiSpy.getVersionRendition.and.returnValue(Promise.resolve(getRenditionEntry(Rendition.StatusEnum.CREATED)));
let result: { url: string; mimeType: string };
renditionService.getNodeRendition(nodeId, versionId).then((r) => (result = r));
tick(10000);
expect(contentApiSpy.getVersionRenditionUrl).toHaveBeenCalledWith(nodeId, versionId, renditionId);
expect(contentApiSpy.getVersionRenditionUrl).not.toHaveBeenCalledWith(nodeId, versionId, mimeType);
expect(result.url).toBe('version-rendition-url');
}));
});
@@ -19,14 +19,12 @@ import { inject, Injectable } from '@angular/core';
import { SavedSearchStrategy } from '../interfaces/saved-searches-strategy.interface';
import { AuthenticationService } from '@alfresco/adf-core';
import { ReplaySubject, Observable, catchError, switchMap, take, tap, throwError, map } from 'rxjs';
import { NodeEntry, NodesApi } from '@alfresco/js-api';
import { LazyApi, NodeEntry, NodesApi } from '@alfresco/js-api';
import { SavedSearch } from '../interfaces/saved-search.interface';
import { AlfrescoApiService } from '../../services';
@Injectable()
export abstract class SavedSearchesBaseService implements SavedSearchStrategy {
private _nodesApi: NodesApi;
private static readonly SAVE_MODE_THRESHOLD = 5;
protected readonly _savedSearches$ = new ReplaySubject<SavedSearch[]>(1);
@@ -35,10 +33,8 @@ export abstract class SavedSearchesBaseService implements SavedSearchStrategy {
protected readonly apiService = inject(AlfrescoApiService);
protected readonly authService = inject(AuthenticationService);
get nodesApi(): NodesApi {
this._nodesApi = this._nodesApi ?? new NodesApi(this.apiService.getInstance());
return this._nodesApi;
}
@LazyApi((self: SavedSearchesBaseService) => new NodesApi(self.apiService.getInstance()))
declare readonly nodesApi: NodesApi;
protected abstract fetchAllSavedSearches(): Observable<SavedSearch[]>;
protected abstract updateSavedSearches(searches: SavedSearch[]): Observable<NodeEntry>;
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { NodeEntry, PreferencesApi, ContentFieldsQuery, PreferenceEntry } from '@alfresco/js-api';
import { NodeEntry, PreferencesApi, ContentFieldsQuery, PreferenceEntry, LazyApi } from '@alfresco/js-api';
import { Injectable, InjectionToken, inject } from '@angular/core';
import { Observable, of, from, throwError } from 'rxjs';
import { catchError, concatMap, first, map, switchMap, take, tap } from 'rxjs/operators';
@@ -34,18 +34,15 @@ export const SAVED_SEARCHES_SERVICE_PREFERENCES = new InjectionToken<SavedSearch
})
export class SavedSearchesService extends SavedSearchesBaseService {
private savedSearchFileNodeId: string;
private _preferencesApi: SavedSearchesPreferencesApiService;
private readonly preferencesService = inject(SAVED_SEARCHES_SERVICE_PREFERENCES, { optional: true });
get preferencesApi(): SavedSearchesPreferencesApiService {
if (this.preferencesService) {
this._preferencesApi = this.preferencesService;
return this._preferencesApi;
@LazyApi((self: SavedSearchesService) => {
if (self.preferencesService) {
return self.preferencesService;
}
this._preferencesApi = this._preferencesApi ?? new PreferencesApi(this.apiService.getInstance());
return this._preferencesApi;
}
return new PreferencesApi(self.apiService.getInstance());
})
declare readonly preferencesApi: SavedSearchesPreferencesApiService;
protected fetchAllSavedSearches(): Observable<SavedSearch[]> {
const savedSearchesMigrated = localStorage.getItem(this.getLocalStorageKey()) ?? '';
@@ -29,7 +29,8 @@ import {
SiteMembershipBodyUpdate,
SiteMembershipRequestWithPersonPaging,
SitePaging,
SitesApi
SitesApi,
LazyApi
} from '@alfresco/js-api';
import { AlfrescoApiService } from '../../services/alfresco-api.service';
@@ -39,11 +40,8 @@ import { AlfrescoApiService } from '../../services/alfresco-api.service';
export class SitesService {
private readonly apiService = inject(AlfrescoApiService);
private _sitesApi: SitesApi;
get sitesApi(): SitesApi {
this._sitesApi = this._sitesApi ?? new SitesApi(this.apiService.getInstance());
return this._sitesApi;
}
@LazyApi((self: SitesService) => new SitesApi(self.apiService.getInstance()))
declare readonly sitesApi: SitesApi;
/**
* Create a site
@@ -26,8 +26,6 @@ import { FileModel, FileUploadStatus } from '../../common/models/file.model';
import { AlfrescoApiService } from '../../services';
import { AlfrescoApiServiceMock } from '../../mock';
declare let jasmine: any;
describe('UploadService', () => {
let service: UploadService;
let appConfigService: AppConfigService;
@@ -35,6 +33,40 @@ describe('UploadService', () => {
const mockProductInfo = new BehaviorSubject<RepositoryInfo>(null);
const createMockPromiseWithEvents = (responseData?: any, shouldError = false) => {
const handlers: any = {};
const promise: any = new Promise((resolve, reject) => {
setTimeout(() => {
if (shouldError) {
if (handlers.error) {
handlers.error(responseData || { status: 404 });
}
reject(responseData);
} else {
if (handlers.success) {
handlers.success(responseData);
}
resolve(responseData);
}
}, 0);
});
promise.on = (event: string, handler: (data?: any) => void) => {
handlers[event] = handler;
return promise;
};
promise.abort = () => {
if (handlers.abort) {
handlers.abort();
}
};
promise.catch = (handler: (error: any) => void) => Promise.prototype.catch.call(promise, handler);
return promise;
};
beforeEach(() => {
TestBed.configureTestingModule({
imports: [],
@@ -75,14 +107,9 @@ describe('UploadService', () => {
uploadFileSpy = spyOn(service.uploadApi, 'uploadFile').and.callThrough();
jasmine.Ajax.install();
mockProductInfo.next({ status: { isThumbnailGenerationEnabled: true } } as RepositoryInfo);
});
afterEach(() => {
jasmine.Ajax.uninstall();
});
it('should return an empty queue if no elements are added', () => {
expect(service.getQueue().length).toEqual(0);
});
@@ -153,53 +180,49 @@ describe('UploadService', () => {
it('should make XHR done request after the file is added in the queue', (done) => {
const emitter = new EventEmitter();
const mockResponse = { entry: { id: 'node-id' } };
const mockPromise = createMockPromiseWithEvents(mockResponse);
uploadFileSpy.and.returnValue(mockPromise);
const emitterDisposable = emitter.subscribe((e) => {
expect(e.value).toBe('File uploaded');
expect(e.value).toEqual(mockResponse);
emitterDisposable.unsubscribe();
done();
});
const fileFake = new FileModel({ name: 'fake-name', size: 10 } as File, { parentId: '-root-', path: 'fake-dir' });
service.addToQueue(fileFake);
service.uploadFilesInTheQueue(emitter);
const request = jasmine.Ajax.requests.mostRecent();
expect(request.url).toBe(
'http://localhost:9876/ecm/alfresco/api/-default-/public/alfresco/versions/1/nodes/-root-/children?autoRename=true&include=allowableOperations'
);
expect(request.method).toBe('POST');
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200,
contentType: 'text/plain',
responseText: 'File uploaded'
});
expect(uploadFileSpy).toHaveBeenCalled();
});
it('should make XHR error request after an error occur', (done) => {
const emitter = new EventEmitter();
const mockPromise = createMockPromiseWithEvents({ status: 404 }, true);
uploadFileSpy.and.returnValue(mockPromise);
const emitterDisposable = emitter.subscribe((e) => {
expect(e.value).toBe('Error file uploaded');
emitterDisposable.unsubscribe();
done();
});
const fileFake = new FileModel({ name: 'fake-name', size: 10 } as File, { parentId: '-root-' });
service.addToQueue(fileFake);
service.uploadFilesInTheQueue(null, emitter);
expect(jasmine.Ajax.requests.mostRecent().url).toBe(
'http://localhost:9876/ecm/alfresco/api/-default-/public/alfresco/versions/1/nodes/-root-/children?autoRename=true&include=allowableOperations'
);
jasmine.Ajax.requests.mostRecent().respondWith({
status: 404,
contentType: 'text/plain',
responseText: 'Error file uploaded'
});
expect(uploadFileSpy).toHaveBeenCalled();
});
it('should abort file only if it is safe to abort', (done) => {
const emitter = new EventEmitter();
const mockPromise = createMockPromiseWithEvents();
uploadFileSpy.and.returnValue(mockPromise);
const emitterDisposable = emitter.subscribe((event) => {
expect(event.value).toEqual('File aborted');
emitterDisposable.unsubscribe();
@@ -217,22 +240,18 @@ describe('UploadService', () => {
it('should let file complete and then delete node if it is not safe to abort', (done) => {
const emitter = new EventEmitter();
const mockUploadResponse = { entry: { id: 'myNodeId' } };
const mockPromise = createMockPromiseWithEvents(mockUploadResponse);
uploadFileSpy.and.returnValue(mockPromise);
const deleteNodeSpy = spyOn(service.nodesApi, 'deleteNode').and.returnValue(Promise.resolve());
const emitterDisposable = emitter.subscribe((event) => {
expect(event.value).toEqual('File deleted');
emitterDisposable.unsubscribe();
const deleteRequest = jasmine.Ajax.requests.mostRecent();
expect(deleteRequest.url).toBe(
'http://localhost:9876/ecm/alfresco/api/-default-/public/alfresco/versions/1/nodes/myNodeId?permanent=true'
);
expect(deleteRequest.method).toBe('DELETE');
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200,
contentType: 'text/plain',
responseText: 'File deleted'
});
done();
if (event.value === 'File deleted') {
expect(deleteNodeSpy).toHaveBeenCalledWith('myNodeId', { permanent: true });
emitterDisposable.unsubscribe();
done();
}
});
const fileFake = new FileModel({ name: 'fake-name', size: 10 } as File);
@@ -241,41 +260,30 @@ describe('UploadService', () => {
const file = service.getQueue();
service.cancelUpload(...file);
const request = jasmine.Ajax.requests.mostRecent();
expect(request.url).toBe(
'http://localhost:9876/ecm/alfresco/api/-default-/public/alfresco/versions/1/nodes/-root-/children?autoRename=true&include=allowableOperations'
);
expect(request.method).toBe('POST');
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200,
contentType: 'json',
responseText: {
entry: {
id: 'myNodeId'
}
}
});
});
it('should delete node version when cancelling the upload of the new file version', (done) => {
const emitter = new EventEmitter();
const mockUploadResponse = {
entry: {
id: 'myNodeId',
properties: {
'cm:versionLabel': '1.1'
}
}
};
const mockPromise = createMockPromiseWithEvents(mockUploadResponse);
spyOn(service.nodesApi, 'updateNodeContent').and.returnValue(mockPromise);
const deleteVersionSpy = spyOn(service.versionsApi, 'deleteVersion').and.returnValue(Promise.resolve());
const emitterDisposable = emitter.subscribe((event) => {
expect(event.value).toEqual('File deleted');
emitterDisposable.unsubscribe();
const deleteRequest = jasmine.Ajax.requests.mostRecent();
expect(deleteRequest.url).toBe('http://localhost:9876/ecm/alfresco/api/-default-/public/alfresco/versions/1/nodes/myNodeId/versions/1.1');
expect(deleteRequest.method).toBe('DELETE');
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200,
contentType: 'text/plain',
responseText: 'File deleted'
});
done();
if (event.value === 'File deleted') {
expect(deleteVersionSpy).toHaveBeenCalledWith('myNodeId', '1.1');
emitterDisposable.unsubscribe();
done();
}
});
const fileFake = new FileModel({ name: 'fake-name', size: 10 } as File, null, 'fakeId');
@@ -284,23 +292,6 @@ describe('UploadService', () => {
const file = service.getQueue();
service.cancelUpload(...file);
const request = jasmine.Ajax.requests.mostRecent();
expect(request.url).toContain('ecm/alfresco/api/-default-/public/alfresco/versions/1/nodes/fakeId/content?include=allowableOperations');
expect(request.method).toBe('PUT');
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200,
contentType: 'json',
responseText: {
entry: {
id: 'myNodeId',
properties: {
'cm:versionLabel': '1.1'
}
}
}
});
});
it('If newVersion is set, name should be a param', () => {
@@ -331,26 +322,27 @@ describe('UploadService', () => {
it('should use custom root folder ID given to the service', (done) => {
const emitter = new EventEmitter();
const mockResponse = { entry: { id: 'node-id' } };
const mockPromise = createMockPromiseWithEvents(mockResponse);
uploadFileSpy.and.returnValue(mockPromise);
const emitterDisposable = emitter.subscribe((e) => {
expect(e.value).toBe('File uploaded');
expect(e.value).toEqual(mockResponse);
emitterDisposable.unsubscribe();
done();
});
const filesFake = new FileModel({ name: 'fake-file-name', size: 10 } as File, { parentId: '123', path: 'fake-dir' });
service.addToQueue(filesFake);
service.uploadFilesInTheQueue(emitter);
const request = jasmine.Ajax.requests.mostRecent();
expect(request.url).toContain(
'/ecm/alfresco/api/-default-/public/alfresco/versions/1/nodes/123/children?autoRename=true&include=allowableOperations'
expect(uploadFileSpy).toHaveBeenCalledWith(
jasmine.objectContaining({ name: 'fake-file-name' }),
'fake-dir',
'123',
jasmine.any(Object),
jasmine.any(Object)
);
expect(request.method).toBe('POST');
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200,
contentType: 'text/plain',
responseText: 'File uploaded'
});
});
describe('versioningEnabled', () => {
@@ -437,6 +429,13 @@ describe('UploadService', () => {
});
it('should start downloading the next one if a file of the list is aborted', (done) => {
const mockResponse1 = { entry: { id: 'node-id-1' } };
const mockResponse2 = { entry: { id: 'node-id-2' } };
const mockPromise1 = createMockPromiseWithEvents(mockResponse1);
const mockPromise2 = createMockPromiseWithEvents(mockResponse2);
uploadFileSpy.and.returnValues(mockPromise1, mockPromise2);
service.fileUploadAborted.subscribe((e) => {
expect(e).not.toBeNull();
});
@@ -23,7 +23,7 @@ import { FileModel, FileUploadProgress, FileUploadStatus } from '../models/file.
import { AppConfigService } from '@alfresco/adf-core';
import { filter } from 'rxjs/operators';
import { DiscoveryApiService } from '../../common/services/discovery-api.service';
import { NodeBodyCreate, NodesApi, UploadApi, VersionsApi } from '@alfresco/js-api';
import { LazyApi, NodeBodyCreate, NodesApi, UploadApi, VersionsApi } from '@alfresco/js-api';
import { AlfrescoApiService } from '../../services/alfresco-api.service';
const MIN_CANCELLABLE_FILE_SIZE = 1000000;
@@ -56,23 +56,14 @@ export class UploadService {
private abortedFile: string;
private isThumbnailGenerationEnabled: boolean;
private _uploadApi: UploadApi;
get uploadApi(): UploadApi {
this._uploadApi = this._uploadApi ?? new UploadApi(this.apiService.getInstance());
return this._uploadApi;
}
@LazyApi((self: UploadService) => new UploadApi(self.apiService.getInstance()))
declare readonly uploadApi: UploadApi;
private _nodesApi: NodesApi;
get nodesApi(): NodesApi {
this._nodesApi = this._nodesApi ?? new NodesApi(this.apiService.getInstance());
return this._nodesApi;
}
@LazyApi((self: UploadService) => new NodesApi(self.apiService.getInstance()))
declare readonly nodesApi: NodesApi;
private _versionsApi: VersionsApi;
get versionsApi(): VersionsApi {
this._versionsApi = this._versionsApi ?? new VersionsApi(this.apiService.getInstance());
return this._versionsApi;
}
@LazyApi((self: UploadService) => new VersionsApi(self.apiService.getInstance()))
declare readonly versionsApi: VersionsApi;
protected apiService = inject(AlfrescoApiService);
protected appConfigService = inject(AppConfigService);
@@ -11,12 +11,6 @@ $panel-properties-height: 56px !default;
margin: 12px;
.adf-property-list .adf-property .adf-property-field {
.adf-property-value:not(.adf-card-view-selectitem .adf-property-value) {
&:is(textarea) {
padding-top: 6px;
}
}
label {
font-size: 19px;
line-height: 24px;
@@ -20,7 +20,7 @@ import { AlfrescoApiService } from '../../services/alfresco-api.service';
import { Observable, defer, forkJoin } from 'rxjs';
import { PropertyGroup, PropertyGroupContainer } from '../interfaces/content-metadata.interfaces';
import { map } from 'rxjs/operators';
import { ClassesApi } from '@alfresco/js-api';
import { ClassesApi, LazyApi } from '@alfresco/js-api';
@Injectable({
providedIn: 'root'
@@ -28,11 +28,8 @@ import { ClassesApi } from '@alfresco/js-api';
export class PropertyDescriptorsService {
private readonly alfrescoApiService = inject(AlfrescoApiService);
private _classesApi: ClassesApi;
get classesApi(): ClassesApi {
this._classesApi = this._classesApi ?? new ClassesApi(this.alfrescoApiService.getInstance());
return this._classesApi;
}
@LazyApi((self: PropertyDescriptorsService) => new ClassesApi(self.alfrescoApiService.getInstance()))
declare readonly classesApi: ClassesApi;
load(groupNames: string[]): Observable<PropertyGroupContainer> {
const groupFetchStreams = groupNames
@@ -17,7 +17,7 @@
import { DestroyRef, Directive, HostListener, inject, Input, NgZone, OnChanges } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { NodeEntry, NodesApi } from '@alfresco/js-api';
import { LazyApi, NodeEntry, NodesApi } from '@alfresco/js-api';
import { ShareDialogComponent } from './content-node-share.dialog';
import { from, Observable } from 'rxjs';
@@ -45,11 +45,8 @@ export class NodeSharedDirective implements OnChanges {
@Input()
baseShareUrl: string;
_nodesApi: NodesApi;
get nodesApi(): NodesApi {
this._nodesApi = this._nodesApi ?? new NodesApi(this.alfrescoApiService.getInstance());
return this._nodesApi;
}
@LazyApi((self: NodeSharedDirective) => new NodesApi(self.alfrescoApiService.getInstance()))
declare readonly nodesApi: NodesApi;
private readonly destroyRef = inject(DestroyRef);
shareNode(nodeEntry: NodeEntry) {
@@ -16,7 +16,7 @@
*/
import { Injectable, inject } from '@angular/core';
import { NodePaging, SharedLinkBodyCreate, SharedLinkEntry, SharedlinksApi } from '@alfresco/js-api';
import { LazyApi, NodePaging, SharedLinkBodyCreate, SharedLinkEntry, SharedlinksApi } from '@alfresco/js-api';
import { Observable, from, of, Subject } from 'rxjs';
import { UserPreferencesService } from '@alfresco/adf-core';
import { catchError } from 'rxjs/operators';
@@ -31,11 +31,8 @@ export class SharedLinksApiService {
error = new Subject<{ statusCode: number; message: string }>();
private _sharedLinksApi: SharedlinksApi;
get sharedLinksApi(): SharedlinksApi {
this._sharedLinksApi = this._sharedLinksApi ?? new SharedlinksApi(this.apiService.getInstance());
return this._sharedLinksApi;
}
@LazyApi((self: SharedLinksApiService) => new SharedlinksApi(self.apiService.getInstance()))
declare readonly sharedLinksApi: SharedlinksApi;
/**
* Gets shared links available to the current user.
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { TypeEntry, TypePaging, TypesApi } from '@alfresco/js-api';
import { LazyApi, TypeEntry, TypePaging, TypesApi } from '@alfresco/js-api';
import { Injectable, inject } from '@angular/core';
import { AlfrescoApiService } from '../services/alfresco-api.service';
import { from, Observable } from 'rxjs';
@@ -27,11 +27,8 @@ import { map } from 'rxjs/operators';
export class ContentTypeService {
private readonly alfrescoApiService = inject(AlfrescoApiService);
private _typesApi: TypesApi;
get typesApi(): TypesApi {
this._typesApi = this._typesApi ?? new TypesApi(this.alfrescoApiService.getInstance());
return this._typesApi;
}
@LazyApi((self: ContentTypeService) => new TypesApi(self.alfrescoApiService.getInstance()))
declare readonly typesApi: TypesApi;
getContentTypeByPrefix(prefixedType: string): Observable<TypeEntry> {
return from(this.typesApi.getType(prefixedType));
@@ -62,11 +62,7 @@ class DownloadsApiMock extends DownloadsApi {
}
export class DownloadZipMockService extends DownloadZipService {
private _mockDownloadsApi: DownloadsApi;
get downloadsApi(): DownloadsApi {
this._mockDownloadsApi = this._mockDownloadsApi ?? new DownloadsApiMock();
return this._mockDownloadsApi;
}
override readonly downloadsApi: DownloadsApi = new DownloadsApiMock();
createDownload(payload: DownloadBodyCreate): Observable<DownloadEntry> {
return from(this.downloadsApi.createDownload(payload)).pipe(catchError((err) => of(err)));
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { DownloadEntry, DownloadBodyCreate, DownloadsApi } from '@alfresco/js-api';
import { DownloadEntry, DownloadBodyCreate, DownloadsApi, LazyApi } from '@alfresco/js-api';
import { Injectable, inject } from '@angular/core';
import { Observable, from } from 'rxjs';
import { AlfrescoApiService } from '../../../services/alfresco-api.service';
@@ -26,11 +26,8 @@ import { AlfrescoApiService } from '../../../services/alfresco-api.service';
export class DownloadZipService {
private readonly apiService = inject(AlfrescoApiService);
private _downloadsApi: DownloadsApi;
get downloadsApi(): DownloadsApi {
this._downloadsApi = this._downloadsApi ?? new DownloadsApi(this.apiService.getInstance());
return this._downloadsApi;
}
@LazyApi((self: DownloadZipService) => new DownloadsApi(self.apiService.getInstance()))
declare readonly downloadsApi: DownloadsApi;
/**
* Creates a new download.
@@ -28,7 +28,7 @@ import {
Validators
} from '@angular/forms';
import { MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { QueriesApi, SiteBodyCreate, SiteEntry, SitePaging } from '@alfresco/js-api';
import { LazyApi, QueriesApi, SiteBodyCreate, SiteEntry, SitePaging } from '@alfresco/js-api';
import { NotificationService } from '@alfresco/adf-core';
import { debounceTime, finalize, map, mergeMap, take } from 'rxjs/operators';
import { SitesService } from '../../common/services/sites.service';
@@ -101,11 +101,8 @@ export class LibraryDialogComponent implements OnInit {
];
disableCreateButton = false;
_queriesApi: QueriesApi;
get queriesApi(): QueriesApi {
this._queriesApi = this._queriesApi ?? new QueriesApi(this.alfrescoApiService.getInstance());
return this._queriesApi;
}
@LazyApi((self: LibraryDialogComponent) => new QueriesApi(self.alfrescoApiService.getInstance()))
declare readonly queriesApi: QueriesApi;
private readonly destroyRef = inject(DestroyRef);
@@ -19,7 +19,7 @@ import { Component, OnInit, ViewEncapsulation, inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { ReactiveFormsModule, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { differenceInSeconds } from 'date-fns';
import { NodeBodyLock, Node, NodeEntry, NodesApi } from '@alfresco/js-api';
import { NodeBodyLock, Node, NodeEntry, NodesApi, LazyApi } from '@alfresco/js-api';
import { CommonModule } from '@angular/common';
import { TranslatePipe } from '@ngx-translate/core';
import { MatCheckboxModule } from '@angular/material/checkbox';
@@ -55,11 +55,8 @@ export class NodeLockDialogComponent implements OnInit {
node: Node = null;
nodeName: string;
private _nodesApi: NodesApi;
get nodesApi(): NodesApi {
this._nodesApi = this._nodesApi ?? new NodesApi(this.alfrescoApi.getInstance());
return this._nodesApi;
}
@LazyApi((self: NodeLockDialogComponent) => new NodesApi(self.alfrescoApi.getInstance()))
declare readonly nodesApi: NodesApi;
ngOnInit() {
const { node } = this.data;
@@ -16,7 +16,7 @@
*/
import { Directive, HostListener, Input, OnChanges, Output, EventEmitter, SimpleChanges, inject } from '@angular/core';
import { FavoriteBodyCreate, FavoritesApi } from '@alfresco/js-api';
import { FavoriteBodyCreate, FavoritesApi, LazyApi } from '@alfresco/js-api';
import { AlfrescoApiService } from '../services/alfresco-api.service';
import { LibraryEntity } from '../interfaces/library-entity.interface';
import { NotificationService } from '@alfresco/adf-core';
@@ -39,11 +39,8 @@ export class LibraryFavoriteDirective implements OnChanges {
private targetLibrary = null;
private _favoritesApi: FavoritesApi;
get favoritesApi(): FavoritesApi {
this._favoritesApi = this._favoritesApi ?? new FavoritesApi(this.alfrescoApiService.getInstance());
return this._favoritesApi;
}
@LazyApi((self: LibraryFavoriteDirective) => new FavoritesApi(self.alfrescoApiService.getInstance()))
declare readonly favoritesApi: FavoritesApi;
@HostListener('click')
onClick() {
@@ -16,7 +16,7 @@
*/
import { Directive, EventEmitter, HostListener, Input, OnChanges, Output, SimpleChanges, inject } from '@angular/core';
import { SiteEntry, SiteMembershipRequestBodyCreate, SiteMembershipRequestEntry, SitesApi } from '@alfresco/js-api';
import { LazyApi, SiteEntry, SiteMembershipRequestBodyCreate, SiteMembershipRequestEntry, SitesApi } from '@alfresco/js-api';
import { BehaviorSubject, from, Observable } from 'rxjs';
import { AlfrescoApiService } from '../services/alfresco-api.service';
import { LibraryMembershipToggleEvent } from '../interfaces/library-membership-toggle-event.interface';
@@ -38,11 +38,8 @@ export class LibraryMembershipDirective implements OnChanges {
isJoinRequested: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
private _sitesApi: SitesApi;
get sitesApi(): SitesApi {
this._sitesApi = this._sitesApi ?? new SitesApi(this.alfrescoApiService.getInstance());
return this._sitesApi;
}
@LazyApi((self: LibraryMembershipDirective) => new SitesApi(self.alfrescoApiService.getInstance()))
declare readonly sitesApi: SitesApi;
/** Site for which to toggle the membership request. */
@Input('adf-library-membership')
@@ -18,7 +18,7 @@
/* eslint-disable @angular-eslint/no-input-rename */
import { Directive, ElementRef, EventEmitter, HostListener, Input, OnChanges, Output, inject } from '@angular/core';
import { NodeEntry, Node, DeletedNodeEntry, DeletedNode, TrashcanApi, NodesApi } from '@alfresco/js-api';
import { NodeEntry, Node, DeletedNodeEntry, DeletedNode, TrashcanApi, NodesApi, LazyApi } from '@alfresco/js-api';
import { Observable, forkJoin, from, of } from 'rxjs';
import { TranslationService } from '@alfresco/adf-core';
import { map, catchError, retry } from 'rxjs/operators';
@@ -67,17 +67,11 @@ export class NodeDeleteDirective implements OnChanges {
@Output()
delete: EventEmitter<any> = new EventEmitter();
private _trashcanApi: TrashcanApi;
get trashcanApi(): TrashcanApi {
this._trashcanApi = this._trashcanApi ?? new TrashcanApi(this.alfrescoApiService.getInstance());
return this._trashcanApi;
}
@LazyApi((self: NodeDeleteDirective) => new TrashcanApi(self.alfrescoApiService.getInstance()))
declare readonly trashcanApi: TrashcanApi;
private _nodesApi: NodesApi;
get nodesApi(): NodesApi {
this._nodesApi = this._nodesApi ?? new NodesApi(this.alfrescoApiService.getInstance());
return this._nodesApi;
}
@LazyApi((self: NodeDeleteDirective) => new NodesApi(self.alfrescoApiService.getInstance()))
declare readonly nodesApi: NodesApi;
@HostListener('click')
onClick() {
@@ -19,7 +19,7 @@ import { Directive, Input, HostListener, inject } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { DownloadService } from '@alfresco/adf-core';
import { DownloadZipDialogComponent } from '../dialogs/download-zip/download-zip.dialog';
import { ContentApi, NodeEntry, VersionEntry } from '@alfresco/js-api';
import { ContentApi, LazyApi, NodeEntry, VersionEntry } from '@alfresco/js-api';
import { AlfrescoApiService } from '../services/alfresco-api.service';
/**
@@ -35,11 +35,8 @@ export class NodeDownloadDirective {
private readonly downloadService = inject(DownloadService);
private readonly dialog = inject(MatDialog);
private _contentApi: ContentApi;
get contentApi(): ContentApi {
this._contentApi = this._contentApi ?? new ContentApi(this.apiService.getInstance());
return this._contentApi;
}
@LazyApi((self: NodeDownloadDirective) => new ContentApi(self.apiService.getInstance()))
declare readonly contentApi: ContentApi;
/** Nodes to download. */
@Input('adfNodeDownload')
@@ -18,7 +18,7 @@
/* eslint-disable @angular-eslint/no-input-rename */
import { Directive, EventEmitter, HostListener, Input, OnChanges, Output, SimpleChanges, inject } from '@angular/core';
import { FavoriteBodyCreate, NodeEntry, SharedLinkEntry, Node, SharedLink, FavoritesApi } from '@alfresco/js-api';
import { FavoriteBodyCreate, NodeEntry, SharedLinkEntry, Node, SharedLink, FavoritesApi, LazyApi } from '@alfresco/js-api';
import { Observable, from, forkJoin, of } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { AlfrescoApiService } from '../services/alfresco-api.service';
@@ -35,11 +35,8 @@ export class NodeFavoriteDirective implements OnChanges {
favorites: any[] = [];
private _favoritesApi: FavoritesApi;
get favoritesApi(): FavoritesApi {
this._favoritesApi = this._favoritesApi ?? new FavoritesApi(this.alfrescoApiService.getInstance());
return this._favoritesApi;
}
@LazyApi((self: NodeFavoriteDirective) => new FavoritesApi(self.alfrescoApiService.getInstance()))
declare readonly favoritesApi: FavoritesApi;
/** Array of nodes to toggle as favorites. */
@Input('adf-node-favorite')
@@ -18,7 +18,7 @@
/* eslint-disable @angular-eslint/component-selector, @angular-eslint/no-input-rename */
import { Directive, EventEmitter, HostListener, Input, Output, inject } from '@angular/core';
import { TrashcanApi, DeletedNodeEntry, DeletedNodesPaging } from '@alfresco/js-api';
import { TrashcanApi, DeletedNodeEntry, DeletedNodesPaging, LazyApi } from '@alfresco/js-api';
import { Observable, forkJoin, from, of } from 'rxjs';
import { tap, mergeMap, map, catchError } from 'rxjs/operators';
import { TranslationService } from '@alfresco/adf-core';
@@ -35,11 +35,8 @@ export class NodeRestoreDirective {
private readonly restoreProcessStatus;
private _trashcanApi: TrashcanApi;
get trashcanApi(): TrashcanApi {
this._trashcanApi = this._trashcanApi ?? new TrashcanApi(this.alfrescoApiService.getInstance());
return this._trashcanApi;
}
@LazyApi((self: NodeRestoreDirective) => new TrashcanApi(self.alfrescoApiService.getInstance()))
declare readonly trashcanApi: TrashcanApi;
/** Array of deleted nodes to restore. */
@Input('adf-restore')
@@ -47,7 +47,7 @@ import {
UserPreferencesService,
UserPreferenceValues
} from '@alfresco/adf-core';
import { Node, NodeEntry, NodePaging, NodesApi, Pagination } from '@alfresco/js-api';
import { LazyApi, Node, NodeEntry, NodePaging, NodesApi, Pagination } from '@alfresco/js-api';
import {
AfterContentInit,
Component,
@@ -469,11 +469,8 @@ export class DocumentListComponent extends DataTableSchema implements OnInit, On
private readonly destroyRef = inject(DestroyRef);
private _nodesApi: NodesApi;
get nodesApi(): NodesApi {
this._nodesApi = this._nodesApi ?? new NodesApi(this.alfrescoApiService.getInstance());
return this._nodesApi;
}
@LazyApi((self: DocumentListComponent) => new NodesApi(self.alfrescoApiService.getInstance()))
declare readonly nodesApi: NodesApi;
constructor() {
const appConfig = inject(AppConfigService);
@@ -493,16 +493,4 @@ describe('ShareDataTableAdapter', () => {
expect(adapter.getRowByNodeId('fake-node-id-2')).toEqual(fakeShareDataRows[1]);
});
});
it('should initialize with allowFocusOnRows as true by default', () => {
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, null);
expect(adapter.allowFocusOnRows).toBe(true);
});
it('should set allowFocusOnRows value', () => {
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, null);
expect(adapter.allowFocusOnRows).toBe(true);
adapter.setAllowFocusOnTableRows(false);
expect(adapter.allowFocusOnRows).toBe(false);
});
});
@@ -38,7 +38,6 @@ export class ShareDataTableAdapter implements DataTableAdapter {
permissionsStyle: PermissionStyleModel[];
selectedRow: DataRow;
allowDropFiles: boolean;
allowFocusOnRows = true;
set sortingMode(value: string) {
let newValue = (value || 'client').toLowerCase();
@@ -197,10 +196,6 @@ export class ShareDataTableAdapter implements DataTableAdapter {
this.imageResolver = resolver;
}
setAllowFocusOnTableRows(allow: boolean) {
this.allowFocusOnRows = allow;
}
private getFolderIcon(node: any) {
if (this.isSmartFolder(node)) {
return this.thumbnailService.getMimeTypeIcon('smartFolder');
@@ -33,7 +33,8 @@ import {
NodesApi,
SitePaging,
ResultSetPaging,
SEARCH_LANGUAGE
SEARCH_LANGUAGE,
LazyApi
} from '@alfresco/js-api';
import { Injectable, inject } from '@angular/core';
import { Observable, from, of } from 'rxjs';
@@ -45,47 +46,26 @@ const CREATE_PERMISSION: string = 'create';
export class CustomResourcesService {
private readonly apiService = inject(AlfrescoApiService);
private _peopleApi: PeopleApi;
get peopleApi(): PeopleApi {
this._peopleApi = this._peopleApi ?? new PeopleApi(this.apiService.getInstance());
return this._peopleApi;
}
@LazyApi((self: CustomResourcesService) => new PeopleApi(self.apiService.getInstance()))
declare readonly peopleApi: PeopleApi;
private _sitesApi: SitesApi;
get sitesApi(): SitesApi {
this._sitesApi = this._sitesApi ?? new SitesApi(this.apiService.getInstance());
return this._sitesApi;
}
@LazyApi((self: CustomResourcesService) => new SitesApi(self.apiService.getInstance()))
declare readonly sitesApi: SitesApi;
private _trashcanApi: TrashcanApi;
get trashcanApi(): TrashcanApi {
this._trashcanApi = this._trashcanApi ?? new TrashcanApi(this.apiService.getInstance());
return this._trashcanApi;
}
@LazyApi((self: CustomResourcesService) => new TrashcanApi(self.apiService.getInstance()))
declare readonly trashcanApi: TrashcanApi;
private _searchApi: SearchApi;
get searchApi(): SearchApi {
this._searchApi = this._searchApi ?? new SearchApi(this.apiService.getInstance());
return this._searchApi;
}
@LazyApi((self: CustomResourcesService) => new SearchApi(self.apiService.getInstance()))
declare readonly searchApi: SearchApi;
private _sharedLinksApi: SharedlinksApi;
get sharedLinksApi(): SharedlinksApi {
this._sharedLinksApi = this._sharedLinksApi ?? new SharedlinksApi(this.apiService.getInstance());
return this._sharedLinksApi;
}
@LazyApi((self: CustomResourcesService) => new SharedlinksApi(self.apiService.getInstance()))
declare readonly sharedLinksApi: SharedlinksApi;
private _favoritesApi: FavoritesApi;
get favoritesApi(): FavoritesApi {
this._favoritesApi = this._favoritesApi ?? new FavoritesApi(this.apiService.getInstance());
return this._favoritesApi;
}
@LazyApi((self: CustomResourcesService) => new FavoritesApi(self.apiService.getInstance()))
declare readonly favoritesApi: FavoritesApi;
private _nodesApi: NodesApi;
get nodesApi(): NodesApi {
this._nodesApi = this._nodesApi ?? new NodesApi(this.apiService.getInstance());
return this._nodesApi;
}
@LazyApi((self: CustomResourcesService) => new NodesApi(self.apiService.getInstance()))
declare readonly nodesApi: NodesApi;
/**
* Gets files recently accessed by a user.
@@ -23,8 +23,6 @@ import { CustomResourcesService } from './custom-resources.service';
import { NodesApiService } from '../../common';
import { provideApiTesting } from '../../testing/providers';
declare let jasmine: any;
describe('DocumentListService', () => {
let service: DocumentListService;
let customResourcesService: CustomResourcesService;
@@ -79,7 +77,6 @@ describe('DocumentListService', () => {
service = TestBed.inject(DocumentListService);
customResourcesService = TestBed.inject(CustomResourcesService);
nodesApiService = TestBed.inject(NodesApiService);
jasmine.Ajax.install();
});
it('should emit resetSelection$ when resetSelection is called', (done) => {
@@ -96,11 +93,9 @@ describe('DocumentListService', () => {
service.reload();
});
afterEach(() => {
jasmine.Ajax.uninstall();
});
it('should return the folder info', fakeAsync(() => {
spyOn(service.nodes, 'listNodeChildren').and.returnValue(Promise.resolve(fakeFolder as any));
service.getFolder('/fake-root/fake-name').subscribe((res) => {
expect(res).toBeDefined();
expect(res.list).toBeDefined();
@@ -109,12 +104,6 @@ describe('DocumentListService', () => {
expect(res.list.entries[0].entry.isFolder).toBeTruthy();
expect(res.list.entries[0].entry.name).toEqual('fake-name');
});
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200,
contentType: 'json',
responseText: fakeFolder
});
}));
it('should use rootFolderId provided in options', () => {
@@ -204,35 +193,33 @@ describe('DocumentListService', () => {
});
});
it('should delete the folder', fakeAsync(() => {
service.deleteNode('fake-id').subscribe((res) => {
expect(res).toBe('');
});
it('should delete the folder', (done) => {
spyOn(service.nodes, 'deleteNode').and.returnValue(Promise.resolve() as any);
jasmine.Ajax.requests.mostRecent().respondWith({
status: 204,
contentType: 'json'
service.deleteNode('fake-id').subscribe(() => {
expect(service.nodes.deleteNode).toHaveBeenCalledWith('fake-id');
done();
});
}));
});
it('should copy a node', (done) => {
service.copyNode('node-id', 'parent-id').subscribe(() => done());
const mockResponse = { entry: { id: 'copied-node-id' } } as NodeEntry;
const copyNodeSpy = spyOn(service.nodes, 'copyNode').and.returnValue(Promise.resolve(mockResponse));
expect(jasmine.Ajax.requests.mostRecent().method).toBe('POST');
expect(jasmine.Ajax.requests.mostRecent().url).toContain('/nodes/node-id/copy');
expect(jasmine.Ajax.requests.mostRecent().params).toEqual(JSON.stringify({ targetParentId: 'parent-id' }));
jasmine.Ajax.requests.mostRecent().respondWith({ status: 200, contentType: 'json' });
service.copyNode('node-id', 'parent-id').subscribe(() => {
expect(copyNodeSpy).toHaveBeenCalledWith('node-id', { targetParentId: 'parent-id' });
done();
});
});
it('should move a node', (done) => {
service.moveNode('node-id', 'parent-id').subscribe(() => done());
const mockResponse = { entry: { id: 'moved-node-id' } } as NodeEntry;
const moveNodeSpy = spyOn(service.nodes, 'moveNode').and.returnValue(Promise.resolve(mockResponse));
expect(jasmine.Ajax.requests.mostRecent().method).toBe('POST');
expect(jasmine.Ajax.requests.mostRecent().url).toContain('/nodes/node-id/move');
expect(jasmine.Ajax.requests.mostRecent().params).toEqual(JSON.stringify({ targetParentId: 'parent-id' }));
jasmine.Ajax.requests.mostRecent().respondWith({ status: 200, contentType: 'json' });
service.moveNode('node-id', 'parent-id').subscribe(() => {
expect(moveNodeSpy).toHaveBeenCalledWith('node-id', { targetParentId: 'parent-id' });
done();
});
});
it('should call isCustomSource from customResourcesService when isCustomSourceService is called', () => {
@@ -18,7 +18,7 @@
import { PaginationModel } from '@alfresco/adf-core';
import { NodesApiService } from '../../common/services/nodes-api.service';
import { inject, Injectable } from '@angular/core';
import { Node, NodeEntry, NodePaging, NodesApi } from '@alfresco/js-api';
import { LazyApi, Node, NodeEntry, NodePaging, NodesApi } from '@alfresco/js-api';
import { DocumentLoaderNode } from '../models/document-folder.model';
import { Observable, from, forkJoin, Subject } from 'rxjs';
import { map } from 'rxjs/operators';
@@ -36,11 +36,8 @@ export class DocumentListService implements DocumentListLoader {
private readonly apiService = inject(AlfrescoApiService);
private readonly customResourcesService = inject(CustomResourcesService);
private _nodesApi: NodesApi;
get nodes(): NodesApi {
this._nodesApi = this._nodesApi ?? new NodesApi(this.apiService.getInstance());
return this._nodesApi;
}
@LazyApi((self: DocumentListService) => new NodesApi(self.apiService.getInstance()))
declare readonly nodes: NodesApi;
private readonly _reload = new Subject<void>();
private readonly _resetSelection = new Subject<void>();
@@ -16,7 +16,7 @@
*/
import { Injectable, inject } from '@angular/core';
import { ContentIncludeQuery, Group, GroupEntry, GroupsApi } from '@alfresco/js-api';
import { ContentIncludeQuery, Group, GroupEntry, GroupsApi, LazyApi } from '@alfresco/js-api';
import { AlfrescoApiService } from '../../services/alfresco-api.service';
import { from, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@@ -27,11 +27,8 @@ import { map } from 'rxjs/operators';
export class GroupService {
private readonly alfrescoApiService = inject(AlfrescoApiService);
private _groupsApi: GroupsApi;
get groupsApi(): GroupsApi {
this._groupsApi = this._groupsApi ?? new GroupsApi(this.alfrescoApiService.getInstance());
return this._groupsApi;
}
@LazyApi((self: GroupService) => new GroupsApi(self.alfrescoApiService.getInstance()))
declare readonly groupsApi: GroupsApi;
async listAllGroupMembershipsForPerson(personId: string, opts?: any, accumulator = []): Promise<GroupEntry[]> {
const groupsPaginated = await this.groupsApi.listGroupMembershipsForPerson(personId, opts);
+12 -9
View File
@@ -446,11 +446,11 @@
"IN_LAST": "Wert erforderlich",
"START_DATE": {
"REQUIRED": "Startdatum erforderlich",
"INVALID_FORMAT": "Startdatum ungültig"
"INVALID_FORMAT": "Startdatum ungültig. Das Datum muss im Format '{{ requiredFormat }} ' sein"
},
"END_DATE": {
"REQUIRED": "Enddatum erforderlich",
"INVALID_FORMAT": "Enddatum ungültig"
"INVALID_FORMAT": "Enddatum ungültig. Das Datum muss im Format '{{ requiredFormat }} ' sein"
}
},
"ARIA_LABEL": {
@@ -503,7 +503,7 @@
},
"CONTENT_TYPE": {
"DIALOG": {
"TITLE": "Content-Typ ändern",
"TITLE": "Inhalts-Typ ändern",
"DESCRIPTION": "Wenn Sie diese Änderung am Content-Typ vornehmen, werden dem Dokument einige Eigenschaften und gespeicherte Metadaten dauerhaft hinzugefügt.",
"CONFIRM": "Möchten Sie den Content-Typ wirklich ändern?",
"CANCEL": "Abbrechen",
@@ -533,7 +533,7 @@
"LINK-WITH-EXPIRY-SETTINGS": "Es wurde ein neuer Link mit Ablaufeinstellungen erstellt",
"EXPIRES": "Läuft ab am",
"LINK-EXPIRY-DATE": "Ablaufdatum des Links",
"EXPIRATION-LABEL": "Ablaufdatum",
"EXPIRATION-LABEL": "Ablaufdatum. Datum im MM/DD/JJJ Format eingeben",
"EXPIRATION-PLACEHOLDER": "TT.MM.JJJJ",
"CLIPBOARD-MESSAGE": "Link in die Zwischenablage kopiert",
"CLOSE": "Schließen",
@@ -566,7 +566,7 @@
"CLOSE-ACTION": "Abbrechen",
"BASE-DIALOG-TITLE": "Es wird nach Gruppen oder Personen gesucht, die hinzugefügt werden können...",
"BASE_DIALOG_SCREEN_READER_TITLE": "Benutzer- oder Gruppenberechtigung hinzufügen",
"EVERYONE": "Jeder",
"EVERYONE": "JEDER",
"USER-GROUP-LIST": "Benutzer- oder Gruppenliste",
"REMOVE_USER_GROUP": "Entfernen"
},
@@ -619,11 +619,14 @@
"ADF-TREE-VIEW": {
"MISSING-ID": "Keine Node-ID angegeben!",
"ACCESSIBILITY": {
"ARIA_LABEL": "{{ name }} wechseln"
"ARIA_LABEL": "{{ name }} umschalten"
}
},
"ADF-TREE": {
"LOAD-MORE-BUTTON": "Mehr laden {{ name }}"
"LOAD-MORE-BUTTON": "Mehr laden {{ name }}",
"ACTIONS": {
"TOOLTIP": "Aktionsmenü öffnen"
}
},
"LIBRARY": {
"DIALOG": {
@@ -674,8 +677,8 @@
},
"BREADCRUMB": {
"ARIA-LABEL": {
"BREADCRUMB": "Breadcrumb",
"DROPDOWN": "Dropdown"
"BREADCRUMB": "Breadcrumb-Navigation",
"DROPDOWN": "Breadcrumb-Menü für {{folderName}} öffnen"
},
"HEADER": {
"SELECTED": "Ausgewählt ({{ count }})"
+13 -10
View File
@@ -193,15 +193,15 @@
},
"ADF_FILE_UPLOAD": {
"BUTTON": {
"MINIMIZE": "Minimize",
"MAXIMIZE": "Maximize",
"MINIMIZE": "Minimise",
"MAXIMIZE": "Maximise",
"CLOSE": "Close",
"STOP_ALL": "Stop uploads",
"STOP_FILE": "Stop upload",
"UPLOAD_SUCCESSFUL": "Upload successful"
},
"STATUS": {
"FILE_CANCELED_STATUS": "Canceled",
"FILE_CANCELED_STATUS": "Cancelled",
"FILE_DONE_STATUS": "Uploaded"
},
"CONFIRMATION": {
@@ -217,9 +217,9 @@
"ARIA-LABEL": {
"VERSION": "File version {{ version }}",
"DIALOG": "Upload list",
"DIALOG_MAXIMIZE": "Maximize upload dialog",
"DIALOG_MINIMIZE": "Minimize upload dialog",
"DIALOG_CLOSE": "Close upload dialog",
"DIALOG_MAXIMIZE": "Maximise upload dialogue",
"DIALOG_MINIMIZE": "Minimise upload dialogue",
"DIALOG_CLOSE": "Close upload dialogue",
"STOP_ALL": "Stop uploads",
"UPLOAD_SUCCESSFUL": "Uploaded successfully file {{ file }}",
"STOP_FILE": "Stop file {{ file }}",
@@ -244,7 +244,7 @@
}
},
"MESSAGES": {
"UPLOAD_CANCELED": "Upload canceled",
"UPLOAD_CANCELED": "Upload cancelled",
"UPLOAD_PROGRESS": "Uploaded {{ completed }} / {{ total }}",
"UPLOAD_ERROR": "{{ total }} upload unsuccessful",
"UPLOAD_ERRORS": "{{ total }} uploads unsuccessful",
@@ -623,7 +623,10 @@
}
},
"ADF-TREE": {
"LOAD-MORE-BUTTON": "Load more {{ name }}"
"LOAD-MORE-BUTTON": "Load more {{ name }}",
"ACTIONS": {
"TOOLTIP": "Open actions menu"
}
},
"LIBRARY": {
"DIALOG": {
@@ -691,7 +694,7 @@
"DESCRIPTION": "Description",
"DATA_TYPE": "Data Type",
"DIALOG": {
"TITLE": "Customize Properties",
"TITLE": "Customise Properties",
"DESCRIPTION": "Manage the properties associated with selected file(s). Choose from property aspects listed below, to expose and apply additional metadata and functionality",
"RESET": "Reset",
"CLEAR": "Clear",
@@ -717,7 +720,7 @@
},
"INFO": {
"JOINED": "Library joined",
"JOIN_CANCELED": "Canceled the request to join the library",
"JOIN_CANCELED": "Cancelled the request to join the library",
"JOIN_REQUESTED": "Request sent to join this library"
}
},
+9 -6
View File
@@ -446,11 +446,11 @@
"IN_LAST": "Valor requerido",
"START_DATE": {
"REQUIRED": "Se requiere la fecha de inicio",
"INVALID_FORMAT": "Fecha de inicio no válida"
"INVALID_FORMAT": "Fecha de inicio no válida. La fecha debe tener el formato '{{ requiredFormat }}'"
},
"END_DATE": {
"REQUIRED": "Se requiere la fecha de fin",
"INVALID_FORMAT": "Fecha de fin no válida"
"INVALID_FORMAT": "Fecha de finalización no válida. La fecha debe tener el formato '{{ requiredFormat }}'"
}
},
"ARIA_LABEL": {
@@ -533,7 +533,7 @@
"LINK-WITH-EXPIRY-SETTINGS": "Se ha generado un nuevo enlace con la configuración de vencimiento",
"EXPIRES": "Caduca el",
"LINK-EXPIRY-DATE": "Fecha de vencimiento del enlace",
"EXPIRATION-LABEL": "Fecha de caducidad",
"EXPIRATION-LABEL": "Fecha de expiración. Introduzca la fecha en formato MM/DD/AAAA",
"EXPIRATION-PLACEHOLDER": "DD/MM/AAAA",
"CLIPBOARD-MESSAGE": "Enlace copiado al portapapeles",
"CLOSE": "Cerrar",
@@ -623,7 +623,10 @@
}
},
"ADF-TREE": {
"LOAD-MORE-BUTTON": "Cargar más {{ name }}"
"LOAD-MORE-BUTTON": "Cargar más {{ name }}",
"ACTIONS": {
"TOOLTIP": "Abrir menú de acciones"
}
},
"LIBRARY": {
"DIALOG": {
@@ -674,8 +677,8 @@
},
"BREADCRUMB": {
"ARIA-LABEL": {
"BREADCRUMB": "Ruta de navegación",
"DROPDOWN": "Desplegable"
"BREADCRUMB": "Navegación por migas de pan",
"DROPDOWN": "Abrir menú de migas de pan para {{folderName}}"
},
"HEADER": {
"SELECTED": "Seleccionado(s) ({{ count }})"
+9 -6
View File
@@ -446,11 +446,11 @@
"IN_LAST": "Valeur obligatoire",
"START_DATE": {
"REQUIRED": "Date de début obligatoire",
"INVALID_FORMAT": "Date de début non valide"
"INVALID_FORMAT": "Date de début invalide. La date doit être au format « {{ requiredFormat }} »"
},
"END_DATE": {
"REQUIRED": "Date de fin obligatoire",
"INVALID_FORMAT": "Date de fin non valide"
"INVALID_FORMAT": "Date de fin invalide. La date doit être au format « {{ requiredFormat }} »"
}
},
"ARIA_LABEL": {
@@ -533,7 +533,7 @@
"LINK-WITH-EXPIRY-SETTINGS": "Un nouveau lien a été généré avec des paramètres d'expiration",
"EXPIRES": "Expire le",
"LINK-EXPIRY-DATE": "Date d'expiration du lien",
"EXPIRATION-LABEL": "Date d'expiration",
"EXPIRATION-LABEL": "Date dexpiration. Saisissez la date au format MM/DD/YYYY",
"EXPIRATION-PLACEHOLDER": "MM/JJ/AAAA",
"CLIPBOARD-MESSAGE": "Lien copié dans le Presse-papiers",
"CLOSE": "Fermer",
@@ -623,7 +623,10 @@
}
},
"ADF-TREE": {
"LOAD-MORE-BUTTON": "Charger plus de {{ name }}"
"LOAD-MORE-BUTTON": "Charger plus de {{ name }}",
"ACTIONS": {
"TOOLTIP": "Ouvrir le menu actions"
}
},
"LIBRARY": {
"DIALOG": {
@@ -674,8 +677,8 @@
},
"BREADCRUMB": {
"ARIA-LABEL": {
"BREADCRUMB": "Fil d'Ariane",
"DROPDOWN": "Liste déroulante"
"BREADCRUMB": "Navigation Fil dAriane",
"DROPDOWN": "Afficher le fil dAriane pour {{folderName}}"
},
"HEADER": {
"SELECTED": "({{ count }}) sélectionnés"
+9 -6
View File
@@ -446,11 +446,11 @@
"IN_LAST": "Valore obbligatorio",
"START_DATE": {
"REQUIRED": "Data di inizio obbligatoria",
"INVALID_FORMAT": "Data di inizio non valida"
"INVALID_FORMAT": "Data di inizio non valida. La data deve avere il formato '{{ requiredFormat }}'"
},
"END_DATE": {
"REQUIRED": "Data di fine obbligatoria",
"INVALID_FORMAT": "Data di fine non valida"
"INVALID_FORMAT": "Data di fine non valida. La data deve avere il formato '{{ requiredFormat }}'"
}
},
"ARIA_LABEL": {
@@ -533,7 +533,7 @@
"LINK-WITH-EXPIRY-SETTINGS": "Il nuovo link è stato creato con impostazioni di scadenza",
"EXPIRES": "Scade il",
"LINK-EXPIRY-DATE": "Data di scadenza link",
"EXPIRATION-LABEL": "Data di scadenza",
"EXPIRATION-LABEL": "Data scadenza. Immettere la data nel formato MM/GG/AAAA",
"EXPIRATION-PLACEHOLDER": "MM/GG/AAAA",
"CLIPBOARD-MESSAGE": "Link copiato negli appunti",
"CLOSE": "Chiudi",
@@ -623,7 +623,10 @@
}
},
"ADF-TREE": {
"LOAD-MORE-BUTTON": "Carica altri {{ name }}"
"LOAD-MORE-BUTTON": "Carica altri {{ name }}",
"ACTIONS": {
"TOOLTIP": "Apri menu azioni"
}
},
"LIBRARY": {
"DIALOG": {
@@ -674,8 +677,8 @@
},
"BREADCRUMB": {
"ARIA-LABEL": {
"BREADCRUMB": "Breadcrumb",
"DROPDOWN": "Elenco a discesa"
"BREADCRUMB": "Navigazione breadcrump",
"DROPDOWN": "Apri il menu breadcrump per {{folderName}}"
},
"HEADER": {
"SELECTED": "Selezionate ({{ count }})"
+9 -6
View File
@@ -446,11 +446,11 @@
"IN_LAST": "Wymagana wartość",
"START_DATE": {
"REQUIRED": "Data rozpoczęcia wymagana",
"INVALID_FORMAT": "Data rozpoczęcia jest nieprawidłowa"
"INVALID_FORMAT": "Data rozpoczęcia jest nieprawidłowa. Data musi być w formacie „{{ requiredFormat }}”"
},
"END_DATE": {
"REQUIRED": "Wymagana data zakończenia",
"INVALID_FORMAT": "Data zakończenia jest nieprawidłowa"
"INVALID_FORMAT": "Data zakończenia jest nieprawidłowa. Data musi być w formacie „{{ requiredFormat }}”"
}
},
"ARIA_LABEL": {
@@ -533,7 +533,7 @@
"LINK-WITH-EXPIRY-SETTINGS": "Wygenerowano nowy link z ustawieniami wygaśnięcia",
"EXPIRES": "Wygasa",
"LINK-EXPIRY-DATE": "Data wygaśnięcia łącza",
"EXPIRATION-LABEL": "Data ważności",
"EXPIRATION-LABEL": "Data ważności. Wprowadź datę w formacie MM/DD/RRRR",
"EXPIRATION-PLACEHOLDER": "MM/DD/RRRR",
"CLIPBOARD-MESSAGE": "Link został skopiowany do schowka.",
"CLOSE": "Zamknij",
@@ -623,7 +623,10 @@
}
},
"ADF-TREE": {
"LOAD-MORE-BUTTON": "Wczytaj {{ name }}"
"LOAD-MORE-BUTTON": "Wczytaj {{ name }}",
"ACTIONS": {
"TOOLTIP": "Otwórz menu akcji"
}
},
"LIBRARY": {
"DIALOG": {
@@ -674,8 +677,8 @@
},
"BREADCRUMB": {
"ARIA-LABEL": {
"BREADCRUMB": "Ścieżka nawigacyjna",
"DROPDOWN": "Rozwiń"
"BREADCRUMB": "Nawigacja okruszkowa",
"DROPDOWN": "Otwórz menu okruszkowe dla {{folderName}}"
},
"HEADER": {
"SELECTED": "Wybrano ({{ count }})"
+9 -6
View File
@@ -446,11 +446,11 @@
"IN_LAST": "O valor é obrigatório",
"START_DATE": {
"REQUIRED": "A data de início é obrigatório",
"INVALID_FORMAT": "Data de início inválida"
"INVALID_FORMAT": "Data inicial inválida. A data deve estar no formato '{{ requiredFormat }}'"
},
"END_DATE": {
"REQUIRED": "Data final obrigatória",
"INVALID_FORMAT": "Data final inválida"
"INVALID_FORMAT": "Data final inválida. A data deve estar no formato '{{ requiredFormat }}'"
}
},
"ARIA_LABEL": {
@@ -533,7 +533,7 @@
"LINK-WITH-EXPIRY-SETTINGS": "Foi gerada uma nova ligação com definições de expiração",
"EXPIRES": "Expira em",
"LINK-EXPIRY-DATE": "Data de expiração da ligação",
"EXPIRATION-LABEL": "Data de validade",
"EXPIRATION-LABEL": "Data de expiração. Insira a data no formato MM/DD/AAAA",
"EXPIRATION-PLACEHOLDER": "DD/MM/AAAA",
"CLIPBOARD-MESSAGE": "Ligação copiada para a área de transferência",
"CLOSE": "Fechar",
@@ -623,7 +623,10 @@
}
},
"ADF-TREE": {
"LOAD-MORE-BUTTON": "Carregar mais {{ name }}"
"LOAD-MORE-BUTTON": "Carregar mais {{ name }}",
"ACTIONS": {
"TOOLTIP": "Abrir menu de ações"
}
},
"LIBRARY": {
"DIALOG": {
@@ -674,8 +677,8 @@
},
"BREADCRUMB": {
"ARIA-LABEL": {
"BREADCRUMB": "Breadcrumb",
"DROPDOWN": "Lista suspensa"
"BREADCRUMB": "Navegação por breadcrumb",
"DROPDOWN": "Abrir menu de navegação por breadcrumb para {{folderName}}"
},
"HEADER": {
"SELECTED": "Selecionado({{ count }})"
@@ -23,6 +23,7 @@ import {
HoldBulkStatusEntry,
HoldEntry,
HoldPaging,
LazyApi,
LegalHoldApi,
RequestQuery
} from '@alfresco/js-api';
@@ -37,11 +38,8 @@ import { AlfrescoApiService } from '../../services/alfresco-api.service';
export class LegalHoldService {
private readonly apiService = inject(AlfrescoApiService);
private _legalHoldApi: LegalHoldApi;
get legalHoldApi(): LegalHoldApi {
this._legalHoldApi = this._legalHoldApi ?? new LegalHoldApi(this.apiService.getInstance());
return this._legalHoldApi;
}
@LazyApi((self: LegalHoldService) => new LegalHoldApi(self.apiService.getInstance()))
declare readonly legalHoldApi: LegalHoldApi;
/**
* Gets the list of holds available in the file plan.
@@ -20,7 +20,7 @@ import { MatDialog, MatDialogConfig } from '@angular/material/dialog';
import { AlfrescoApiService } from '../services/alfresco-api.service';
import { NewVersionUploaderDialogComponent } from './new-version-uploader.dialog';
import { VersionsApi } from '@alfresco/js-api';
import { VersionsApi, LazyApi } from '@alfresco/js-api';
import { NewVersionUploaderData, NewVersionUploaderDialogData } from './models';
import { Observable } from 'rxjs';
import { OverlayContainer } from '@angular/cdk/overlay';
@@ -34,11 +34,8 @@ export class NewVersionUploaderService {
private readonly dialog = inject(MatDialog);
private readonly overlayContainer = inject(OverlayContainer);
private _versionsApi: VersionsApi;
get versionsApi(): VersionsApi {
this._versionsApi = this._versionsApi ?? new VersionsApi(this.apiService.getInstance());
return this._versionsApi;
}
@LazyApi((self: NewVersionUploaderService) => new VersionsApi(self.apiService.getInstance()))
declare readonly versionsApi: VersionsApi;
/**
* Open a dialog NewVersionUploaderDialogComponent to display:
@@ -25,8 +25,6 @@ import { EMPTY, of } from 'rxjs';
import { AlfrescoApiService } from '../../services';
import { AlfrescoApiServiceMock } from '../../mock';
declare let jasmine: any;
describe('NodeCommentsService', () => {
let service: NodeCommentsService;
@@ -40,15 +38,12 @@ describe('NodeCommentsService', () => {
]
});
service = TestBed.inject(NodeCommentsService);
jasmine.Ajax.install();
});
afterEach(() => {
jasmine.Ajax.uninstall();
});
describe('Node comments', () => {
it('should add a comment node ', (done) => {
spyOn(service.commentsApi, 'createComment').and.returnValue(Promise.resolve(fakeContentComment as any));
service.add('999', 'fake-comment-message').subscribe((res: CommentModel) => {
expect(res).toBeDefined();
expect(res.id).not.toEqual(null);
@@ -59,15 +54,11 @@ describe('NodeCommentsService', () => {
expect(res.createdBy.lastName).toEqual('lastName');
done();
});
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200,
contentType: 'application/json',
responseText: JSON.stringify(fakeContentComment)
});
});
it('should return the nodes comments ', (done) => {
spyOn(service.commentsApi, 'listComments').and.returnValue(Promise.resolve(fakeContentComments as any));
service.get('999').subscribe((res: CommentModel[]) => {
expect(res).toBeDefined();
expect(res.length).toEqual(2);
@@ -75,12 +66,6 @@ describe('NodeCommentsService', () => {
expect(res[1].message).toEqual('fake-message-2');
done();
});
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200,
contentType: 'application/json',
responseText: JSON.stringify(fakeContentComments)
});
});
it('should return avatar image URL for given userId', () => {
@@ -16,7 +16,7 @@
*/
import { CommentModel, CommentsService, User } from '@alfresco/adf-core';
import { CommentEntry, CommentsApi, Comment, PeopleApi } from '@alfresco/js-api';
import { CommentEntry, CommentsApi, Comment, PeopleApi, LazyApi } from '@alfresco/js-api';
import { Injectable, inject } from '@angular/core';
import { Observable, from } from 'rxjs';
import { map } from 'rxjs/operators';
@@ -28,17 +28,11 @@ import { AlfrescoApiService } from '../../services/alfresco-api.service';
export class NodeCommentsService implements CommentsService {
private readonly apiService = inject(AlfrescoApiService);
private _commentsApi: CommentsApi;
get commentsApi(): CommentsApi {
this._commentsApi = this._commentsApi ?? new CommentsApi(this.apiService.getInstance());
return this._commentsApi;
}
@LazyApi((self: NodeCommentsService) => new CommentsApi(self.apiService.getInstance()))
declare readonly commentsApi: CommentsApi;
private _peopleApi: PeopleApi;
get peopleApi(): PeopleApi {
this._peopleApi = this._peopleApi ?? new PeopleApi(this.apiService.getInstance());
return this._peopleApi;
}
@LazyApi((self: NodeCommentsService) => new PeopleApi(self.apiService.getInstance()))
declare readonly peopleApi: PeopleApi;
/**
* Gets all comments that have been added to a task.
@@ -18,11 +18,12 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { UserNameColumnComponent } from './user-name-column.component';
import { NodeEntry } from '@alfresco/js-api';
import { UnitTestingUtils } from '@alfresco/adf-core';
describe('UserNameColumnComponent', () => {
let fixture: ComponentFixture<UserNameColumnComponent>;
let component: UserNameColumnComponent;
let element: HTMLElement;
let testingUtils: UnitTestingUtils;
const person = {
firstName: 'fake',
lastName: 'user',
@@ -34,13 +35,15 @@ describe('UserNameColumnComponent', () => {
displayName: 'fake authority'
};
const getUserName = (): string => testingUtils.getInnerTextByCSS('span.adf-user-name-column');
beforeEach(() => {
TestBed.configureTestingModule({
imports: [UserNameColumnComponent]
});
fixture = TestBed.createComponent(UserNameColumnComponent);
component = fixture.componentInstance;
element = fixture.nativeElement;
testingUtils = new UnitTestingUtils(fixture.debugElement);
fixture.detectChanges();
});
@@ -55,8 +58,8 @@ describe('UserNameColumnComponent', () => {
};
component.ngOnInit();
fixture.detectChanges();
expect(element.querySelector('[title="fake user"]').textContent).toContain('fake user');
expect(element.querySelector('[title="fake@test.com"]').textContent).toContain('fake@test.com');
expect(getUserName()).toBe('fake user');
expect(testingUtils.getInnerTextByCSS('.adf-user-email-column')).toBe('fake@test.com');
});
it('should render person value from node', (done) => {
@@ -95,7 +98,7 @@ describe('UserNameColumnComponent', () => {
};
component.ngOnInit();
fixture.detectChanges();
expect(element.querySelector('[title="fake authority"]').textContent.trim()).toBe('fake authority');
expect(getUserName()).toBe('fake authority');
});
it('should display group id when display name is not provided', () => {
@@ -110,20 +113,35 @@ describe('UserNameColumnComponent', () => {
};
component.ngOnInit();
fixture.detectChanges();
expect(element.querySelector('[title="fake_group_id"]').textContent.trim()).toBe('fake_group_id');
expect(getUserName()).toBe('fake_group_id');
});
it('should render group for authorityId', () => {
it('should render group for authorityId when authorityDisplayName is not provided', () => {
component.context = {
row: {
obj: {
authorityId: 'fake-id'
authorityId: 'fake-id',
authorityDisplayName: null
}
}
};
component.ngOnInit();
fixture.detectChanges();
expect(element.querySelector('[title=fake-id]').textContent.trim()).toBe('fake-id');
expect(getUserName()).toBe('fake-id');
});
it('should render authority display name when provided', () => {
component.context = {
row: {
obj: {
authorityId: 'fake-id',
authorityDisplayName: 'Fake authority'
}
}
};
component.ngOnInit();
fixture.detectChanges();
expect(getUserName()).toBe('Fake authority');
});
it('should render person value from node', () => {
@@ -137,7 +155,7 @@ describe('UserNameColumnComponent', () => {
} as NodeEntry;
component.ngOnInit();
fixture.detectChanges();
expect(element.querySelector('[title="Fake authority"]').textContent.trim()).toBe('Fake authority');
expect(getUserName()).toBe('Fake authority');
});
});
});
@@ -52,8 +52,8 @@ export class UserNameColumnComponent implements OnInit {
ngOnInit() {
if (this.context != null) {
const { person, group, authorityId } = this.context.row.obj?.entry ?? this.context.row.obj;
const permissionGroup = authorityId ? ({ displayName: authorityId } as Group) : null;
const { person, group, authorityId, authorityDisplayName } = this.context.row.obj?.entry ?? this.context.row.obj;
const permissionGroup: Group | null = authorityId ? { displayName: authorityDisplayName, id: authorityId } : null;
this.updatePerson(person);
this.updateGroup(group || permissionGroup);
}
@@ -19,6 +19,7 @@ import { PermissionElement } from '@alfresco/js-api';
export class PermissionDisplayModel implements PermissionElement {
authorityId?: string;
authorityDisplayName?: string;
name?: string;
accessStatus?: 'ALLOWED' | 'DENIED' | string;
isInherited: boolean = false;
@@ -28,6 +29,7 @@ export class PermissionDisplayModel implements PermissionElement {
constructor(obj?: any) {
if (obj) {
this.authorityId = obj.authorityId;
this.authorityDisplayName = obj.authorityDisplayName;
this.name = obj.name;
this.accessStatus = obj.accessStatus;
this.isInherited = obj.isInherited !== null && obj.isInherited !== undefined ? obj.isInherited : false;
@@ -19,7 +19,7 @@ import { AlfrescoApiService } from '../../services/alfresco-api.service';
import { TranslationService } from '@alfresco/adf-core';
import { NodesApiService } from '../../common/services/nodes-api.service';
import { EcmUserModel } from '../../common/models/ecm-user.model';
import { Group, GroupMemberPaging, GroupsApi, Node, PathElement, PermissionElement, SearchRequest } from '@alfresco/js-api';
import { Group, GroupMemberPaging, GroupsApi, LazyApi, Node, PathElement, PermissionElement, SearchRequest } from '@alfresco/js-api';
import { SearchService } from '../../search/services/search.service';
import { Injectable, inject } from '@angular/core';
import { forkJoin, from, Observable, of, throwError } from 'rxjs';
@@ -36,11 +36,8 @@ export class NodePermissionService {
private readonly nodeService = inject(NodesApiService);
private readonly translation = inject(TranslationService);
private _groupsApi: GroupsApi;
get groupsApi(): GroupsApi {
this._groupsApi = this._groupsApi ?? new GroupsApi(this.apiService.getInstance());
return this._groupsApi;
}
@LazyApi((self: NodePermissionService) => new GroupsApi(self.apiService.getInstance()))
declare readonly groupsApi: GroupsApi;
/**
* Gets a list of roles for the current node.
@@ -16,7 +16,7 @@
*/
import { Injectable, inject } from '@angular/core';
import { PredictionsApi, PredictionPaging, ReviewStatus } from '@alfresco/js-api';
import { PredictionsApi, PredictionPaging, ReviewStatus, LazyApi } from '@alfresco/js-api';
import { from, Observable } from 'rxjs';
import { AlfrescoApiService } from '../../services/alfresco-api.service';
@@ -24,12 +24,8 @@ import { AlfrescoApiService } from '../../services/alfresco-api.service';
export class PredictionService {
private readonly apiService = inject(AlfrescoApiService);
private _predictionsApi: PredictionsApi;
get predictionsApi(): PredictionsApi {
this._predictionsApi = this._predictionsApi ?? new PredictionsApi(this.apiService.getInstance());
return this._predictionsApi;
}
@LazyApi((self: PredictionService) => new PredictionsApi(self.apiService.getInstance()))
declare readonly predictionsApi: PredictionsApi;
/**
* Get predictions for a given node
@@ -16,7 +16,7 @@
*/
import { Injectable, inject } from '@angular/core';
import { AiAnswerEntry, KnowledgeRetrievalConfigEntry, QuestionModel, QuestionRequest, SearchAiApi } from '@alfresco/js-api';
import { AiAnswerEntry, KnowledgeRetrievalConfigEntry, LazyApi, QuestionModel, QuestionRequest, SearchAiApi } from '@alfresco/js-api';
import { BehaviorSubject, from, Observable } from 'rxjs';
import { SelectionState } from '@alfresco/adf-extensions';
import { TranslateService } from '@ngx-translate/core';
@@ -33,12 +33,9 @@ export class SearchAiService {
private readonly toggleSearchAiInput = new BehaviorSubject<SearchAiInputState>({
active: false
});
private _searchAiApi: SearchAiApi;
get searchAiApi(): SearchAiApi {
this._searchAiApi = this._searchAiApi ?? new SearchAiApi(this.apiService.getInstance());
return this._searchAiApi;
}
@LazyApi((self: SearchAiService) => new SearchAiApi(self.apiService.getInstance()))
declare readonly searchAiApi: SearchAiApi;
toggleSearchAiInput$ = this.toggleSearchAiInput.asObservable();
@@ -18,7 +18,7 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { SearchFilterAutocompleteChipsComponent } from './search-filter-autocomplete-chips.component';
import { EMPTY, of, ReplaySubject } from 'rxjs';
import { of, ReplaySubject } from 'rxjs';
import { AutocompleteField, AutocompleteOption } from '../../models/autocomplete-option.interface';
import { TagService } from '../../../tag/services/tag.service';
import { SitesService } from '../../../common/services/sites.service';
@@ -33,13 +33,7 @@ describe('SearchFilterAutocompleteChipsComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [SearchFilterAutocompleteChipsComponent],
providers: [
{
provide: TagService,
useValue: { getAllTheTags: () => EMPTY }
}
]
imports: [SearchFilterAutocompleteChipsComponent]
});
fixture = TestBed.createComponent(SearchFilterAutocompleteChipsComponent);
@@ -86,23 +80,6 @@ describe('SearchFilterAutocompleteChipsComponent', () => {
});
});
it('should load tags if field = TAG', (done) => {
const tagPagingMock = {
list: {
pagination: {},
entries: [{ entry: { tag: 'tag1', id: 'id1' } }, { entry: { tag: 'tag2', id: 'id2' } }]
}
};
component.settings.field = AutocompleteField.TAG;
spyOn(tagService, 'getAllTheTags').and.returnValue(of(tagPagingMock));
component.ngOnInit();
component.autocompleteOptions$.subscribe((result) => {
expect(result).toEqual([{ value: 'tag1' }, { value: 'tag2' }]);
done();
});
});
it('should update display value when options changes', () => {
const newOption = 'option1';
spyOn(component, 'onOptionsChange').and.callThrough();
@@ -215,13 +192,9 @@ describe('SearchFilterAutocompleteChipsComponent', () => {
it('should use id if present, otherwise value, in LOCATION query fragment', () => {
component.settings.field = AutocompleteField.LOCATION;
component.settings.autocompleteOptions = [];
component.selectedOptions = [
{ id: 'site1', value: 'Marketing' },
{ value: 'custom' }
];
component.selectedOptions = [{ id: 'site1', value: 'Marketing' }, { value: 'custom' }];
component.submitValues();
expect(component.context.queryFragments[component.id])
.toBe('SITE:"site1" OR SITE:"custom"');
expect(component.context.queryFragments[component.id]).toBe('SITE:"site1" OR SITE:"custom"');
});
it('should still call sitesService.getSites when input is empty for LOCATION field', () => {
@@ -251,6 +224,22 @@ describe('SearchFilterAutocompleteChipsComponent', () => {
expect(searchSpy).toHaveBeenCalledWith('', 0, 15);
});
it('should search for tags if field = TAG and input is not empty', () => {
component.settings.field = AutocompleteField.TAG;
const searchSpy = spyOn(tagService, 'searchTags').and.returnValue(
of({
list: {
pagination: {},
entries: [{ entry: { tag: 'tag1', id: 'id1' } }, { entry: { tag: 'tag2', id: 'id2' } }]
}
})
);
component.onInputChange('tag');
expect(searchSpy).toHaveBeenCalledWith('tag', { orderBy: 'tag', direction: 'asc' }, false, 0, 15);
});
describe('optionComparator', () => {
it('should return false if either option is undefined', () => {
expect(component.optionComparator(undefined, { value: 'A' })).toBe(false);
@@ -258,7 +247,7 @@ describe('SearchFilterAutocompleteChipsComponent', () => {
});
it('should compare by id if both have id', () => {
expect(component.optionComparator({ id: 'abc', value: 'B' } , { id: 'ABC', value: 'B' })).toBe(true);
expect(component.optionComparator({ id: 'abc', value: 'B' }, { id: 'ABC', value: 'B' })).toBe(true);
expect(component.optionComparator({ id: 'abc', value: 'B' }, { id: 'def', value: 'B' })).toBe(false);
});
@@ -124,6 +124,8 @@ export class SearchFilterAutocompleteChipsComponent implements SearchWidget, OnI
onInputChange(value: string) {
if (this.settings.field === AutocompleteField.CATEGORIES) {
this.searchForExistingCategories(value);
} else if (this.settings.field === AutocompleteField.TAG) {
this.searchForExistingTags(value);
} else if (this.settings.field === AutocompleteField.LOCATION) {
this.populateSitesOptions();
}
@@ -166,13 +168,7 @@ export class SearchFilterAutocompleteChipsComponent implements SearchWidget, OnI
private setOptions() {
switch (this.settings.field) {
case AutocompleteField.TAG:
this.tagService.getAllTheTags().subscribe((tagPaging) => {
this.autocompleteOptionsSubject$.next(
tagPaging.list.entries.map((tag) => ({
value: tag.entry.tag
}))
);
});
this.autocompleteOptionsSubject$.next([]);
break;
case AutocompleteField.CATEGORIES:
this.autocompleteOptionsSubject$.next([]);
@@ -197,6 +193,17 @@ export class SearchFilterAutocompleteChipsComponent implements SearchWidget, OnI
});
}
private searchForExistingTags(searchTerm: string) {
this.tagService.searchTags(searchTerm, { orderBy: 'tag', direction: 'asc' }, false, 0, 15).subscribe((existingTagsResult) => {
this.autocompleteOptionsSubject$.next(
existingTagsResult.list.entries.map((tag) => ({
id: tag.entry.id,
value: tag.entry.tag
}))
);
});
}
private populateSitesOptions(): void {
this.sitesService
.getSites()
@@ -20,18 +20,26 @@
</button>
<mat-menu #filter="matMenu" class="adf-filter-menu adf-search-filter-menu" (closed)="onClosed()">
<div #filterContainer role="menuitem" tabindex="0" (keydown.tab)="$event.stopPropagation()">
<div (click)="$event.stopPropagation()" role="button" tabindex="0" (keyup.enter)="$event.stopPropagation()" class="adf-filter-container">
<div class="adf-filter-title">{{ category?.name | translate }}</div>
<adf-search-widget-container
(keypress)="onKeyPressed($event, menuTrigger)"
[id]="category?.id"
[selector]="category?.component?.selector"
[settings]="category?.component?.settings"
[value]="initialValue"
[useHeaderQueryBuilder]="true"
/>
</div>
<fieldset
#filterContainer
tabindex="0"
[attr.aria-labelledby]="'filter-legend-' + category?.id"
(click)="$event.stopPropagation()"
(keyup.enter)="$event.stopPropagation()"
(keydown.tab)="$event.stopPropagation()"
class="adf-filter-container adf-filter-fieldset"
>
<legend class="adf-filter-title" [id]="'filter-legend-' + category?.id">
{{ category?.name | translate }}
</legend>
<adf-search-widget-container
(keypress)="onKeyPressed($event, menuTrigger)"
[id]="category?.id"
[selector]="category?.component?.selector"
[settings]="category?.component?.settings"
[value]="initialValue"
[useHeaderQueryBuilder]="true"
/>
<mat-dialog-actions class="adf-filter-actions">
<button
mat-button
@@ -52,6 +60,6 @@
{{ 'SEARCH.SEARCH_HEADER.APPLY' | translate | uppercase }}
</button>
</mat-dialog-actions>
</div>
</fieldset>
</mat-menu>
</div>
@@ -15,10 +15,17 @@
}
}
&-fieldset {
border: none;
margin: 0;
padding: 0;
min-inline-size: 0;
}
&-container {
display: flex;
flex-direction: column;
padding: 15.5px 15px 10px;
padding: 0;
color: var(--adf-theme-foreground-text-color-087);
.adf-facet-buttons {
@@ -36,9 +43,11 @@
&-title {
font-size: 1.1em;
padding-bottom: 5px;
padding: 16px 0 0 16px;
color: var(--adf-theme-foreground-text-color-087);
-webkit-font-smoothing: subpixel-antialiased;
float: none;
width: 100%;
}
}
@@ -51,6 +60,10 @@
padding: 0;
}
.adf-search-checklist {
margin: 4px 0 0 16px;
}
.adf-filter-actions {
display: flex;
justify-content: flex-end;
@@ -19,7 +19,7 @@ import { Subject } from 'rxjs';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { SearchService } from '../../services/search.service';
import { SearchHeaderQueryBuilderService } from '../../services/search-header-query-builder.service';
import { By, DomSanitizer } from '@angular/platform-browser';
import { DomSanitizer } from '@angular/platform-browser';
import { SearchFilterContainerComponent } from './search-filter-container.component';
import { SearchCategory } from '../../models/search-category.interface';
import { HarnessLoader } from '@angular/cdk/testing';
@@ -141,7 +141,7 @@ describe('SearchFilterContainerComponent', () => {
await menu.open();
component.widgetContainer.componentRef.instance.value = 'searchText';
const widgetContainer = fixture.debugElement.query(By.css('adf-search-widget-container'));
const widgetContainer = unitTestingUtils.getByCSS('adf-search-widget-container');
widgetContainer.triggerEventHandler('keypress', { key: 'Enter' });
fixture.detectChanges();
@@ -207,5 +207,30 @@ describe('SearchFilterContainerComponent', () => {
await menu.close();
expect(await menu.isFocused()).toBe(true);
});
it('should use a fieldset with aria-labelledby pointing to the legend', async () => {
const menu = await loader.getHarness(MatMenuHarness);
await menu.open();
fixture.detectChanges();
const fieldset = unitTestingUtils.getByCSS('fieldset.adf-filter-fieldset');
const legend = unitTestingUtils.getByCSS('legend.adf-filter-title');
expect(fieldset).toBeTruthy();
expect(legend).toBeTruthy();
const legendId = legend.nativeElement.getAttribute('id');
expect(legendId).toBe('filter-legend-' + mockCategory.id);
expect(fieldset.nativeElement.getAttribute('aria-labelledby')).toBe(legendId);
});
it('should have the legend text matching the category name', async () => {
const menu = await loader.getHarness(MatMenuHarness);
await menu.open();
fixture.detectChanges();
const legendText = unitTestingUtils.getInnerTextByCSS('legend.adf-filter-title');
expect(legendText.trim()).toBe(mockCategory.name);
});
});
});
@@ -38,8 +38,7 @@ export const LogicalSearchFields = {
export type LogicalSearchFields = (typeof LogicalSearchFields)[keyof typeof LogicalSearchFields];
export type LogicalSearchConditionEnumValuedKeys = { [T in LogicalSearchFields]: string };
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface LogicalSearchCondition extends LogicalSearchConditionEnumValuedKeys {}
export type LogicalSearchCondition = LogicalSearchConditionEnumValuedKeys;
@Component({
selector: 'adf-search-logical-filter',
@@ -18,6 +18,7 @@
import { BehaviorSubject, from, Observable, ReplaySubject, Subject } from 'rxjs';
import { AppConfigService } from '@alfresco/adf-core';
import {
LazyApi,
RequestFacetFields,
RequestHighlight,
RequestScope,
@@ -43,11 +44,9 @@ import { ActivatedRoute, Router } from '@angular/router';
export abstract class BaseQueryBuilderService {
private readonly router = inject(Router);
private readonly activatedRoute = inject(ActivatedRoute);
private _searchApi: SearchApi;
get searchApi(): SearchApi {
this._searchApi = this._searchApi ?? new SearchApi(this.alfrescoApiService.getInstance());
return this._searchApi;
}
@LazyApi((self: BaseQueryBuilderService) => new SearchApi(self.alfrescoApiService.getInstance()))
declare readonly searchApi: SearchApi;
/* Stream that emits the search configuration whenever the user change the search forms */
configUpdated = new Subject<SearchConfiguration>();
@@ -693,7 +692,7 @@ export abstract class BaseQueryBuilderService {
} else {
const configurations = this.loadConfiguration();
if (Array.isArray(configurations)) {
const defaultConfig = configurations.find(config => config.default);
const defaultConfig = configurations.find((config) => config.default);
if (defaultConfig && this.selectedConfigurationId !== defaultConfig.id) {
this.setSelectedConfiguration(defaultConfig.id);
}
@@ -16,7 +16,7 @@
*/
import { inject, Injectable } from '@angular/core';
import { NodePaging, QueriesApi, SearchRequest, ResultSetPaging, SearchApi } from '@alfresco/js-api';
import { NodePaging, QueriesApi, SearchRequest, ResultSetPaging, SearchApi, LazyApi } from '@alfresco/js-api';
import { Observable, Subject, from } from 'rxjs';
import { AlfrescoApiService } from '../../services/alfresco-api.service';
import { SearchConfigurationService } from './search-configuration.service';
@@ -30,17 +30,11 @@ export class SearchService {
dataLoaded = new Subject<ResultSetPaging>();
private _queriesApi: QueriesApi;
get queriesApi(): QueriesApi {
this._queriesApi = this._queriesApi ?? new QueriesApi(this.apiService.getInstance());
return this._queriesApi;
}
@LazyApi((self: SearchService) => new QueriesApi(self.apiService.getInstance()))
declare readonly queriesApi: QueriesApi;
private _searchApi: SearchApi;
get searchApi(): SearchApi {
this._searchApi = this._searchApi ?? new SearchApi(this.apiService.getInstance());
return this._searchApi;
}
@LazyApi((self: SearchService) => new SearchApi(self.apiService.getInstance()))
declare readonly searchApi: SearchApi;
/**
* Gets a list of nodes that match the given search criteria.
@@ -30,7 +30,8 @@ import {
AuthorityClearanceApi,
AuthorityClearanceGroupPaging,
NodeSecurityMarkBody,
GsGroupInclude
GsGroupInclude,
LazyApi
} from '@alfresco/js-api';
import { UserPreferencesService } from '@alfresco/adf-core';
import { finalize } from 'rxjs/operators';
@@ -59,26 +60,19 @@ export class SecurityControlsService {
private readonly loadingSource = new BehaviorSubject<boolean>(true);
loading$ = this.loadingSource.asObservable();
private securityGroup: SecurityGroupsApi;
private securityMark: SecurityMarksApi;
private authorityClearance: AuthorityClearanceApi;
get groupsApi(): SecurityGroupsApi {
return this.securityGroup || (this.securityGroup = new SecurityGroupsApi(this.apiService.getInstance()));
}
get marksApi(): SecurityMarksApi {
return this.securityMark || (this.securityMark = new SecurityMarksApi(this.apiService.getInstance()));
}
get authorityClearanceApi(): AuthorityClearanceApi {
return this.authorityClearance || (this.authorityClearance = new AuthorityClearanceApi(this.apiService.getInstance()));
}
get reloadAuthorityClearance(): Subject<void> {
return this._reloadAuthorityClearance;
}
@LazyApi((self: SecurityControlsService) => new SecurityGroupsApi(self.apiService.getInstance()))
declare readonly groupsApi: SecurityGroupsApi;
@LazyApi((self: SecurityControlsService) => new SecurityMarksApi(self.apiService.getInstance()))
declare readonly marksApi: SecurityMarksApi;
@LazyApi((self: SecurityControlsService) => new AuthorityClearanceApi(self.apiService.getInstance()))
declare readonly authorityClearanceApi: AuthorityClearanceApi;
/**
* Get All security groups
*
@@ -20,7 +20,7 @@ import { AppConfigService, UserPreferencesService } from '@alfresco/adf-core';
import { EventEmitter, Injectable, Output, inject } from '@angular/core';
import { from, Observable } from 'rxjs';
import { map, tap } from 'rxjs/operators';
import { TagBody, TagEntry, TagPaging, TagsApi } from '@alfresco/js-api';
import { LazyApi, TagBody, TagEntry, TagPaging, TagsApi } from '@alfresco/js-api';
@Injectable({
providedIn: 'root'
@@ -30,11 +30,8 @@ export class TagService {
private readonly userPreferencesService = inject(UserPreferencesService);
private readonly appConfigService = inject(AppConfigService);
private _tagsApi: TagsApi;
get tagsApi(): TagsApi {
this._tagsApi = this._tagsApi ?? new TagsApi(this.apiService.getInstance());
return this._tagsApi;
}
@LazyApi((self: TagService) => new TagsApi(self.apiService.getInstance()))
declare readonly tagsApi: TagsApi;
/** Emitted when tag information is updated. */
@Output()
@@ -50,7 +50,7 @@
(contextmenu)="contextMenuSource = node"
>
<div class="adf-tree-expand-collapse-container">
<button
<button
*ngIf="node.hasChildren"
class="adf-tree-expand-collapse-button"
(click)="expandCollapseNode(node)"
@@ -98,13 +98,22 @@
<div class="adf-tree-actions">
<button mat-icon-button
[matMenuTriggerFor]="menu"
[attr.aria-label]="'ADF-TREE.ACTIONS.TOOLTIP' | translate"
[attr.id]="'action_menu_right_' + node.id">
<mat-icon adf-icon="more_vert" />
</button>
<mat-menu #menu="matMenu">
<ng-template
[ngTemplateOutlet]="nodeActionsMenuTemplate"
[ngTemplateOutletContext]="{ node: node }" />
@for (option of contextMenuOptions; track $index) {
<button
mat-menu-item
[title]="option.title | translate"
(click)="contextMenuOptionSelected.emit({row: node, contextMenuOption: option})">
@if (option?.model?.icon) {
<mat-icon [adf-icon]="option.model.icon" aria-hidden="true" />
}
<span>{{ option.title | translate }}</span>
</button>
}
</mat-menu>
</div>
</mat-tree-node>
@@ -17,7 +17,7 @@
import { TreeComponent } from './tree.component';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ContextMenuDirective, UserPreferencesService } from '@alfresco/adf-core';
import { ContextMenuDirective, UnitTestingUtils, UserPreferencesService } from '@alfresco/adf-core';
import { TreeNode, TreeNodeType } from '../models/tree-node.interface';
import { singleNode, treeNodesChildrenMockExpanded, treeNodesMock, treeNodesMockExpanded, treeNodesNoChildrenMock } from '../mock/tree-node.mock';
import { of, Subject } from 'rxjs';
@@ -28,35 +28,31 @@ import { SelectionChange } from '@angular/cdk/collections';
import { DebugElement } from '@angular/core';
import { HarnessLoader } from '@angular/cdk/testing';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { MatProgressSpinnerHarness } from '@angular/material/progress-spinner/testing';
import { MatCheckboxHarness } from '@angular/material/checkbox/testing';
import { MatIconHarness } from '@angular/material/icon/testing';
describe('TreeComponent', () => {
let fixture: ComponentFixture<TreeComponent<TreeNode>>;
let component: TreeComponent<TreeNode>;
let userPreferenceService: UserPreferencesService;
let loader: HarnessLoader;
let testingUtils: UnitTestingUtils;
const composeNodeSelector = (nodeId: string) => `[data-automation-id="node_${nodeId}"]`;
const getNode = (nodeId: string) => testingUtils.getByCSS(composeNodeSelector(nodeId));
const getNode = (nodeId: string) => fixture.debugElement.query(By.css(composeNodeSelector(nodeId)));
const clickDisplayNameElement = (nodeId: string) => testingUtils.clickByCSS(`${composeNodeSelector(nodeId)} .adf-tree-cell-value`);
const getDisplayNameElement = (nodeId: string) => fixture.nativeElement.querySelector(`${composeNodeSelector(nodeId)} .adf-tree-cell-value`);
const getDisplayNameValue = (nodeId: string) => getDisplayNameElement(nodeId).innerText.trim();
const getDisplayNameValue = (nodeId: string) => testingUtils.getInnerTextByCSS(`${composeNodeSelector(nodeId)} .adf-tree-cell-value`);
const getNodePadding = (nodeId: string) => parseInt(getComputedStyle(getNode(nodeId).nativeElement).paddingLeft, 10);
const getNodeSpinner = async (nodeId: string) =>
loader.getHarnessOrNull(MatProgressSpinnerHarness.with({ ancestor: composeNodeSelector(nodeId) }));
const getNodeSpinner = async (nodeId: string) => testingUtils.getMatProgressSpinnerWithAncestorByDataAutomationId(`node_${nodeId}`);
const getExpandCollapseBtn = (nodeId: string) =>
fixture.nativeElement.querySelector(`${composeNodeSelector(nodeId)} .adf-tree-expand-collapse-button`);
const clickExpandCollapseBtn = (nodeId: string) => testingUtils.clickByCSS(`${composeNodeSelector(nodeId)} .adf-tree-expand-collapse-button`);
const tickCheckbox = (index: number) => {
const selector = `[data-automation-id="${index === 0 ? 'has-children-node-checkbox' : 'no-children-node-checkbox'}"]`;
const nodeCheckboxes = fixture.debugElement.queryAll(By.css(selector));
const nodeCheckboxes = testingUtils.getAllByCSS(selector);
nodeCheckboxes[index].nativeElement.dispatchEvent(new Event('change'));
};
@@ -70,6 +66,7 @@ describe('TreeComponent', () => {
loader = TestbedHarnessEnvironment.loader(fixture);
component = fixture.componentInstance;
userPreferenceService = TestBed.inject(UserPreferencesService);
testingUtils = new UnitTestingUtils(fixture.debugElement, loader);
});
afterEach(() => {
@@ -101,8 +98,8 @@ describe('TreeComponent', () => {
spyOn(component, 'isEmpty').and.returnValue(false);
component.displayName = 'test';
fixture.detectChanges();
const treeHeaderDisplayName = fixture.nativeElement.querySelector(`[data-automation-id="tree-header-display-name"]`);
expect(treeHeaderDisplayName.innerText.trim()).toBe('test');
const treeHeaderDisplayName = testingUtils.getByDataAutomationId('tree-header-display-name');
expect(treeHeaderDisplayName.nativeElement.innerText.trim()).toBe('test');
});
it('should show a list of nodes', () => {
@@ -138,8 +135,8 @@ describe('TreeComponent', () => {
component.loadingRoot$ = of(true);
fixture.detectChanges();
const matSpinnerElement = await loader.getHarnessOrNull(MatProgressSpinnerHarness.with({ ancestor: '.adf-tree-loading-spinner-container' }));
expect(matSpinnerElement).not.toBeNull();
const matSpinnerElement = await testingUtils.getMatProgressSpinnerWithAncestorByCSS('.adf-tree-loading-spinner-container');
expect(await matSpinnerElement.getMode()).toBe('indeterminate');
});
it('should show provided expand/collapse icons', async () => {
@@ -148,7 +145,7 @@ describe('TreeComponent', () => {
component.collapseIcon = 'chevron_left';
component.treeService.collapseNode(component.treeService.treeNodes[0]);
fixture.detectChanges();
const icon = await loader.getHarnessOrNull(MatIconHarness.with({ ancestor: '.adf-tree-expand-collapse-button' }));
const icon = await testingUtils.getMatIconWithAncestorByCSS('.adf-tree-expand-collapse-button');
expect(await icon.getName()).toContain('folder');
spyOn(component.treeService.treeControl, 'isExpanded').and.returnValue(true);
fixture.detectChanges();
@@ -158,7 +155,7 @@ describe('TreeComponent', () => {
it('when node has more items to load loadMore node should appear', () => {
component.treeService.treeNodes = Array.from(treeNodesMockExpanded);
fixture.detectChanges();
const loadMoreNode = fixture.nativeElement.querySelector('.adf-tree-load-more-row');
const loadMoreNode = testingUtils.getByCSS('.adf-tree-load-more-row');
expect(loadMoreNode).not.toBeNull();
});
@@ -186,7 +183,7 @@ describe('TreeComponent', () => {
fixture.detectChanges();
const collapseSpy = spyOn(component.treeService, 'collapseNode');
spyOn(component.treeService.treeControl, 'isExpanded').and.returnValue(true);
getExpandCollapseBtn(component.treeService.treeNodes[0].id).dispatchEvent(new Event('click'));
clickExpandCollapseBtn(component.treeService.treeNodes[0].id);
expect(collapseSpy).toHaveBeenCalledWith(component.treeService.treeNodes[0]);
});
@@ -206,7 +203,7 @@ describe('TreeComponent', () => {
fixture.detectChanges();
const collapseSpy = spyOn(component.treeService, 'expandNode');
spyOn(component.treeService.treeControl, 'isExpanded').and.returnValue(false);
getExpandCollapseBtn(component.treeService.treeNodes[0].id).dispatchEvent(new Event('click'));
clickExpandCollapseBtn(component.treeService.treeNodes[0].id);
expect(collapseSpy).toHaveBeenCalledWith(component.treeService.treeNodes[0], treeNodesMockExpanded);
});
@@ -215,7 +212,7 @@ describe('TreeComponent', () => {
fixture.detectChanges();
spyOn(component.treeService, 'collapseNode');
spyOn(component.treeService.treeControl, 'isExpanded').and.returnValue(true);
getDisplayNameElement(component.treeService.treeNodes[0].id).dispatchEvent(new Event('click'));
clickDisplayNameElement(component.treeService.treeNodes[0].id);
expect(component.treeService.collapseNode).toHaveBeenCalledWith(component.treeService.treeNodes[0]);
});
@@ -224,7 +221,7 @@ describe('TreeComponent', () => {
fixture.detectChanges();
spyOn(component.treeService, 'expandNode');
spyOn(component.treeService.treeControl, 'isExpanded').and.returnValue(false);
getDisplayNameElement(component.treeService.treeNodes[0].id).dispatchEvent(new Event('click'));
clickDisplayNameElement(component.treeService.treeNodes[0].id);
expect(component.treeService.expandNode).toHaveBeenCalledWith(component.treeService.treeNodes[0], treeNodesMockExpanded);
});
@@ -242,7 +239,7 @@ describe('TreeComponent', () => {
fixture.detectChanges();
spyOn(component.treeService, 'collapseNode');
spyOn(component.treeService.treeControl, 'isExpanded').and.returnValue(true);
getDisplayNameElement(component.treeService.treeNodes[0].id).dispatchEvent(new Event('click'));
clickDisplayNameElement(component.treeService.treeNodes[0].id);
expect(component.treeService.collapseNode).not.toHaveBeenCalled();
});
@@ -260,7 +257,7 @@ describe('TreeComponent', () => {
fixture.detectChanges();
spyOn(component.treeService, 'expandNode');
spyOn(component.treeService.treeControl, 'isExpanded').and.returnValue(false);
getDisplayNameElement(component.treeService.treeNodes[0].id).dispatchEvent(new Event('click'));
clickDisplayNameElement(component.treeService.treeNodes[0].id);
expect(component.treeService.expandNode).not.toHaveBeenCalled();
});
@@ -376,10 +373,16 @@ describe('TreeComponent', () => {
contextMenu = node.injector.get(ContextMenuDirective);
contextMenuOption1 = {
title: optionTitle1,
model: {
icon: 'label'
},
subject: new Subject()
};
contextMenuOption2 = {
title: optionTitle2,
model: {
icon: 'edit'
},
subject: new Subject()
};
});
@@ -400,10 +403,16 @@ describe('TreeComponent', () => {
expect(contextMenu.links).toEqual([
{
title: optionTitle1,
model: {
icon: 'label'
},
subject: jasmine.any(Subject)
},
{
title: optionTitle2,
model: {
icon: 'edit'
},
subject: jasmine.any(Subject)
}
]);
@@ -454,5 +463,19 @@ describe('TreeComponent', () => {
row: treeNodesMockExpanded[0]
});
});
it('should display set of context menu options when tree actions button is clicked', async () => {
component.contextMenuOptions = [contextMenuOption1, contextMenuOption2];
fixture.detectChanges();
const menu = await testingUtils.getMatMenuByCSS('#action_menu_right_testId1');
await menu.open();
expect(await menu.isOpen()).toBeTrue();
expect(component.contextMenuOptions.length).toEqual(2);
const menuItems = await menu.getItems();
expect(menuItems.length).toEqual(2);
expect(await menuItems[0].getText()).toEqual(`${contextMenuOption1.model.icon}${optionTitle1}`);
expect(await menuItems[1].getText()).toEqual(`${contextMenuOption2.model.icon}${optionTitle2}`);
});
});
});
@@ -71,10 +71,6 @@ export class TreeComponent<T extends TreeNode> implements OnInit, OnDestroy {
@Input()
public emptyContentTemplate: TemplateRef<any>;
/** TemplateRef to provide context menu items for context menu displayed on each row*/
@Input()
public nodeActionsMenuTemplate: TemplateRef<any>;
/** Variable defining if tree header should be sticky. By default set to false */
@Input()
@HostBinding('class.adf-tree-sticky-header')
@@ -17,21 +17,15 @@
import { Injectable, inject } from '@angular/core';
import { AlfrescoApiService } from '../services/alfresco-api.service';
import { ContentApi } from '@alfresco/js-api';
import { ContentApi, LazyApi } from '@alfresco/js-api';
import { Observable, of } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class ContentVersionService {
private readonly alfrescoApi = inject(AlfrescoApiService);
private _contentApi: ContentApi;
get contentApi(): ContentApi {
if (!this._contentApi) {
this._contentApi = new ContentApi(this.alfrescoApi.getInstance());
}
return this._contentApi;
}
@LazyApi((self: ContentVersionService) => new ContentApi(self.alfrescoApi.getInstance()))
declare readonly contentApi: ContentApi;
/**
* Get content URL for the given nodeId and specific version.
@@ -18,7 +18,7 @@
import { ConfirmDialogComponent, IconModule } from '@alfresco/adf-core';
import { AlfrescoApiService } from '../services/alfresco-api.service';
import { Component, DestroyRef, EventEmitter, inject, Input, OnChanges, OnInit, Output, ViewChild, ViewEncapsulation } from '@angular/core';
import { ContentApi, ContentPagingQuery, Node, NodeEntry, NodesApi, VersionEntry, VersionsApi } from '@alfresco/js-api';
import { ContentApi, ContentPagingQuery, LazyApi, Node, NodeEntry, NodesApi, VersionEntry, VersionsApi } from '@alfresco/js-api';
import { MatDialog } from '@angular/material/dialog';
import { ContentVersionService } from './content-version.service';
import { ContentService } from '../common';
@@ -77,23 +77,14 @@ export class VersionListComponent implements OnChanges, OnInit {
private readonly contentVersionService = inject(ContentVersionService);
private readonly dialog = inject(MatDialog);
private _contentApi: ContentApi;
get contentApi(): ContentApi {
this._contentApi = this._contentApi ?? new ContentApi(this.alfrescoApi.getInstance());
return this._contentApi;
}
@LazyApi((self: VersionListComponent) => new ContentApi(self.alfrescoApi.getInstance()))
declare readonly contentApi: ContentApi;
private _versionsApi: VersionsApi;
get versionsApi(): VersionsApi {
this._versionsApi = this._versionsApi ?? new VersionsApi(this.alfrescoApi.getInstance());
return this._versionsApi;
}
@LazyApi((self: VersionListComponent) => new VersionsApi(self.alfrescoApi.getInstance()))
declare readonly versionsApi: VersionsApi;
private _nodesApi: NodesApi;
get nodesApi(): NodesApi {
this._nodesApi = this._nodesApi ?? new NodesApi(this.alfrescoApi.getInstance());
return this._nodesApi;
}
@LazyApi((self: VersionListComponent) => new NodesApi(self.alfrescoApi.getInstance()))
declare readonly nodesApi: NodesApi;
versionsDataSource: VersionListDataSource;
latestVersion: VersionEntry;
@@ -45,7 +45,7 @@ import {
ViewUtilService
} from '@alfresco/adf-core';
import { AlfrescoApiService } from '../../services/alfresco-api.service';
import { ContentApi, Node, NodeEntry, NodesApi, RenditionEntry, SharedlinksApi, Version, VersionEntry, VersionsApi } from '@alfresco/js-api';
import { ContentApi, LazyApi, Node, NodeEntry, NodesApi, RenditionEntry, SharedlinksApi, Version, VersionEntry, VersionsApi } from '@alfresco/js-api';
import { RenditionService } from '../../common/services/rendition.service';
import { MatDialog } from '@angular/material/dialog';
import { filter } from 'rxjs/operators';
@@ -240,29 +240,17 @@ export class AlfrescoViewerComponent implements OnChanges, OnInit {
sidebarRightTemplateContext: { node: Node } = { node: null };
sidebarLeftTemplateContext: { node: Node } = { node: null };
private _sharedLinksApi: SharedlinksApi;
get sharedLinksApi(): SharedlinksApi {
this._sharedLinksApi = this._sharedLinksApi ?? new SharedlinksApi(this.apiService.getInstance());
return this._sharedLinksApi;
}
@LazyApi((self: AlfrescoViewerComponent) => new SharedlinksApi(self.apiService.getInstance()))
declare readonly sharedLinksApi: SharedlinksApi;
private _versionsApi: VersionsApi;
get versionsApi(): VersionsApi {
this._versionsApi = this._versionsApi ?? new VersionsApi(this.apiService.getInstance());
return this._versionsApi;
}
@LazyApi((self: AlfrescoViewerComponent) => new VersionsApi(self.apiService.getInstance()))
declare readonly versionsApi: VersionsApi;
private _nodesApi: NodesApi;
get nodesApi(): NodesApi {
this._nodesApi = this._nodesApi ?? new NodesApi(this.apiService.getInstance());
return this._nodesApi;
}
@LazyApi((self: AlfrescoViewerComponent) => new NodesApi(self.apiService.getInstance()))
declare readonly nodesApi: NodesApi;
private _contentApi: ContentApi;
get contentApi(): ContentApi {
this._contentApi = this._contentApi ?? new ContentApi(this.apiService.getInstance());
return this._contentApi;
}
@LazyApi((self: AlfrescoViewerComponent) => new ContentApi(self.apiService.getInstance()))
declare readonly contentApi: ContentApi;
private readonly destroyRef = inject(DestroyRef);
@@ -22,6 +22,7 @@ import { FeaturesDirective } from './features.directive';
import { UnitTestingUtils } from '../../../../src/lib/testing/unit-testing-utils';
@Component({
selector: 'adf-test-features-enabled',
template: `
<div>
<div id="underFeatureFlag" *adfForFeatures="features"></div>
@@ -34,6 +35,7 @@ class TestWithEnabledFlagComponent {
features = 'feature1';
}
@Component({
selector: 'adf-test-features-disabled',
template: `
<div>
<div id="underFeatureFlag" *adfForFeatures="features"></div>
@@ -22,6 +22,7 @@ import { NotFeaturesDirective } from './not-features.directive';
import { UnitTestingUtils } from '../../../../src/lib/testing/unit-testing-utils';
@Component({
selector: 'adf-test-not-features-enabled',
template: `
<div>
<div id="underFeatureFlag" *adfNotForFeatures="features"></div>
@@ -34,6 +35,7 @@ class TestWithEnabledFlagComponent {
}
@Component({
selector: 'adf-test-not-features-disabled',
template: `
<div>
<div id="underFeatureFlag" *adfNotForFeatures="features"></div>
+7 -12
View File
@@ -29,11 +29,11 @@ module.exports = function (config) {
}
],
frameworks: ['jasmine-ajax', 'jasmine', '@angular-devkit/build-angular'],
frameworks: ['jasmine', '@angular-devkit/build-angular'],
proxies: {
'/fake-url-file.png': '/base/lib/core/src/lib/assets/images/logo.png',
'/logo.png': '/base/lib/core/src/lib/assets/images/logo.png',
'/fake-url-file.png': '/base/lib/core/src/lib/assets/images/logo.svg',
'/logo.svg': '/base/lib/core/src/lib/assets/images/logo.svg',
'/alfresco-logo.svg': '/base/lib/core/src/lib/assets/images/alfresco-logo.svg',
'/assets/images/': '/base/lib/core/src/lib/assets/images/',
'/assets/images/ecm-background.png': '/base/lib/core/src/lib/assets/images/ecm-background.png',
@@ -43,8 +43,8 @@ module.exports = function (config) {
'/assets/adf-core/i18n/en.json': '/base/lib/core/src/lib/i18n/en.json',
'/assets/adf-core/i18n/en-GB.json': '/base/lib/core/src/lib/i18n/en.json',
'/assets/adf-core/i18n/en-US.json': '/base/lib/core/src/lib/i18n/en.json',
'/fake-content-img': '/base/lib/core/src/lib/assets/images/logo.png',
'/fake-content-img.bin': '/base/lib/core/src/lib/assets/images/logo.png',
'/fake-content-img': '/base/lib/core/src/lib/assets/images/logo.svg',
'/fake-content-img.bin': '/base/lib/core/src/lib/assets/images/logo.svg',
'/fake-test-file.pdf': '/base/lib/core/src/lib/viewer/assets/fake-test-file.pdf',
'/fake-content-pdf': '/base/lib/core/src/lib/viewer/assets/fake-test-file.pdf',
'/fake-content-pdf.bin': '/base/lib/core/src/lib/viewer/assets/fake-test-file.pdf',
@@ -56,13 +56,11 @@ module.exports = function (config) {
},
plugins: [
require('karma-jasmine-ajax'),
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage'),
require('@angular-devkit/build-angular/plugins/karma'),
require('karma-mocha-reporter')
require('@angular-devkit/build-angular/plugins/karma')
],
client: {
clearContext: false,
@@ -73,9 +71,6 @@ module.exports = function (config) {
jasmineHtmlReporter: {
suppressAll: true // removes the duplicated traces
},
mochaReporter: {
ignoreSkipped: process.env.KARMA_IGNORE_SKIPPED === 'true'
},
coverageReporter: {
dir: join(__dirname, '../../coverage/core'),
@@ -98,7 +93,7 @@ module.exports = function (config) {
}
},
reporters: ['mocha', 'kjhtml'],
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: constants.LOG_INFO,
+4 -4
View File
@@ -1,7 +1,7 @@
{
"name": "@alfresco/adf-core",
"description": "Alfresco ADF core",
"version": "8.3.1",
"version": "8.4.1",
"author": "Hyland Software, Inc. and its affiliates",
"repository": {
"type": "git",
@@ -37,9 +37,9 @@
"@angular/platform-browser": ">=16.0.0",
"@angular/router": ">=16.0.0",
"@mat-datetimepicker/core": ">=12.0.1",
"@ngx-translate/core": ">=16.0.0",
"@alfresco/js-api": ">=9.3.1",
"@alfresco/adf-extensions": ">=8.3.1",
"@ngx-translate/core": ">=17.0.0",
"@alfresco/js-api": ">=9.4.1",
"@alfresco/adf-extensions": ">=8.4.1",
"minimatch": ">=10.0.0",
"pdfjs-dist": ">=3.3.122"
},
@@ -1,16 +1,27 @@
<div>
<article *ngIf="licenseEntries">
<header>{{ 'ABOUT.LICENSE.TITLE' | translate }}</header>
@if (licenseEntries) {
<article>
<h2 data-automation-id="adf-about-repository-info-header-license"
class="adf-about-repository-info-header">
{{ 'ABOUT.LICENSE.TITLE' | translate }}
</h2>
<adf-about-license-list [data]="licenseEntries" />
</article>
<article *ngIf="statusEntries">
<header>{{ 'ABOUT.STATUS.TITLE' | translate }}</header>
}
@if (statusEntries) {
<article>
<h2 data-automation-id="adf-about-repository-info-header-status"
class="adf-about-repository-info-header">
{{ 'ABOUT.STATUS.TITLE' | translate }}
</h2>
<adf-about-status-list [data]="statusEntries" />
</article>
<article *ngIf="data?.modules">
<header>{{ 'ABOUT.MODULES.TITLE' | translate }}</header>
}
@if (data?.modules) {
<article>
<h2 data-automation-id="adf-about-repository-info-header-modules"
class="adf-about-repository-info-header">
{{ 'ABOUT.MODULES.TITLE' | translate }}
</h2>
<adf-about-module-list [data]="data.modules" />
</article>
</div>
}
@@ -1,3 +1,11 @@
article {
margin-top: 16px;
adf-about-repository-info {
article {
margin-top: 16px;
}
.adf-about-repository-info-header {
font-size: 14px;
margin: 0;
font-weight: 500;
}
}
@@ -0,0 +1,85 @@
/*!
* @license
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AboutRepositoryInfoComponent, RepositoryInfo, UnitTestingUtils } from '@alfresco/adf-core';
describe('AboutRepositoryInfoComponent', () => {
let component: AboutRepositoryInfoComponent;
let fixture: ComponentFixture<AboutRepositoryInfoComponent>;
let unitTestingUtils: UnitTestingUtils;
const headerTag = 'H2';
beforeEach(() => {
TestBed.configureTestingModule({
imports: [AboutRepositoryInfoComponent]
});
fixture = TestBed.createComponent(AboutRepositoryInfoComponent);
component = fixture.componentInstance;
unitTestingUtils = new UnitTestingUtils(fixture.debugElement);
});
describe('License', () => {
it('should render license header', () => {
component.data = {
status: {},
license: {
holder: 'Some holder'
}
} as RepositoryInfo;
fixture.detectChanges();
const licenseHeader = unitTestingUtils.getByDataAutomationId('adf-about-repository-info-header-license').nativeElement;
expect(licenseHeader.innerText).toBe('ABOUT.LICENSE.TITLE');
expect(licenseHeader.tagName).toBe(headerTag);
});
});
describe('Status', () => {
it('should render status header', () => {
component.data = {
status: {
isReadOnly: true
}
} as RepositoryInfo;
fixture.detectChanges();
const statusHeader = unitTestingUtils.getByDataAutomationId('adf-about-repository-info-header-status').nativeElement;
expect(statusHeader.innerText).toBe('ABOUT.STATUS.TITLE');
expect(statusHeader.tagName).toBe(headerTag);
});
});
describe('Modules', () => {
it('should render modules header', () => {
component.data = {
status: {},
modules: [
{
title: 'Module 1'
}
]
} as RepositoryInfo;
fixture.detectChanges();
const modulesHeader = unitTestingUtils.getByDataAutomationId('adf-about-repository-info-header-modules').nativeElement;
expect(modulesHeader.innerText).toBe('ABOUT.MODULES.TITLE');
expect(modulesHeader.tagName).toBe(headerTag);
});
});
});
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 21 KiB

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